Skip to content

Commit

Permalink
feat: add dashboard endpoints (#131)
Browse files Browse the repository at this point in the history
Co-authored-by: M4rcxs <[email protected]>
Co-authored-by: Marcos Silva <[email protected]>
  • Loading branch information
3 people authored May 28, 2024
1 parent 25246e8 commit 38da306
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 1 deletion.
35 changes: 35 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-fastify": "^10.3.8",
"@nestjs/schedule": "^4.0.2",
"@nestjs/swagger": "^7.3.1",
"@prisma/client": "^5.13.0",
"bcrypt": "^5.1.1",
Expand Down
2 changes: 1 addition & 1 deletion prisma/dev_dump.sql
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ INSERT INTO public.users VALUES ('e0306bc0-8c29-429a-bbd2-384f48d4f993', 'Dinho'
INSERT INTO public.users VALUES ('e82f476a-1574-4dd2-a4c4-1c1f0117db12', 'Rhuam', '51992047974', '$2b$10$V4hFTbT7MrskROc4TI2lNe6gAd0g7U1niziAPycFueLhPJRFIfoGm', '51992047974', '2024-05-05T22:06:11.390Z', '2024-05-16T18:52:36.650Z', 'Admin', 'Estevam');


--
---
-- Data for Name: shelters; Type: TABLE DATA; Schema: public; Owner: doadmin
--

Expand Down
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SupplyCategoriesModule } from './supply-categories/supply-categories.mo
import { ShelterManagersModule } from './shelter-managers/shelter-managers.module';
import { ShelterSupplyModule } from './shelter-supply/shelter-supply.module';
import { PartnersModule } from './partners/partners.module';
import { DashboardModule } from './modules/dashboard/dashboard.module';
import { SupportersModule } from './supporters/supporters.module';
import { SuppliesHistoryModule } from './supplies-history/supplies-history.module';

Expand All @@ -26,6 +27,7 @@ import { SuppliesHistoryModule } from './supplies-history/supplies-history.modul
ShelterManagersModule,
ShelterSupplyModule,
PartnersModule,
DashboardModule,
SupportersModule,
SuppliesHistoryModule,
],
Expand Down
20 changes: 20 additions & 0 deletions src/modules/dashboard/dashboard.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DashboardController } from './dashboard.controller';
import { DashboardService } from './dashboard.service';

describe('DashboardController', () => {
let controller: DashboardController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [DashboardController],
providers: [DashboardService],
}).compile();

controller = module.get<DashboardController>(DashboardController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
22 changes: 22 additions & 0 deletions src/modules/dashboard/dashboard.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Controller, Get, HttpException, Logger, Query } from '@nestjs/common';
import { DashboardService } from './dashboard.service';
import { ServerResponse } from '@/utils/utils';
import { ApiTags } from '@nestjs/swagger';

@ApiTags('Dashboard')
@Controller('dashboard')
export class DashboardController {
private logger = new Logger();
constructor(private readonly dashboardService: DashboardService) {}

@Get('')
async index(@Query() query) {
try {
const data = await this.dashboardService.index(query);
return new ServerResponse(200, 'Successfully get dashboard', data);
} catch (err: any) {
this.logger.error(`Failed to get shelters: ${err}`);
throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400);
}
}
}
11 changes: 11 additions & 0 deletions src/modules/dashboard/dashboard.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { DashboardService } from './dashboard.service';
import { DashboardController } from './dashboard.controller';
import { PrismaModule } from 'src/prisma/prisma.module';

@Module({
imports: [PrismaModule],
controllers: [DashboardController],
providers: [DashboardService],
})
export class DashboardModule {}
18 changes: 18 additions & 0 deletions src/modules/dashboard/dashboard.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DashboardService } from './dashboard.service';

describe('DashboardService', () => {
let service: DashboardService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [DashboardService],
}).compile();

