Skip to content

Commit

Permalink
[EN-6259] feat: backoffice admin offres (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulEntourage authored Nov 29, 2023
1 parent 80cf01c commit 4265958
Show file tree
Hide file tree
Showing 6 changed files with 552 additions and 388 deletions.
30 changes: 25 additions & 5 deletions src/opportunities/opportunities.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ import { OpportunitiesService } from './opportunities.service';
import {
EventTypes,
OfferAdminTab,
OfferCandidateTab,
OfferCandidateType,
OfferCandidateTypes,
OfferFilterKey,
OfferStatuses,
OpportunityRestricted,
Expand Down Expand Up @@ -357,6 +358,8 @@ export class OpportunitiesController {
query: {
type: OfferAdminTab;
search: string;
offset: number;
limit: number;
} & FilterParams<OfferFilterKey>
) {
return this.opportunitiesService.findAll(query);
Expand Down Expand Up @@ -399,7 +402,7 @@ export class OpportunitiesController {
@LinkedUser('params.candidateId')
@UseGuards(LinkedUserGuard)
@Get('/candidate/tabCount/:candidateId')
async countOffersByStatus(
async candidateCountOffersByStatus(
@Param('candidateId', new ParseUUIDPipe()) candidateId: string
) {
const opportunityUsers =
Expand All @@ -409,9 +412,26 @@ export class OpportunitiesController {
throw new NotFoundException();
}

return this.opportunityUsersService.countOffersByStatus(candidateId);
return this.opportunityUsersService.candidateCountOffersByStatus(
candidateId
);
}

// to be implemented
// @UserPermissions(Permissions.ADMIN)
// @UseGuards(UserPermissionsGuard)
// @Get('/admin/tabCount')
// async adminCountOffersByType(
// @Query()
// query: {
// type: OfferAdminTab;
// search: string;
// } & FilterParams<OfferFilterKey>
// ) {
// const { type, search, businessLines, department, contracts } = query
// return this.opportunitiesService.adminCountOfferByType(type, search,businessLines, department, contracts);
// }

@UserPermissions(Permissions.CANDIDATE, Permissions.COACH)
@UseGuards(UserPermissionsGuard)
@LinkedUser('params.candidateId')
Expand All @@ -421,14 +441,14 @@ export class OpportunitiesController {
@Param('candidateId', new ParseUUIDPipe()) candidateId: string,
@Query()
query: {
type: OfferCandidateTab;
type: OfferCandidateType;
search: string;
offset: number;
limit: number;
} & FilterParams<OfferFilterKey>
) {
const { type, status } = query;
if (type !== 'public' && !status) {
if (type !== OfferCandidateTypes.PUBLIC && !status) {
throw new BadRequestException('status expected');
}

Expand Down
97 changes: 77 additions & 20 deletions src/opportunities/opportunities.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,23 @@ import {
} from './models';
import { OpportunityCandidateAttributes } from './models/opportunity.attributes';
import {
OpportunityCompleteAdminInclude,
OpportunityCompleteAdminWithoutBusinessLinesInclude,
OpportunityCompleteInclude,
OpportunityCompleteWithoutOpportunityUsersInclude,
} from './models/opportunity.include';
import {
OfferAdminTab,
OfferAdminTabs,
OfferCandidateTab,
OfferFilterKey,
OfferStatuses,
OpportunityRestricted,
} from './opportunities.types';
import {
destructureOptionsAndParams,
filterAdminOffersByType,
filterOffersByStatus,
getOfferOptions,
getOfferOptionsAdminByType,
renderOffersQuery,
sortOpportunities,
} from './opportunities.utils';
Expand Down Expand Up @@ -160,6 +160,8 @@ export class OpportunitiesService {
query: {
type: OfferAdminTab;
search: string;
offset: number;
limit: number;
} & FilterParams<OfferFilterKey>
) {
const {
Expand All @@ -170,35 +172,47 @@ export class OpportunitiesService {
filterOptions,
} = destructureOptionsAndParams(query);

const options = {
include: [
...OpportunityCompleteAdminWithoutBusinessLinesInclude,
businessLinesOptions,
],
};

if (typeParams && typeParams === OfferAdminTabs.EXTERNAL) {
delete filterOptions.isPublic;
}

const limit = query.limit || LIMIT;

const opportunities = await this.opportunityModel.findAll({
...options,
attributes: ['id', 'createdAt'],
include: [
{
model: OpportunityUser,
as: 'opportunityUsers',
required: !!statusParams && statusParams.length > 0,
...(statusParams && statusParams?.length > 0
? {
where: {
status: statusParams.map(({ value }) => value),
},
}
: {}),
attributes: ['status'],
},
businessLinesOptions,
],
where: {
...searchOptions,
...filterOptions,
...getOfferOptionsAdminByType(typeParams),
},
offset: query.offset ? query.offset * limit : 0,
limit,
order: [['createdAt', 'DESC']],
});

const cleanedOpportunites = opportunities.map((opportunity) => {
return opportunity.toJSON();
return this.opportunityModel.findAll({
include: OpportunityCompleteAdminInclude,
where: {
id: opportunities.map(({ id }) => id),
},
order: [['createdAt', 'DESC']],
});

const filteredTypeOpportunites = filterAdminOffersByType(
cleanedOpportunites,
typeParams as OfferAdminTab
);

return filterOffersByStatus(filteredTypeOpportunites, statusParams);
}

async findAllUserOpportunitiesAsAdmin(
Expand Down Expand Up @@ -243,7 +257,6 @@ export class OpportunitiesService {
async findAllAsCandidate(
candidateId: string,
query: {
type: OfferCandidateTab;
search: string;
offset: number;
limit: number;
Expand Down Expand Up @@ -1051,4 +1064,48 @@ export class OpportunitiesService {
description
);
}

// to be implemented
// async adminCountOfferByType(
// type: OfferAdminTab,
// search: string,
// businessLines: string[],
// department: string[],
// contracts: string[],
// ) {

// const {
// typeParams,
// searchOptions,
// filterOptions,
// } = destructureOptionsAndParams({type, search, businessLines, department});

// // const typeCounts = await this.opportunityModel.sequelize.query()

// // console.log("before destructure")
// // console.log({typeParams, searchOptions,
// // businessLinesOptions,
// // filterOptions})
// // console.log("after destructure")

// console.log("type params", typeParams);

// const pendingOpportunitiesCount = await this.opportunityModel.count({
// where: {
// ...searchOptions,
// ...filterOptions,
// department,
// isValidated: false,
// isArchived: false,
// },
// });

// // const cleanedOpportunites = pendingOpportunitiesCount.map((opportunity) => {
// // return opportunity.toJSON();
// // });

// console.log({type, search, businessLines, department, contracts});

// return {pending: pendingOpportunitiesCount}
// }
}
35 changes: 8 additions & 27 deletions src/opportunities/opportunities.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,7 @@ import {
Department,
DepartmentFilters,
} from 'src/common/locations/locations.types';
import {
AdminZones,
FilterConstant,
Filters,
TabFilters,
} from 'src/utils/types';
import { AdminZones, FilterConstant, Filters } from 'src/utils/types';
import { Opportunity, OpportunityUser } from './models';

export type ExternalOfferOrigin = 'network' | 'internet' | 'counselor';
Expand Down Expand Up @@ -85,21 +80,6 @@ export interface OfferOptions {

export type OfferFilterKey = keyof OfferOptions;

export const OfferCandidateTabs = {
PRIVATE: 'private',
PUBLIC: 'public',
ARCHIVED: 'archived',
} as const;

type OfferCandidateTabKey = keyof typeof OfferCandidateTabs;
export type OfferCandidateTab = typeof OfferCandidateTabs[OfferCandidateTabKey];

export const OfferCandidateTabFilters: TabFilters<OfferCandidateTab> = [
{ tag: 'private', title: 'Offres personnelles', active: true },
{ tag: 'public', title: 'Offres générales' },
{ tag: 'archived', title: 'Offres archivées' },
];

export const OfferAdminTabs = {
PENDING: 'pending',
VALIDATED: 'validated',
Expand All @@ -110,13 +90,14 @@ export const OfferAdminTabs = {
type OfferAdminTabKey = keyof typeof OfferAdminTabs;
export type OfferAdminTab = typeof OfferAdminTabs[OfferAdminTabKey];

export const OfferAdminTabFilters: TabFilters<OfferAdminTab> = [
{ tag: 'pending', title: 'Offres à valider' },
{ tag: 'validated', title: 'Offres publiées', active: true },
{ tag: 'external', title: 'Offres externes' },
{ tag: 'archived', title: 'Offres archivées' },
];
export const OfferCandidateTypes = {
PUBLIC: 'public',
PRIVATE: 'private',
} as const;

type OfferCandidateTypeKey = keyof typeof OfferCandidateTypes;
export type OfferCandidateType =
typeof OfferCandidateTypes[OfferCandidateTypeKey];
export const OfferFilters: Filters<OfferFilterKey> = [
{
key: 'isPublic',
Expand Down
Loading

0 comments on commit 4265958

Please sign in to comment.