service = module.get<DashboardService>(DashboardService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
160 changes: 160 additions & 0 deletions src/modules/dashboard/dashboard.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import * as qs from 'qs';
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { ShelterSearchPropsSchema } from 'src/shelter/types/search.types';
import { SearchSchema } from 'src/types';
import { ShelterSearch } from 'src/shelter/ShelterSearch';
import { DefaultArgs } from '@prisma/client/runtime/library';
import { Prisma } from '@prisma/client';

@Injectable()
export class DashboardService {
constructor(private readonly prismaService: PrismaService) {}

async index(query: any) {
const {
order,
orderBy,
page,
perPage,
search: searchQuery,
} = SearchSchema.parse(query);
const queryData = ShelterSearchPropsSchema.parse(qs.parse(searchQuery));
const { getQuery } = new ShelterSearch(this.prismaService, queryData);
const where = await getQuery();

const take = perPage;
const skip = perPage * (page - 1);

const whereData: Prisma.ShelterFindManyArgs<DefaultArgs> = {
take,
skip,
orderBy: { [orderBy]: order },
where,
};

const allShelters = await this.prismaService.shelter.findMany({
...whereData,
select: {
id: true,
name: true,
shelteredPeople: true,
actived: true,
capacity: true,
shelterSupplies: {
select: {
priority: true,
supply: {
select: {
supplyCategory: {
select: {
name: true,
},
},
},
},
},
},
},
});

const categoriesWithPriorities = await this.prismaService.supplyCategory.findMany({
select: {
id: true,
name: true,
supplies: {
select: {
shelterSupplies: {
select: {
priority: true,
shelterId: true
}
}
}
}
}
});

const result = categoriesWithPriorities.map(category => {
const priorityCounts = {
priority100: 0,
priority10: 0,
priority1: 0,
};

const countedShelters = new Set();

category.supplies.forEach(supply => {
supply.shelterSupplies.forEach(shelterSupply => {
if (!countedShelters.has(shelterSupply.shelterId)) {
switch (shelterSupply.priority) {
case 100:
priorityCounts.priority100++;
break;
case 10:
priorityCounts.priority10++;
break;
case 1:
priorityCounts.priority1++;
break;
default:
break;
}
countedShelters.add(shelterSupply.shelterId);
}
});
});

return {
categoryId: category.id,
categoryName: category.name,
...priorityCounts,
};
});

const allPeopleSheltered = allShelters.reduce((accumulator, current) => {
if (
current.actived &&
current.capacity !== null &&
current.capacity > 0
) {
return accumulator + (current.shelteredPeople ?? 0);
} else {
return accumulator;
}
}, 0);

const numSheltersAvailable = allShelters.filter(shelter => {
if (shelter.actived && shelter.capacity !== null && shelter.capacity > 0) {
return (shelter.shelteredPeople ?? 0) < shelter.capacity;
}
return false;
}).length;

const numSheltersFull = allShelters.reduce((count, shelter) => {
if (shelter.actived && shelter.capacity !== null && shelter.capacity > 0) {
if ((shelter.shelteredPeople ?? 0) >= shelter.capacity) {
return count + 1;
}
}
return count;
}, 0);

const shelterWithoutInformation = allShelters.reduce((count, shelter) => {
if (shelter.shelteredPeople === null || shelter.shelteredPeople === undefined) {
return count + 1;
}
return count;
}, 0);


return {
allShelters: allShelters.length,
allPeopleSheltered: allPeopleSheltered,
shelterAvaliable: numSheltersAvailable,
shelterFull: numSheltersFull,
shelterWithoutInformation: shelterWithoutInformation,
categoriesWithPriorities: result,
};
}
}
2 changes: 2 additions & 0 deletions src/partners/partners.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import {
} from '@nestjs/common';
import { PartnersService } from './partners.service';
import { ServerResponse } from '../utils';
import { ApiTags } from '@nestjs/swagger';
import { AdminGuard } from '@/guards/admin.guard';

@ApiTags('Parceiros')
@Controller('partners')
export class PartnersController {
private logger = new Logger(PartnersController.name);
Expand Down

0 comments on commit 38da306

Please sign in to comment.