diff --git a/apps/portal/prisma/schema.prisma b/apps/portal/prisma/schema.prisma
index aa29f612..4085e88b 100644
--- a/apps/portal/prisma/schema.prisma
+++ b/apps/portal/prisma/schema.prisma
@@ -191,13 +191,13 @@ model OffersProfile {
user User? @relation(fields: [userId], references: [id])
userId String?
- OffersAnalysis OffersAnalysis?
+ analysis OffersAnalysis?
}
model OffersBackground {
id String @id @default(cuid())
- totalYoe Int?
+ totalYoe Int
specificYoes OffersSpecificYoe[]
experiences OffersExperience[] // For extensibility in the future
@@ -308,8 +308,8 @@ model OffersOffer {
monthYearReceived DateTime
location String
- negotiationStrategy String?
- comments String?
+ negotiationStrategy String
+ comments String
jobType JobType
@@ -320,7 +320,6 @@ model OffersOffer {
offersFullTimeId String? @unique
OffersAnalysis OffersAnalysis? @relation("HighestOverallOffer")
-
OffersAnalysisTopOverallOffers OffersAnalysis[] @relation("TopOverallOffers")
OffersAnalysisTopCompanyOffers OffersAnalysis[] @relation("TopCompanyOffers")
}
diff --git a/apps/portal/src/components/offers/table/OffersRow.tsx b/apps/portal/src/components/offers/table/OffersRow.tsx
index 8ab39bdd..d5039014 100644
--- a/apps/portal/src/components/offers/table/OffersRow.tsx
+++ b/apps/portal/src/components/offers/table/OffersRow.tsx
@@ -1,11 +1,13 @@
import Link from 'next/link';
-import type { OfferTableRowData } from '~/components/offers/table/types';
+import type { DashboardOffer } from '../../../types/offers';
+import { convertCurrencyToString } from '../../../utils/offers/currency';
+import { formatDate } from '../../../utils/offers/time';
-export type OfferTableRowProps = Readonly<{ row: OfferTableRowData }>;
+export type OfferTableRowProps = Readonly<{ row: DashboardOffer }>;
export default function OfferTableRow({
- row: { company, date, id, profileId, salary, title, yoe },
+ row: { company, id, income, monthYearReceived, profileId, title, totalYoe },
}: OfferTableRowProps) {
return (
- {company}
+ {company.name}
{title} |
- {yoe} |
- {salary} |
- {date} |
+ {totalYoe} |
+ {convertCurrencyToString(income)} |
+ {formatDate(monthYearReceived)} |
({
- currentPage: 1,
- numOfItems: 1,
+ const [pagination, setPagination] = useState({
+ currentPage: 0,
+ numOfItems: 0,
numOfPages: 0,
totalItems: 0,
});
- const [offers, setOffers] = useState>([]);
+ const [offers, setOffers] = useState>([]);
useEffect(() => {
setPagination({
- currentPage: 1,
- numOfItems: 1,
+ currentPage: 0,
+ numOfItems: 0,
numOfPages: 0,
totalItems: 0,
});
@@ -48,7 +45,7 @@ export default function OffersTable({
companyId: companyFilter,
limit: NUMBER_OF_OFFERS_IN_PAGE,
location: 'Singapore, Singapore', // TODO: Geolocation
- offset: pagination.currentPage - 1,
+ offset: 0,
sortBy: '-monthYearReceived',
title: jobTitleFilter,
yoeCategory: selectedTab,
@@ -56,28 +53,19 @@ export default function OffersTable({
],
{
onSuccess: (response) => {
- const filteredData = response.data.map((res) => {
- return {
- company: res.company.name,
- date: formatDate(res.monthYearReceived),
- id: res.OffersFullTime
- ? res.OffersFullTime!.id
- : res.OffersIntern!.id,
- profileId: res.profileId,
- salary: res.OffersFullTime
- ? res.OffersFullTime?.totalCompensation.value
- : res.OffersIntern?.monthlySalary.value,
- title: res.OffersFullTime ? res.OffersFullTime?.level : '',
- yoe: 100,
- };
- });
- setOffers(filteredData);
- setPagination({
- currentPage: (response.paging.currPage as number) + 1,
- numOfItems: response.paging.numOfItemsInPage,
- numOfPages: response.paging.numOfPages,
- totalItems: response.paging.totalNumberOfOffers,
- });
+ // Const filteredData = response.data.map((res) => {
+ // return {
+ // company: res.company.name,
+ // date: res.monthYearReceived,
+ // id: res.id,
+ // profileId: res.profileId,
+ // income: res.income,
+ // title: res.title,
+ // yoe: res.totalYoe,
+ // };
+ // });
+ setOffers(response.data);
+ setPagination(response.paging);
},
},
);
@@ -90,15 +78,15 @@ export default function OffersTable({
label="Table Navigation"
tabs={[
{
- label: 'Fresh Grad (0-3 YOE)',
+ label: 'Fresh Grad (0-2 YOE)',
value: YOE_CATEGORY.ENTRY,
},
{
- label: 'Mid (4-7 YOE)',
+ label: 'Mid (3-5 YOE)',
value: YOE_CATEGORY.MID,
},
{
- label: 'Senior (8+ YOE)',
+ label: 'Senior (6+ YOE)',
value: YOE_CATEGORY.SENIOR,
},
{
@@ -187,14 +175,11 @@ export default function OffersTable({
)}
diff --git a/apps/portal/src/components/offers/table/OffersTablePagination.tsx b/apps/portal/src/components/offers/table/OffersTablePagination.tsx
index e7346c44..0800a529 100644
--- a/apps/portal/src/components/offers/table/OffersTablePagination.tsx
+++ b/apps/portal/src/components/offers/table/OffersTablePagination.tsx
@@ -1,11 +1,11 @@
import { Pagination } from '@tih/ui';
-import type { PaginationType } from '~/components/offers/table/types';
+import type { Paging } from '~/types/offers';
type OffersTablePaginationProps = Readonly<{
endNumber: number;
handlePageChange: (page: number) => void;
- pagination: PaginationType;
+ pagination: Paging;
startNumber: number;
}>;
@@ -30,13 +30,13 @@ export default function OffersTablePagination({
{
- handlePageChange(currPage);
+ handlePageChange(currPage - 1);
}}
/>
diff --git a/apps/portal/src/components/offers/table/types.ts b/apps/portal/src/components/offers/table/types.ts
index 9522a9bb..c7d92680 100644
--- a/apps/portal/src/components/offers/table/types.ts
+++ b/apps/portal/src/components/offers/table/types.ts
@@ -1,13 +1,3 @@
-export type OfferTableRowData = {
- company: string;
- date: string;
- id: string;
- profileId: string;
- salary: number | undefined;
- title: string;
- yoe: number;
-};
-
// eslint-disable-next-line no-shadow
export enum YOE_CATEGORY {
INTERN = 0,
diff --git a/apps/portal/src/mappers/offers-mappers.ts b/apps/portal/src/mappers/offers-mappers.ts
new file mode 100644
index 00000000..1a6e415c
--- /dev/null
+++ b/apps/portal/src/mappers/offers-mappers.ts
@@ -0,0 +1,574 @@
+import type {
+ Company,
+ OffersAnalysis,
+ OffersBackground,
+ OffersCurrency,
+ OffersEducation,
+ OffersExperience,
+ OffersFullTime,
+ OffersIntern,
+ OffersOffer,
+ OffersProfile,
+ OffersReply,
+ OffersSpecificYoe,
+ User,
+} from '@prisma/client';
+import { JobType } from '@prisma/client';
+
+import type {
+ AddToProfileResponse,
+ Analysis,
+ AnalysisHighestOffer,
+ AnalysisOffer,
+ Background,
+ CreateOfferProfileResponse,
+ DashboardOffer,
+ Education,
+ Experience,
+ GetOffersResponse,
+ OffersCompany,
+ Paging,
+ Profile,
+ ProfileAnalysis,
+ ProfileOffer,
+ SpecificYoe,
+ Valuation,
+} from '~/types/offers';
+
+const analysisOfferDtoMapper = (
+ offer: OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | null;
+ OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
+ company: Company;
+ profile: OffersProfile & { background: OffersBackground | null };
+ },
+) => {
+ const { background, profileName } = offer.profile;
+ const analysisOfferDto: AnalysisOffer = {
+ company: offersCompanyDtoMapper(offer.company),
+ id: offer.id,
+ income: -1,
+ jobType: offer.jobType,
+ level: offer.OffersFullTime?.level ?? '',
+ location: offer.location,
+ monthYearReceived: offer.monthYearReceived,
+ negotiationStrategy: offer.negotiationStrategy,
+ previousCompanies: [],
+ profileName,
+ specialization:
+ offer.jobType === JobType.FULLTIME
+ ? offer.OffersFullTime?.specialization ?? ''
+ : offer.OffersIntern?.specialization ?? '',
+ title:
+ offer.jobType === JobType.FULLTIME
+ ? offer.OffersFullTime?.title ?? ''
+ : offer.OffersIntern?.title ?? '',
+ totalYoe: background?.totalYoe ?? -1,
+ };
+
+ if (offer.OffersFullTime?.totalCompensation) {
+ analysisOfferDto.income = offer.OffersFullTime.totalCompensation.value;
+ } else if (offer.OffersIntern?.monthlySalary) {
+ analysisOfferDto.income = offer.OffersIntern.monthlySalary.value;
+ }
+
+ return analysisOfferDto;
+};
+
+const analysisDtoMapper = (
+ noOfOffers: number,
+ percentile: number,
+ topPercentileOffers: Array<
+ OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | null;
+ OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
+ company: Company;
+ profile: OffersProfile & { background: OffersBackground | null };
+ }
+ >,
+) => {
+ const analysisDto: Analysis = {
+ noOfOffers,
+ percentile,
+ topPercentileOffers: topPercentileOffers.map((offer) =>
+ analysisOfferDtoMapper(offer),
+ ),
+ };
+ return analysisDto;
+};
+
+const analysisHighestOfferDtoMapper = (
+ offer: OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | null;
+ OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
+ company: Company;
+ profile: OffersProfile & { background: OffersBackground | null };
+ },
+) => {
+ const analysisHighestOfferDto: AnalysisHighestOffer = {
+ company: offersCompanyDtoMapper(offer.company),
+ id: offer.id,
+ level: offer.OffersFullTime?.level ?? '',
+ location: offer.location,
+ specialization:
+ offer.jobType === JobType.FULLTIME
+ ? offer.OffersFullTime?.specialization ?? ''
+ : offer.OffersIntern?.specialization ?? '',
+ totalYoe: offer.profile.background?.totalYoe ?? -1,
+ };
+ return analysisHighestOfferDto;
+};
+
+export const profileAnalysisDtoMapper = (
+ analysis:
+ | (OffersAnalysis & {
+ overallHighestOffer: OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | null;
+ OffersIntern:
+ | (OffersIntern & { monthlySalary: OffersCurrency })
+ | null;
+ company: Company;
+ profile: OffersProfile & { background: OffersBackground | null };
+ };
+ topCompanyOffers: Array<
+ OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | null;
+ OffersIntern:
+ | (OffersIntern & { monthlySalary: OffersCurrency })
+ | null;
+ company: Company;
+ profile: OffersProfile & {
+ background:
+ | (OffersBackground & {
+ experiences: Array<
+ OffersExperience & { company: Company | null }
+ >;
+ })
+ | null;
+ };
+ }
+ >;
+ topOverallOffers: Array<
+ OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | null;
+ OffersIntern:
+ | (OffersIntern & { monthlySalary: OffersCurrency })
+ | null;
+ company: Company;
+ profile: OffersProfile & {
+ background:
+ | (OffersBackground & {
+ experiences: Array<
+ OffersExperience & { company: Company | null }
+ >;
+ })
+ | null;
+ };
+ }
+ >;
+ })
+ | null,
+) => {
+ if (!analysis) {
+ return null;
+ }
+
+ const profileAnalysisDto: ProfileAnalysis = {
+ companyAnalysis: [
+ analysisDtoMapper(
+ analysis.noOfSimilarCompanyOffers,
+ analysis.companyPercentile,
+ analysis.topCompanyOffers,
+ ),
+ ],
+ id: analysis.id,
+ overallAnalysis: analysisDtoMapper(
+ analysis.noOfSimilarOffers,
+ analysis.overallPercentile,
+ analysis.topOverallOffers,
+ ),
+ overallHighestOffer: analysisHighestOfferDtoMapper(
+ analysis.overallHighestOffer,
+ ),
+ profileId: analysis.profileId,
+ };
+ return profileAnalysisDto;
+};
+
+export const valuationDtoMapper = (currency: {
+ currency: string;
+ id?: string;
+ value: number;
+}) => {
+ const valuationDto: Valuation = {
+ currency: currency.currency,
+ value: currency.value,
+ };
+ return valuationDto;
+};
+
+export const offersCompanyDtoMapper = (company: Company) => {
+ const companyDto: OffersCompany = {
+ createdAt: company.createdAt,
+ description: company?.description ?? '',
+ id: company.id,
+ logoUrl: company.logoUrl ?? '',
+ name: company.name,
+ slug: company.slug,
+ updatedAt: company.updatedAt,
+ };
+ return companyDto;
+};
+
+export const educationDtoMapper = (education: {
+ backgroundId?: string;
+ endDate: Date | null;
+ field: string | null;
+ id: string;
+ school: string | null;
+ startDate: Date | null;
+ type: string | null;
+}) => {
+ const educationDto: Education = {
+ endDate: education.endDate,
+ field: education.field,
+ id: education.id,
+ school: education.school,
+ startDate: education.startDate,
+ type: education.type,
+ };
+ return educationDto;
+};
+
+export const experienceDtoMapper = (
+ experience: OffersExperience & {
+ company: Company | null;
+ monthlySalary: OffersCurrency | null;
+ totalCompensation: OffersCurrency | null;
+ },
+) => {
+ const experienceDto: Experience = {
+ company: experience.company
+ ? offersCompanyDtoMapper(experience.company)
+ : null,
+ durationInMonths: experience.durationInMonths,
+ id: experience.id,
+ jobType: experience.jobType,
+ level: experience.level,
+ monthlySalary: experience.monthlySalary
+ ? valuationDtoMapper(experience.monthlySalary)
+ : experience.monthlySalary,
+ specialization: experience.specialization,
+ title: experience.title,
+ totalCompensation: experience.totalCompensation
+ ? valuationDtoMapper(experience.totalCompensation)
+ : experience.totalCompensation,
+ };
+ return experienceDto;
+};
+
+export const specificYoeDtoMapper = (specificYoe: {
+ backgroundId?: string;
+ domain: string;
+ id: string;
+ yoe: number;
+}) => {
+ const specificYoeDto: SpecificYoe = {
+ domain: specificYoe.domain,
+ id: specificYoe.id,
+ yoe: specificYoe.yoe,
+ };
+ return specificYoeDto;
+};
+
+export const backgroundDtoMapper = (
+ background:
+ | (OffersBackground & {
+ educations: Array;
+ experiences: Array<
+ OffersExperience & {
+ company: Company | null;
+ monthlySalary: OffersCurrency | null;
+ totalCompensation: OffersCurrency | null;
+ }
+ >;
+ specificYoes: Array;
+ })
+ | null,
+) => {
+ if (!background) {
+ return null;
+ }
+
+ const educations = background.educations.map((education) =>
+ educationDtoMapper(education),
+ );
+
+ const experiences = background.experiences.map((experience) =>
+ experienceDtoMapper(experience),
+ );
+
+ const specificYoes = background.specificYoes.map((specificYoe) =>
+ specificYoeDtoMapper(specificYoe),
+ );
+
+ const backgroundDto: Background = {
+ educations,
+ experiences,
+ id: background.id,
+ specificYoes,
+ totalYoe: background.totalYoe,
+ };
+
+ return backgroundDto;
+};
+
+export const profileOfferDtoMapper = (
+ offer: OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & {
+ baseSalary: OffersCurrency;
+ bonus: OffersCurrency;
+ stocks: OffersCurrency;
+ totalCompensation: OffersCurrency;
+ })
+ | null;
+ OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
+ company: Company;
+ },
+) => {
+ const profileOfferDto: ProfileOffer = {
+ comments: offer.comments,
+ company: offersCompanyDtoMapper(offer.company),
+ id: offer.id,
+ jobType: offer.jobType,
+ location: offer.location,
+ monthYearReceived: offer.monthYearReceived,
+ negotiationStrategy: offer.negotiationStrategy,
+ offersFullTime: offer.OffersFullTime,
+ offersIntern: offer.OffersIntern,
+ };
+
+ if (offer.OffersFullTime) {
+ profileOfferDto.offersFullTime = {
+ baseSalary: valuationDtoMapper(offer.OffersFullTime.baseSalary),
+ bonus: valuationDtoMapper(offer.OffersFullTime.bonus),
+ id: offer.OffersFullTime.id,
+ level: offer.OffersFullTime.level,
+ specialization: offer.OffersFullTime.specialization,
+ stocks: valuationDtoMapper(offer.OffersFullTime.stocks),
+ title: offer.OffersFullTime.title,
+ totalCompensation: valuationDtoMapper(
+ offer.OffersFullTime.totalCompensation,
+ ),
+ };
+ } else if (offer.OffersIntern) {
+ profileOfferDto.offersIntern = {
+ id: offer.OffersIntern.id,
+ internshipCycle: offer.OffersIntern.internshipCycle,
+ monthlySalary: valuationDtoMapper(offer.OffersIntern.monthlySalary),
+ specialization: offer.OffersIntern.specialization,
+ startYear: offer.OffersIntern.startYear,
+ title: offer.OffersIntern.title,
+ };
+ }
+
+ return profileOfferDto;
+};
+
+export const profileDtoMapper = (
+ profile: OffersProfile & {
+ analysis:
+ | (OffersAnalysis & {
+ overallHighestOffer: OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | null;
+ OffersIntern:
+ | (OffersIntern & { monthlySalary: OffersCurrency })
+ | null;
+ company: Company;
+ profile: OffersProfile & { background: OffersBackground | null };
+ };
+ topCompanyOffers: Array<
+ OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | null;
+ OffersIntern:
+ | (OffersIntern & { monthlySalary: OffersCurrency })
+ | null;
+ company: Company;
+ profile: OffersProfile & {
+ background:
+ | (OffersBackground & {
+ experiences: Array<
+ OffersExperience & { company: Company | null }
+ >;
+ })
+ | null;
+ };
+ }
+ >;
+ topOverallOffers: Array<
+ OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | null;
+ OffersIntern:
+ | (OffersIntern & { monthlySalary: OffersCurrency })
+ | null;
+ company: Company;
+ profile: OffersProfile & {
+ background:
+ | (OffersBackground & {
+ experiences: Array<
+ OffersExperience & { company: Company | null }
+ >;
+ })
+ | null;
+ };
+ }
+ >;
+ })
+ | null;
+ background:
+ | (OffersBackground & {
+ educations: Array;
+ experiences: Array<
+ OffersExperience & {
+ company: Company | null;
+ monthlySalary: OffersCurrency | null;
+ totalCompensation: OffersCurrency | null;
+ }
+ >;
+ specificYoes: Array;
+ })
+ | null;
+ discussion: Array<
+ OffersReply & {
+ replies: Array;
+ replyingTo: OffersReply | null;
+ user: User | null;
+ }
+ >;
+ offers: Array<
+ OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & {
+ baseSalary: OffersCurrency;
+ bonus: OffersCurrency;
+ stocks: OffersCurrency;
+ totalCompensation: OffersCurrency;
+ })
+ | null;
+ OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
+ company: Company;
+ }
+ >;
+ },
+ inputToken: string | undefined,
+) => {
+ const profileDto: Profile = {
+ analysis: profileAnalysisDtoMapper(profile.analysis),
+ background: backgroundDtoMapper(profile.background),
+ editToken: null,
+ id: profile.id,
+ isEditable: false,
+ offers: profile.offers.map((offer) => profileOfferDtoMapper(offer)),
+ profileName: profile.profileName,
+ };
+
+ if (inputToken === profile.editToken) {
+ profileDto.editToken = profile.editToken;
+ profileDto.isEditable = true;
+ }
+
+ return profileDto;
+};
+
+export const createOfferProfileResponseMapper = (
+ profile: { id: string },
+ token: string,
+) => {
+ const res: CreateOfferProfileResponse = {
+ id: profile.id,
+ token,
+ };
+ return res;
+};
+
+export const addToProfileResponseMapper = (updatedProfile: {
+ id: string;
+ profileName: string;
+ userId?: string | null;
+}) => {
+ const addToProfileResponse: AddToProfileResponse = {
+ id: updatedProfile.id,
+ profileName: updatedProfile.profileName,
+ userId: updatedProfile.userId ?? '',
+ };
+
+ return addToProfileResponse;
+};
+
+export const dashboardOfferDtoMapper = (
+ offer: OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & {
+ baseSalary: OffersCurrency;
+ bonus: OffersCurrency;
+ stocks: OffersCurrency;
+ totalCompensation: OffersCurrency;
+ })
+ | null;
+ OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
+ company: Company;
+ profile: OffersProfile & { background: OffersBackground | null };
+ },
+) => {
+ const dashboardOfferDto: DashboardOffer = {
+ company: offersCompanyDtoMapper(offer.company),
+ id: offer.id,
+ income: valuationDtoMapper({ currency: '', value: -1 }),
+ monthYearReceived: offer.monthYearReceived,
+ profileId: offer.profileId,
+ title: offer.OffersFullTime?.title ?? '',
+ totalYoe: offer.profile.background?.totalYoe ?? -1,
+ };
+
+ if (offer.OffersFullTime) {
+ dashboardOfferDto.income = valuationDtoMapper(
+ offer.OffersFullTime.totalCompensation,
+ );
+ } else if (offer.OffersIntern) {
+ dashboardOfferDto.income = valuationDtoMapper(
+ offer.OffersIntern.monthlySalary,
+ );
+ }
+
+ return dashboardOfferDto;
+};
+
+export const getOffersResponseMapper = (
+ data: Array,
+ paging: Paging,
+) => {
+ const getOffersResponse: GetOffersResponse = {
+ data,
+ paging,
+ };
+ return getOffersResponse;
+};
diff --git a/apps/portal/src/pages/offers/profile/[offerProfileId].tsx b/apps/portal/src/pages/offers/profile/[offerProfileId].tsx
index ba629b87..db1965ca 100644
--- a/apps/portal/src/pages/offers/profile/[offerProfileId].tsx
+++ b/apps/portal/src/pages/offers/profile/[offerProfileId].tsx
@@ -43,25 +43,23 @@ export default function OfferProfile() {
if (data?.offers) {
const filteredOffers: Array = data
? data?.offers.map((res) => {
- if (res.OfferFullTime) {
+ if (res.offersFullTime) {
const filteredOffer: OfferEntity = {
base: convertCurrencyToString(
- res.OfferFullTime.baseSalary,
- ),
- bonus: convertCurrencyToString(
- res.OfferFullTime.bonus,
+ res.offersFullTime.baseSalary,
),
+ bonus: convertCurrencyToString(res.offersFullTime.bonus),
companyName: res.company.name,
- id: res.OfferFullTime.id,
- jobLevel: res.OfferFullTime.level,
- jobTitle: res.OfferFullTime.title,
+ id: res.offersFullTime.id,
+ jobLevel: res.offersFullTime.level,
+ jobTitle: res.offersFullTime.title,
location: res.location,
negotiationStrategy: res.negotiationStrategy || '',
otherComment: res.comments || '',
receivedMonth: formatDate(res.monthYearReceived),
- stocks: convertCurrencyToString(res.OfferFullTime.stocks),
+ stocks: convertCurrencyToString(res.offersFullTime.stocks),
totalCompensation: convertCurrencyToString(
- res.OfferFullTime.totalCompensation,
+ res.offersFullTime.totalCompensation,
),
};
@@ -69,11 +67,11 @@ export default function OfferProfile() {
}
const filteredOffer: OfferEntity = {
companyName: res.company.name,
- id: res.OfferIntern!.id,
- jobTitle: res.OfferIntern!.title,
+ id: res.offersIntern!.id,
+ jobTitle: res.offersIntern!.title,
location: res.location,
monthlySalary: convertCurrencyToString(
- res.OfferIntern!.monthlySalary,
+ res.offersIntern!.monthlySalary,
),
negotiationStrategy: res.negotiationStrategy || '',
otherComment: res.comments || '',
diff --git a/apps/portal/src/pages/offers/test/createProfile.tsx b/apps/portal/src/pages/offers/test/createProfile.tsx
index e47980b3..6aad538b 100644
--- a/apps/portal/src/pages/offers/test/createProfile.tsx
+++ b/apps/portal/src/pages/offers/test/createProfile.tsx
@@ -7,7 +7,7 @@ function Test() {
const [error, setError] = useState('');
const createMutation = trpc.useMutation(['offers.profile.create'], {
- onError(err: any) {
+ onError(err) {
alert(err);
},
onSuccess(data) {
@@ -18,7 +18,7 @@ function Test() {
const addToUserProfileMutation = trpc.useMutation(
['offers.profile.addToUserProfile'],
{
- onError(err: any) {
+ onError(err) {
alert(err);
},
onSuccess(data) {
@@ -28,7 +28,7 @@ function Test() {
);
const deleteCommentMutation = trpc.useMutation(['offers.comments.delete'], {
- onError(err: any) {
+ onError(err) {
alert(err);
},
onSuccess(data) {
@@ -46,7 +46,7 @@ function Test() {
};
const updateCommentMutation = trpc.useMutation(['offers.comments.update'], {
- onError(err: any) {
+ onError(err) {
alert(err);
},
onSuccess(data) {
@@ -64,7 +64,7 @@ function Test() {
};
const createCommentMutation = trpc.useMutation(['offers.comments.create'], {
- onError(err: any) {
+ onError(err) {
alert(err);
},
onSuccess(data) {
@@ -74,17 +74,18 @@ function Test() {
const handleCreate = () => {
createCommentMutation.mutate({
- message: 'hello',
- profileId: 'cl96stky5002ew32gx2kale2x',
- // UserId: 'cl97dl51k001e7iygd5v5gt58'
+ message: 'wassup bro',
+ profileId: 'cl9efyn9p004ww3u42mjgl1vn',
+ replyingToId: 'cl9el4xj10001w3w21o3p2iny',
+ userId: 'cl9ehvpng0000w3ec2mpx0bdd'
});
};
const handleLink = () => {
addToUserProfileMutation.mutate({
- profileId: 'cl96stky5002ew32gx2kale2x',
+ profileId: 'cl9efyn9p004ww3u42mjgl1vn',
token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba',
- userId: 'cl97dl51k001e7iygd5v5gt58',
+ userId: 'cl9ehvpng0000w3ec2mpx0bdd',
});
};
@@ -102,7 +103,7 @@ function Test() {
],
experiences: [
{
- companyId: 'cl98yuqk80007txhgjtjp8fk4',
+ companyId: 'cl9ec1mgg0000w33hg1a3612r',
durationInMonths: 24,
jobType: 'FULLTIME',
level: 'Junior',
@@ -150,6 +151,8 @@ function Test() {
value: 104100,
},
},
+
+ comments: 'I am a Raffles Institution almumni',
// Comments: '',
companyId: 'cl98yuqk80007txhgjtjp8fk4',
jobType: 'FULLTIME',
@@ -179,25 +182,25 @@ function Test() {
value: 104100,
},
},
- comments: undefined,
+ comments: '',
companyId: 'cl98yuqk80007txhgjtjp8fk4',
jobType: 'FULLTIME',
location: 'Singapore, Singapore',
monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
- // NegotiationStrategy: 'Leveraged having multiple offers',
+ negotiationStrategy: 'Leveraged having multiple offers',
},
],
});
};
- const profileId = 'cl99fhrsf00007ijpbrdk8gue'; // Remember to change this filed after testing deleting
+ const profileId = 'cl9efyn9p004ww3u42mjgl1vn'; // Remember to change this filed after testing deleting
const data = trpc.useQuery(
[
`offers.profile.listOne`,
{
profileId,
token:
- 'e7effd2a40adba2deb1ddea4fb9f1e6c3c98ab0a85a88ed1567fc2a107fdb445',
+ 'd14666ff76e267c9e99445844b41410e83874936d0c07e664db73ff0ea76919e',
},
],
{
@@ -216,6 +219,7 @@ function Test() {
},
);
+ // Console.log(replies.data?.data)
const deleteMutation = trpc.useMutation(['offers.profile.delete']);
const handleDelete = (id: string) => {
@@ -226,7 +230,7 @@ function Test() {
};
const updateMutation = trpc.useMutation(['offers.profile.update'], {
- onError(err: any) {
+ onError(err) {
alert(err);
},
onSuccess(response) {
@@ -261,7 +265,7 @@ function Test() {
slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
},
- companyId: 'cl98yuqk80007txhgjtjp8fk4',
+ companyId: 'cl9ec1mgg0000w33hg1a3612r',
durationInMonths: 24,
id: 'cl96stky6002iw32gpt6t87s2',
jobType: 'FULLTIME',
@@ -368,7 +372,7 @@ function Test() {
slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
},
- companyId: 'cl98yuqk80007txhgjtjp8fk4',
+ companyId: 'cl9ec1mgg0000w33hg1a3612r',
id: 'cl976t4de00047iygl0zbce11',
jobType: 'FULLTIME',
location: 'Singapore, Singapore',
@@ -410,7 +414,7 @@ function Test() {
totalCompensationId: 'cl96stky90039w32glbpktd0o',
},
OffersIntern: null,
- comments: null,
+ comments: '',
company: {
createdAt: new Date('2022-10-12T16:19:05.196Z'),
description:
@@ -421,7 +425,7 @@ function Test() {
slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
},
- companyId: 'cl98yuqk80007txhgjtjp8fk4',
+ companyId: 'cl9ec1mgg0000w33hg1a3612r',
id: 'cl96stky80031w32gau9mu1gs',
jobType: 'FULLTIME',
location: 'Singapore, Singapore',
@@ -463,7 +467,7 @@ function Test() {
totalCompensationId: 'cl96stky9003jw32gzumcoi7v',
},
OffersIntern: null,
- comments: null,
+ comments: '',
company: {
createdAt: new Date('2022-10-12T16:19:05.196Z'),
description:
@@ -474,7 +478,7 @@ function Test() {
slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
},
- companyId: 'cl98yuqk80007txhgjtjp8fk4',
+ companyId: 'cl9ec1mgg0000w33hg1a3612r',
id: 'cl96stky9003bw32gc3l955vr',
jobType: 'FULLTIME',
location: 'Singapore, Singapore',
@@ -527,7 +531,7 @@ function Test() {
slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
},
- companyId: 'cl98yuqk80007txhgjtjp8fk4',
+ companyId: 'cl9ec1mgg0000w33hg1a3612r',
id: 'cl976wf28000t7iyga4noyz7s',
jobType: 'FULLTIME',
location: 'Singapore, Singapore',
@@ -580,7 +584,7 @@ function Test() {
slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
},
- companyId: 'cl98yuqk80007txhgjtjp8fk4',
+ companyId: 'cl9ec1mgg0000w33hg1a3612r',
id: 'cl96tbb3o0051w32gjrpaiiit',
jobType: 'FULLTIME',
location: 'Singapore, Singapore',
@@ -600,7 +604,7 @@ function Test() {
return (
<>
{createdData}
- {JSON.stringify(replies.data)}
+ {JSON.stringify(replies.data?.data)}
diff --git a/apps/portal/src/server/router/offers/offers-analysis-router.ts b/apps/portal/src/server/router/offers/offers-analysis-router.ts
index efa684af..de92b546 100644
--- a/apps/portal/src/server/router/offers/offers-analysis-router.ts
+++ b/apps/portal/src/server/router/offers/offers-analysis-router.ts
@@ -8,9 +8,10 @@ import type {
OffersOffer,
OffersProfile,
} from '@prisma/client';
-import { JobType } from '@prisma/client';
import { TRPCError } from '@trpc/server';
+import { profileAnalysisDtoMapper } from '~/mappers/offers-mappers';
+
import { createRouter } from '../context';
const searchOfferPercentile = (
@@ -27,9 +28,19 @@ const searchOfferPercentile = (
company: Company;
profile: OffersProfile & { background: OffersBackground | null };
},
- similarOffers: Array | string,
+ similarOffers: Array<
+ OffersOffer & {
+ OffersFullTime:
+ | (OffersFullTime & {
+ totalCompensation: OffersCurrency;
+ })
+ | null;
+ OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
+ company: Company;
+ profile: OffersProfile & { background: OffersBackground | null };
+ }
+ >,
) => {
-
for (let i = 0; i < similarOffers.length; i++) {
if (similarOffers[i].id === offer.id) {
return i;
@@ -39,116 +50,6 @@ const searchOfferPercentile = (
return -1;
};
-const topPercentileDtoMapper = (topPercentileOffers: Array) => {
- return topPercentileOffers.map((offer) => {
- const { background } = offer.profile;
- return {
- company: { id: offer.company.id, name: offer.company.name },
- id: offer.id,
- jobType: offer.jobType,
- level: offer.OffersFullTime?.level,
- monthYearReceived: offer.monthYearReceived,
- monthlySalary: offer.OffersIntern?.monthlySalary?.value,
- negotiationStrategy: offer.negotiationStrategy,
- profile: {
- background: {
- experiences: background?.experiences.map(
- (exp: { company: { id: any; name: any }; id: any }) => {
- return {
- company: { id: exp.company.id, name: exp.company.name },
- id: exp.id,
- };
- },
- ),
- id: background?.id,
- totalYoe: background?.totalYoe,
- },
- id: offer.profileId,
- name: offer.profile.profileName,
- },
- specialization:
- offer.jobType === JobType.FULLTIME
- ? offer.OffersFullTime?.specialization
- : offer.OffersIntern?.specialization,
- title:
- offer.jobType === JobType.FULLTIME
- ? offer.OffersFullTime?.title
- : offer.OffersIntern?.title,
- totalCompensation: offer.OffersFullTime?.totalCompensation?.value,
- };
- });
-};
-
-const specificAnalysisDtoMapper = (
- noOfOffers: number,
- percentile: number,
- topPercentileOffers: Array,
-) => {
- return {
- noOfOffers,
- percentile,
- topPercentileCompanyOffers: topPercentileDtoMapper(topPercentileOffers),
- };
-};
-
-const highestOfferDtoMapper = (
- offer: OffersOffer & {
- OffersFullTime:
- | (OffersFullTime & { totalCompensation: OffersCurrency })
- | null;
- OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
- company: Company;
- profile: OffersProfile & { background: OffersBackground | null };
- },
-) => {
- return {
- company: { id: offer.company.id, name: offer.company.name },
- id: offer.id,
- level: offer.OffersFullTime?.level,
- location: offer.location,
- specialization:
- offer.jobType === JobType.FULLTIME
- ? offer.OffersFullTime?.specialization
- : offer.OffersIntern?.specialization,
- totalYoe: offer.profile.background?.totalYoe,
- };
-};
-
-const profileAnalysisDtoMapper = (
- analysisId: string,
- profileId: string,
- overallHighestOffer: OffersOffer & {
- OffersFullTime:
- | (OffersFullTime & { totalCompensation: OffersCurrency })
- | null;
- OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
- company: Company;
- profile: OffersProfile & { background: OffersBackground | null };
- },
- noOfSimilarOffers: number,
- overallPercentile: number,
- topPercentileOffers: Array,
- noOfSimilarCompanyOffers: number,
- companyPercentile: number,
- topPercentileCompanyOffers: Array,
-) => {
- return {
- companyAnalysis: specificAnalysisDtoMapper(
- noOfSimilarCompanyOffers,
- companyPercentile,
- topPercentileCompanyOffers,
- ),
- id: analysisId,
- overallAnalysis: specificAnalysisDtoMapper(
- noOfSimilarOffers,
- overallPercentile,
- topPercentileOffers,
- ),
- overallHighestOffer: highestOfferDtoMapper(overallHighestOffer),
- profileId,
- };
-};
-
export const offersAnalysisRouter = createRouter()
.query('generate', {
input: z.object({
@@ -213,7 +114,7 @@ export const offersAnalysisRouter = createRouter()
const overallHighestOffer = offers[0];
- // TODO: Shift yoe to background to make it mandatory
+ // TODO: Shift yoe out of background to make it mandatory
if (
!overallHighestOffer.profile.background ||
!overallHighestOffer.profile.background.totalYoe
@@ -465,17 +366,7 @@ export const offersAnalysisRouter = createRouter()
},
});
- return profileAnalysisDtoMapper(
- analysis.id,
- analysis.profileId,
- overallHighestOffer,
- noOfSimilarOffers,
- overallPercentile,
- topPercentileOffers,
- noOfSimilarCompanyOffers,
- companyPercentile,
- topPercentileCompanyOffers,
- );
+ return profileAnalysisDtoMapper(analysis);
},
})
.query('get', {
@@ -574,16 +465,6 @@ export const offersAnalysisRouter = createRouter()
});
}
- return profileAnalysisDtoMapper(
- analysis.id,
- analysis.profileId,
- analysis.overallHighestOffer,
- analysis.noOfSimilarOffers,
- analysis.overallPercentile,
- analysis.topOverallOffers,
- analysis.noOfSimilarCompanyOffers,
- analysis.companyPercentile,
- analysis.topCompanyOffers,
- );
+ return profileAnalysisDtoMapper(analysis);
},
});
diff --git a/apps/portal/src/server/router/offers/offers-comments-router.ts b/apps/portal/src/server/router/offers/offers-comments-router.ts
index 6e4cf6cc..20c79248 100644
--- a/apps/portal/src/server/router/offers/offers-comments-router.ts
+++ b/apps/portal/src/server/router/offers/offers-comments-router.ts
@@ -1,264 +1,329 @@
import { z } from 'zod';
import * as trpc from '@trpc/server';
-import { createProtectedRouter } from '../context';
+import { createRouter } from '../context';
-import type { Reply } from '~/types/offers-profile';
+import type { OffersDiscussion, Reply } from '~/types/offers';
+export const offersCommentsRouter = createRouter()
+ .query('getComments', {
+ input: z.object({
+ profileId: z.string(),
+ }),
+ async resolve({ ctx, input }) {
+ const profile = await ctx.prisma.offersProfile.findFirst({
+ where: {
+ id: input.profileId,
+ },
+ });
-export const offersCommentsRouter = createProtectedRouter()
- .query('getComments', {
- input: z.object({
- profileId: z.string()
- }),
- async resolve({ ctx, input }) {
+ const result = await ctx.prisma.offersProfile.findFirst({
+ include: {
+ discussion: {
+ include: {
+ replies: {
+ include: {
+ user: true,
+ },
+ },
+ replyingTo: true,
+ user: true,
+ },
+ },
+ },
+ where: {
+ id: input.profileId,
+ },
+ });
- const profile = await ctx.prisma.offersProfile.findFirst({
- where: {
- id: input.profileId
- }
+ const discussions: OffersDiscussion = {
+ data: result?.discussion
+ .filter((x) => {
+ return x.replyingToId === null
})
+ .map((x) => {
+ if (x.user == null) {
+ x.user = {
+ email: '',
+ emailVerified: null,
+ id: '',
+ image: '',
+ name: profile?.profileName ?? '',
+ };
+ }
- const result = await ctx.prisma.offersProfile.findFirst({
- include: {
- discussion: {
- include: {
- replies: {
- include: {
- user: true
- }
- },
- replyingTo: true,
- user: true
- }
- }
- },
- where: {
- id: input.profileId
+ x.replies?.map((y) => {
+ if (y.user == null) {
+ y.user = {
+ email: '',
+ emailVerified: null,
+ id: '',
+ image: '',
+ name: profile?.profileName ?? '',
+ };
}
- })
+ });
- if (result) {
- return result.discussion
- .filter((x: Reply) => x.replyingToId === null)
- .map((x: Reply) => {
- if (x.user == null) {
- x.user = {
- email: "",
- emailVerified: null,
- id: "",
- image: "",
- name: profile?.profileName ?? ""
- }
- }
+ const replyType: Reply = {
+ createdAt: x.createdAt,
+ id: x.id,
+ message: x.message,
+ replies: x.replies.map((reply) => {
+ return {
+ createdAt: reply.createdAt,
+ id: reply.id,
+ message: reply.message,
+ replies: [],
+ replyingToId: reply.replyingToId,
+ user: reply.user
+ }
+ }),
+ replyingToId: x.replyingToId,
+ user: x.user
+ }
- x.replies?.map((y) => {
- if (y.user == null) {
- y.user = {
- email: "",
- emailVerified: null,
- id: "",
- image: "",
- name: profile?.profileName ?? ""
- }
- }
- })
- return x;
- })
- }
+ return replyType
+ }) ?? []
+ }
- return result
- }
- })
- .mutation("create", {
- input: z.object({
- message: z.string(),
- profileId: z.string(),
- replyingToId: z.string().optional(),
- userId: z.string().optional()
- }),
- async resolve({ ctx, input }) {
- const createdReply = await ctx.prisma.offersReply.create({
- data: {
- message: input.message,
- profile: {
- connect: {
- id: input.profileId
- }
- }
- }
- })
+ return discussions
+ },
+ })
+ .mutation('create', {
+ input: z.object({
+ message: z.string(),
+ profileId: z.string(),
+ replyingToId: z.string().optional(),
+ token: z.string().optional(),
+ userId: z.string().optional()
+ }),
+ async resolve({ ctx, input }) {
+ const profile = await ctx.prisma.offersProfile.findFirst({
+ where: {
+ id: input.profileId,
+ },
+ });
- if (input.replyingToId) {
- await ctx.prisma.offersReply.update({
- data: {
- replyingTo: {
- connect: {
- id: input.replyingToId
- }
- }
- },
- where: {
- id: createdReply.id
- }
- })
- }
+ const profileEditToken = profile?.editToken;
- if (input.userId) {
- await ctx.prisma.offersReply.update({
- data: {
- user: {
- connect: {
- id: input.userId
- }
- }
- },
- where: {
- id: createdReply.id
- }
- })
- }
- // Get replies
- const result = await ctx.prisma.offersProfile.findFirst({
- include: {
- discussion: {
- include: {
- replies: true,
- replyingTo: true,
- user: true
- }
- }
+ if (input.token === profileEditToken || input.userId) {
+ const createdReply = await ctx.prisma.offersReply.create({
+ data: {
+ message: input.message,
+ profile: {
+ connect: {
+ id: input.profileId,
+ },
+ },
+ },
+ });
+
+ if (input.replyingToId) {
+ await ctx.prisma.offersReply.update({
+ data: {
+ replyingTo: {
+ connect: {
+ id: input.replyingToId,
},
- where: {
- id: input.profileId
- }
- })
+ },
+ },
+ where: {
+ id: createdReply.id,
+ },
+ });
+ }
- if (result) {
- return result.discussion.filter((x) => x.replyingToId === null)
- }
+ if (input.userId) {
+ await ctx.prisma.offersReply.update({
+ data: {
+ user: {
+ connect: {
+ id: input.userId,
+ },
+ },
+ },
+ where: {
+ id: createdReply.id,
+ },
+ });
+ }
+
+ const created = await ctx.prisma.offersReply.findFirst({
+ include: {
+ user: true
+ },
+ where: {
+ id: createdReply.id,
+ },
+ });
- return result
+ const result: Reply = {
+ createdAt: created!.createdAt,
+ id: created!.id,
+ message: created!.message,
+ replies: [], // New message should have no replies
+ replyingToId: created!.replyingToId,
+ user: created!.user ?? {
+ email: '',
+ emailVerified: null,
+ id: '',
+ image: '',
+ name: profile?.profileName ?? '',
+ }
}
- })
- .mutation("update", {
- input: z.object({
- id: z.string(),
- message: z.string(),
- profileId: z.string(),
- // Have to pass in either userID or token for validation
- token: z.string().optional(),
- userId: z.string().optional(),
- }),
- async resolve({ ctx, input }) {
- const messageToUpdate = await ctx.prisma.offersReply.findFirst({
- where: {
- id: input.id
- }
- })
- const profile = await ctx.prisma.offersProfile.findFirst({
- where: {
- id: input.profileId,
- },
- });
- const profileEditToken = profile?.editToken;
+ return result
+ }
- // To validate user editing, OP or correct user
- // TODO: improve validation process
- if (profileEditToken === input.token || messageToUpdate?.userId === input.userId) {
- await ctx.prisma.offersReply.update({
- data: {
- message: input.message
- },
- where: {
- id: input.id
- }
- })
+ throw new trpc.TRPCError({
+ code: 'UNAUTHORIZED',
+ message: 'Missing userId or wrong token.',
+ });
+ },
+ })
+ .mutation('update', {
+ input: z.object({
+ id: z.string(),
+ message: z.string(),
+ profileId: z.string(),
+ // Have to pass in either userID or token for validation
+ token: z.string().optional(),
+ userId: z.string().optional(),
+ }),
+ async resolve({ ctx, input }) {
+ const messageToUpdate = await ctx.prisma.offersReply.findFirst({
+ where: {
+ id: input.id,
+ },
+ });
+ const profile = await ctx.prisma.offersProfile.findFirst({
+ where: {
+ id: input.profileId,
+ },
+ });
- const result = await ctx.prisma.offersProfile.findFirst({
- include: {
- discussion: {
- include: {
- replies: true,
- replyingTo: true,
- user: true
- }
- }
- },
- where: {
- id: input.profileId
- }
- })
+ const profileEditToken = profile?.editToken;
- if (result) {
- return result.discussion.filter((x) => x.replyingToId === null)
- }
+ // To validate user editing, OP or correct user
+ // TODO: improve validation process
+ if (
+ profileEditToken === input.token ||
+ messageToUpdate?.userId === input.userId
+ ) {
+ const updated = await ctx.prisma.offersReply.update({
+ data: {
+ message: input.message,
+ },
+ include: {
+ replies: {
+ include: {
+ user: true
+ }
+ },
+ user: true
+ },
+ where: {
+ id: input.id,
+ },
+ });
- return result
+ const result: Reply = {
+ createdAt: updated!.createdAt,
+ id: updated!.id,
+ message: updated!.message,
+ replies: updated!.replies.map((x) => {
+ return {
+ createdAt: x.createdAt,
+ id: x.id,
+ message: x.message,
+ replies: [],
+ replyingToId: x.replyingToId,
+ user: x.user ?? {
+ email: '',
+ emailVerified: null,
+ id: '',
+ image: '',
+ name: profile?.profileName ?? '',
+ }
}
-
- throw new trpc.TRPCError({
- code: 'UNAUTHORIZED',
- message: 'Wrong userId or token.'
- })
+ }),
+ replyingToId: updated!.replyingToId,
+ user: updated!.user ?? {
+ email: '',
+ emailVerified: null,
+ id: '',
+ image: '',
+ name: profile?.profileName ?? '',
+ }
}
- })
- .mutation("delete", {
- input: z.object({
- id: z.string(),
- profileId: z.string(),
- // Have to pass in either userID or token for validation
- token: z.string().optional(),
- userId: z.string().optional(),
- }),
- async resolve({ ctx, input }) {
- const messageToDelete = await ctx.prisma.offersReply.findFirst({
- where: {
- id: input.id
- }
- })
- const profile = await ctx.prisma.offersProfile.findFirst({
- where: {
- id: input.profileId,
- },
- });
- const profileEditToken = profile?.editToken;
+ return result
+ }
- // To validate user editing, OP or correct user
- // TODO: improve validation process
- if (profileEditToken === input.token || messageToDelete?.userId === input.userId) {
- await ctx.prisma.offersReply.delete({
- where: {
- id: input.id
- }
- })
- const result = await ctx.prisma.offersProfile.findFirst({
- include: {
- discussion: {
- include: {
- replies: true,
- replyingTo: true,
- user: true
- }
- }
- },
- where: {
- id: input.profileId
- }
- })
+ throw new trpc.TRPCError({
+ code: 'UNAUTHORIZED',
+ message: 'Wrong userId or token.',
+ });
+ },
+ })
+ .mutation('delete', {
+ input: z.object({
+ id: z.string(),
+ profileId: z.string(),
+ // Have to pass in either userID or token for validation
+ token: z.string().optional(),
+ userId: z.string().optional(),
+ }),
+ async resolve({ ctx, input }) {
+ const messageToDelete = await ctx.prisma.offersReply.findFirst({
+ where: {
+ id: input.id,
+ },
+ });
+ const profile = await ctx.prisma.offersProfile.findFirst({
+ where: {
+ id: input.profileId,
+ },
+ });
- if (result) {
- return result.discussion.filter((x) => x.replyingToId === null)
- }
+ const profileEditToken = profile?.editToken;
- return result
- }
+ // To validate user editing, OP or correct user
+ // TODO: improve validation process
+ if (
+ profileEditToken === input.token ||
+ messageToDelete?.userId === input.userId
+ ) {
+ await ctx.prisma.offersReply.delete({
+ where: {
+ id: input.id,
+ },
+ });
+ await ctx.prisma.offersProfile.findFirst({
+ include: {
+ discussion: {
+ include: {
+ replies: true,
+ replyingTo: true,
+ user: true,
+ },
+ },
+ },
+ where: {
+ id: input.profileId,
+ },
+ });
- throw new trpc.TRPCError({
- code: 'UNAUTHORIZED',
- message: 'Wrong userId or token.'
- })
- }
- })
\ No newline at end of file
+ // If (result) {
+ // return result.discussion.filter((x) => x.replyingToId === null);
+ // }
+
+ // return result;
+ }
+
+ throw new trpc.TRPCError({
+ code: 'UNAUTHORIZED',
+ message: 'Wrong userId or token.',
+ });
+ },
+ });
diff --git a/apps/portal/src/server/router/offers/offers-profile-router.ts b/apps/portal/src/server/router/offers/offers-profile-router.ts
index 09e073da..11f74c3e 100644
--- a/apps/portal/src/server/router/offers/offers-profile-router.ts
+++ b/apps/portal/src/server/router/offers/offers-profile-router.ts
@@ -2,9 +2,13 @@ import crypto, { randomUUID } from 'crypto';
import { z } from 'zod';
import * as trpc from '@trpc/server';
-import { createRouter } from '../context';
+import {
+ addToProfileResponseMapper,
+ createOfferProfileResponseMapper,
+ profileDtoMapper,
+} from '~/mappers/offers-mappers';
-import type { OffersProfile } from '~/types/offers-profile';
+import { createRouter } from '../context';
const valuation = z.object({
currency: z.string(),
@@ -19,41 +23,45 @@ const company = z.object({
logoUrl: z.string().nullish(),
name: z.string(),
slug: z.string(),
- updatedAt: z.date()
-})
+ updatedAt: z.date(),
+});
const offer = z.object({
- OffersFullTime: z.object({
- baseSalary: valuation.nullish(),
- baseSalaryId: z.string().nullish(),
- bonus: valuation.nullish(),
- bonusId: z.string().nullish(),
- id: z.string().optional(),
- level: z.string().nullish(),
- specialization: z.string(),
- stocks: valuation.nullish(),
- stocksId: z.string().nullish(),
- title: z.string(),
- totalCompensation: valuation.nullish(),
- totalCompensationId: z.string().nullish(),
- }).nullish(),
- OffersIntern: z.object({
- id: z.string().optional(),
- internshipCycle: z.string().nullish(),
- monthlySalary: valuation.nullish(),
- specialization: z.string(),
- startYear: z.number().nullish(),
- title: z.string(),
- totalCompensation: valuation.nullish(), // Full time
- }).nullish(),
- comments: z.string().nullish(),
+ OffersFullTime: z
+ .object({
+ baseSalary: valuation.nullish(),
+ baseSalaryId: z.string().nullish(),
+ bonus: valuation.nullish(),
+ bonusId: z.string().nullish(),
+ id: z.string().optional(),
+ level: z.string().nullish(),
+ specialization: z.string(),
+ stocks: valuation.nullish(),
+ stocksId: z.string().nullish(),
+ title: z.string(),
+ totalCompensation: valuation.nullish(),
+ totalCompensationId: z.string().nullish(),
+ })
+ .nullish(),
+ OffersIntern: z
+ .object({
+ id: z.string().optional(),
+ internshipCycle: z.string().nullish(),
+ monthlySalary: valuation.nullish(),
+ specialization: z.string(),
+ startYear: z.number().nullish(),
+ title: z.string(),
+ totalCompensation: valuation.nullish(), // Full time
+ })
+ .nullish(),
+ comments: z.string(),
company: company.nullish(),
companyId: z.string(),
id: z.string().optional(),
jobType: z.string(),
location: z.string(),
monthYearReceived: z.date(),
- negotiationStrategy: z.string().nullish(),
+ negotiationStrategy: z.string(),
offersFullTimeId: z.string().nullish(),
offersInternId: z.string().nullish(),
profileId: z.string().nullish(),
@@ -72,7 +80,7 @@ const experience = z.object({
specialization: z.string().nullish(),
title: z.string().nullish(),
totalCompensation: valuation.nullish(),
- totalCompensationId: z.string().nullish()
+ totalCompensationId: z.string().nullish(),
});
const education = z.object({
@@ -91,32 +99,8 @@ const reply = z.object({
messages: z.string().nullish(),
profileId: z.string().nullish(),
replyingToId: z.string().nullish(),
- userId: z.string().nullish()
-})
-
-type WithIsEditable = T & {
- isEditable: boolean;
-};
-
-function computeIsEditable(
- profileInput: OffersProfile,
- editToken?: string,
-): WithIsEditable {
- return {
- ...profileInput,
- isEditable: profileInput.editToken === editToken,
- };
-}
-
-function exclude>(
- profile: WithIsEditable,
- ...keys: Array
-): Omit, Key> {
- for (const key of keys) {
- delete profile[key];
- }
- return profile;
-}
+ userId: z.string().nullish(),
+});
export const offersProfileRouter = createRouter()
.query('listOne', {
@@ -127,6 +111,86 @@ export const offersProfileRouter = createRouter()
async resolve({ ctx, input }) {
const result = await ctx.prisma.offersProfile.findFirst({
include: {
+ analysis: {
+ include: {
+ overallHighestOffer: {
+ include: {
+ OffersFullTime: {
+ include: {
+ totalCompensation: true,
+ },
+ },
+ OffersIntern: {
+ include: {
+ monthlySalary: true,
+ },
+ },
+ company: true,
+ profile: {
+ include: {
+ background: true,
+ },
+ },
+ },
+ },
+ topCompanyOffers: {
+ include: {
+ OffersFullTime: {
+ include: {
+ totalCompensation: true,
+ },
+ },
+ OffersIntern: {
+ include: {
+ monthlySalary: true,
+ },
+ },
+ company: true,
+ profile: {
+ include: {
+ background: {
+ include: {
+ experiences: {
+ include: {
+ company: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ topOverallOffers: {
+ include: {
+ OffersFullTime: {
+ include: {
+ totalCompensation: true,
+ },
+ },
+ OffersIntern: {
+ include: {
+ monthlySalary: true,
+ },
+ },
+ company: true,
+ profile: {
+ include: {
+ background: {
+ include: {
+ experiences: {
+ include: {
+ company: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
background: {
include: {
educations: true,
@@ -144,7 +208,7 @@ export const offersProfileRouter = createRouter()
include: {
replies: true,
replyingTo: true,
- user: true
+ user: true,
},
},
offers: {
@@ -172,7 +236,7 @@ export const offersProfileRouter = createRouter()
});
if (result) {
- return exclude(computeIsEditable(result, input.token), 'editToken')
+ return profileDtoMapper(result, input.token);
}
throw new trpc.TRPCError({
@@ -389,7 +453,8 @@ export const offersProfileRouter = createRouter()
title: x.OffersFullTime.title,
totalCompensation: {
create: {
- currency: x.OffersFullTime.totalCompensation?.currency,
+ currency:
+ x.OffersFullTime.totalCompensation?.currency,
value: x.OffersFullTime.totalCompensation?.value,
},
},
@@ -417,41 +482,9 @@ export const offersProfileRouter = createRouter()
},
profileName: randomUUID().substring(0, 10),
},
- include: {
- background: {
- include: {
- educations: true,
- experiences: {
- include: {
- company: true,
- monthlySalary: true,
- totalCompensation: true,
- },
- },
- specificYoes: true,
- },
- },
- offers: {
- include: {
- OffersFullTime: {
- include: {
- baseSalary: true,
- bonus: true,
- stocks: true,
- totalCompensation: true,
- },
- },
- OffersIntern: {
- include: {
- monthlySalary: true,
- },
- },
- },
- },
- },
});
- // TODO: add analysis to profile object then return
- return profile;
+
+ return createOfferProfileResponseMapper(profile, token);
},
})
.mutation('delete', {
@@ -468,11 +501,13 @@ export const offersProfileRouter = createRouter()
const profileEditToken = profileToDelete?.editToken;
if (profileEditToken === input.token) {
- return await ctx.prisma.offersProfile.delete({
+ const deletedProfile = await ctx.prisma.offersProfile.delete({
where: {
id: input.profileId,
},
});
+
+ return deletedProfile.id;
}
// TODO: Throw 401
throw new trpc.TRPCError({
@@ -493,7 +528,7 @@ export const offersProfileRouter = createRouter()
backgroundId: z.string().optional(),
domain: z.string(),
id: z.string().optional(),
- yoe: z.number()
+ yoe: z.number(),
}),
),
totalYoe: z.number(),
@@ -505,7 +540,7 @@ export const offersProfileRouter = createRouter()
offers: z.array(offer),
profileName: z.string(),
token: z.string(),
- userId: z.string().nullish()
+ userId: z.string().nullish(),
}),
async resolve({ ctx, input }) {
const profileToUpdate = await ctx.prisma.offersProfile.findFirst({
@@ -522,17 +557,17 @@ export const offersProfileRouter = createRouter()
},
where: {
id: input.id,
- }
+ },
});
await ctx.prisma.offersBackground.update({
data: {
- totalYoe: input.background.totalYoe
+ totalYoe: input.background.totalYoe,
},
where: {
- id: input.background.id
- }
- })
+ id: input.background.id,
+ },
+ });
for (const edu of input.background.educations) {
if (edu.id) {
@@ -545,27 +580,26 @@ export const offersProfileRouter = createRouter()
type: edu.type,
},
where: {
- id: edu.id
- }
- })
+ id: edu.id,
+ },
+ });
} else {
await ctx.prisma.offersBackground.update({
data: {
educations: {
- create:
- {
+ create: {
endDate: edu.endDate,
field: edu.field,
school: edu.school,
startDate: edu.startDate,
type: edu.type,
- }
- }
+ },
+ },
},
where: {
- id: input.background.id
- }
- })
+ id: input.background.id,
+ },
+ });
}
}
@@ -579,9 +613,9 @@ export const offersProfileRouter = createRouter()
specialization: exp.specialization,
},
where: {
- id: exp.id
- }
- })
+ id: exp.id,
+ },
+ });
if (exp.monthlySalary) {
await ctx.prisma.offersCurrency.update({
@@ -590,9 +624,9 @@ export const offersProfileRouter = createRouter()
value: exp.monthlySalary.value,
},
where: {
- id: exp.monthlySalary.id
- }
- })
+ id: exp.monthlySalary.id,
+ },
+ });
}
if (exp.totalCompensation) {
@@ -602,12 +636,16 @@ export const offersProfileRouter = createRouter()
value: exp.totalCompensation.value,
},
where: {
- id: exp.totalCompensation.id
- }
- })
+ id: exp.totalCompensation.id,
+ },
+ });
}
} else if (!exp.id) {
- if (exp.jobType === 'FULLTIME' && exp.totalCompensation?.currency !== undefined && exp.totalCompensation.value !== undefined) {
+ if (
+ exp.jobType === 'FULLTIME' &&
+ exp.totalCompensation?.currency !== undefined &&
+ exp.totalCompensation.value !== undefined
+ ) {
if (exp.companyId) {
await ctx.prisma.offersBackground.update({
data: {
@@ -630,12 +668,12 @@ export const offersProfileRouter = createRouter()
},
},
},
- }
+ },
},
where: {
- id: input.background.id
- }
- })
+ id: input.background.id,
+ },
+ });
} else {
await ctx.prisma.offersBackground.update({
data: {
@@ -652,16 +690,15 @@ export const offersProfileRouter = createRouter()
value: exp.totalCompensation?.value,
},
},
- }
- }
+ },
+ },
},
where: {
- id: input.background.id
- }
- })
+ id: input.background.id,
+ },
+ });
}
- }
- else if (
+ } else if (
exp.jobType === 'INTERN' &&
exp.monthlySalary?.currency !== undefined &&
exp.monthlySalary.value !== undefined
@@ -686,13 +723,13 @@ export const offersProfileRouter = createRouter()
},
specialization: exp.specialization,
title: exp.title,
- }
- }
+ },
+ },
},
where: {
- id: input.background.id
- }
- })
+ id: input.background.id,
+ },
+ });
} else {
await ctx.prisma.offersBackground.update({
data: {
@@ -708,44 +745,42 @@ export const offersProfileRouter = createRouter()
},
specialization: exp.specialization,
title: exp.title,
- }
- }
+ },
+ },
},
where: {
- id: input.background.id
- }
- })
+ id: input.background.id,
+ },
+ });
}
}
}
-
}
for (const yoe of input.background.specificYoes) {
if (yoe.id) {
await ctx.prisma.offersSpecificYoe.update({
data: {
- ...yoe
+ ...yoe,
},
where: {
- id: yoe.id
- }
- })
+ id: yoe.id,
+ },
+ });
} else {
await ctx.prisma.offersBackground.update({
data: {
specificYoes: {
- create:
- {
+ create: {
domain: yoe.domain,
yoe: yoe.yoe,
- }
- }
+ },
+ },
},
where: {
- id: input.background.id
- }
- })
+ id: input.background.id,
+ },
+ });
}
}
@@ -760,42 +795,46 @@ export const offersProfileRouter = createRouter()
negotiationStrategy: offerToUpdate.negotiationStrategy,
},
where: {
- id: offerToUpdate.id
- }
- })
+ id: offerToUpdate.id,
+ },
+ });
- if (offerToUpdate.jobType === "INTERN" || offerToUpdate.jobType === "FULLTIME") {
+ if (
+ offerToUpdate.jobType === 'INTERN' ||
+ offerToUpdate.jobType === 'FULLTIME'
+ ) {
await ctx.prisma.offersOffer.update({
data: {
- jobType: offerToUpdate.jobType
+ jobType: offerToUpdate.jobType,
},
where: {
- id: offerToUpdate.id
- }
- })
+ id: offerToUpdate.id,
+ },
+ });
}
if (offerToUpdate.OffersIntern?.monthlySalary) {
await ctx.prisma.offersIntern.update({
data: {
- internshipCycle: offerToUpdate.OffersIntern.internshipCycle ?? undefined,
+ internshipCycle:
+ offerToUpdate.OffersIntern.internshipCycle ?? undefined,
specialization: offerToUpdate.OffersIntern.specialization,
startYear: offerToUpdate.OffersIntern.startYear ?? undefined,
title: offerToUpdate.OffersIntern.title,
},
where: {
id: offerToUpdate.OffersIntern.id,
- }
- })
+ },
+ });
await ctx.prisma.offersCurrency.update({
data: {
currency: offerToUpdate.OffersIntern.monthlySalary.currency,
- value: offerToUpdate.OffersIntern.monthlySalary.value
+ value: offerToUpdate.OffersIntern.monthlySalary.value,
},
where: {
- id: offerToUpdate.OffersIntern.monthlySalary.id
- }
- })
+ id: offerToUpdate.OffersIntern.monthlySalary.id,
+ },
+ });
}
if (offerToUpdate.OffersFullTime?.totalCompensation) {
@@ -807,54 +846,55 @@ export const offersProfileRouter = createRouter()
},
where: {
id: offerToUpdate.OffersFullTime.id,
- }
- })
+ },
+ });
if (offerToUpdate.OffersFullTime.baseSalary) {
await ctx.prisma.offersCurrency.update({
data: {
currency: offerToUpdate.OffersFullTime.baseSalary.currency,
- value: offerToUpdate.OffersFullTime.baseSalary.value
+ value: offerToUpdate.OffersFullTime.baseSalary.value,
},
where: {
- id: offerToUpdate.OffersFullTime.baseSalary.id
- }
- })
+ id: offerToUpdate.OffersFullTime.baseSalary.id,
+ },
+ });
}
if (offerToUpdate.OffersFullTime.bonus) {
await ctx.prisma.offersCurrency.update({
data: {
currency: offerToUpdate.OffersFullTime.bonus.currency,
- value: offerToUpdate.OffersFullTime.bonus.value
+ value: offerToUpdate.OffersFullTime.bonus.value,
},
where: {
- id: offerToUpdate.OffersFullTime.bonus.id
- }
- })
+ id: offerToUpdate.OffersFullTime.bonus.id,
+ },
+ });
}
if (offerToUpdate.OffersFullTime.stocks) {
await ctx.prisma.offersCurrency.update({
data: {
currency: offerToUpdate.OffersFullTime.stocks.currency,
- value: offerToUpdate.OffersFullTime.stocks.value
+ value: offerToUpdate.OffersFullTime.stocks.value,
},
where: {
- id: offerToUpdate.OffersFullTime.stocks.id
- }
- })
+ id: offerToUpdate.OffersFullTime.stocks.id,
+ },
+ });
}
await ctx.prisma.offersCurrency.update({
data: {
- currency: offerToUpdate.OffersFullTime.totalCompensation.currency,
- value: offerToUpdate.OffersFullTime.totalCompensation.value
+ currency:
+ offerToUpdate.OffersFullTime.totalCompensation.currency,
+ value: offerToUpdate.OffersFullTime.totalCompensation.value,
},
where: {
- id: offerToUpdate.OffersFullTime.totalCompensation.id
- }
- })
+ id: offerToUpdate.OffersFullTime.totalCompensation.id,
+ },
+ });
}
} else {
if (
- offerToUpdate.jobType === "INTERN" &&
+ offerToUpdate.jobType === 'INTERN' &&
offerToUpdate.OffersIntern &&
offerToUpdate.OffersIntern.internshipCycle &&
offerToUpdate.OffersIntern.monthlySalary?.currency &&
@@ -867,14 +907,19 @@ export const offersProfileRouter = createRouter()
create: {
OffersIntern: {
create: {
- internshipCycle: offerToUpdate.OffersIntern.internshipCycle,
+ internshipCycle:
+ offerToUpdate.OffersIntern.internshipCycle,
monthlySalary: {
create: {
- currency: offerToUpdate.OffersIntern.monthlySalary?.currency,
- value: offerToUpdate.OffersIntern.monthlySalary?.value,
+ currency:
+ offerToUpdate.OffersIntern.monthlySalary
+ ?.currency,
+ value:
+ offerToUpdate.OffersIntern.monthlySalary?.value,
},
},
- specialization: offerToUpdate.OffersIntern.specialization,
+ specialization:
+ offerToUpdate.OffersIntern.specialization,
startYear: offerToUpdate.OffersIntern.startYear,
title: offerToUpdate.OffersIntern.title,
},
@@ -889,13 +934,13 @@ export const offersProfileRouter = createRouter()
location: offerToUpdate.location,
monthYearReceived: offerToUpdate.monthYearReceived,
negotiationStrategy: offerToUpdate.negotiationStrategy,
- }
- }
+ },
+ },
},
where: {
id: input.id,
- }
- })
+ },
+ });
}
if (
offerToUpdate.jobType === 'FULLTIME' &&
@@ -918,29 +963,39 @@ export const offersProfileRouter = createRouter()
create: {
baseSalary: {
create: {
- currency: offerToUpdate.OffersFullTime.baseSalary?.currency,
- value: offerToUpdate.OffersFullTime.baseSalary?.value,
+ currency:
+ offerToUpdate.OffersFullTime.baseSalary
+ ?.currency,
+ value:
+ offerToUpdate.OffersFullTime.baseSalary?.value,
},
},
bonus: {
create: {
- currency: offerToUpdate.OffersFullTime.bonus?.currency,
+ currency:
+ offerToUpdate.OffersFullTime.bonus?.currency,
value: offerToUpdate.OffersFullTime.bonus?.value,
},
},
level: offerToUpdate.OffersFullTime.level,
- specialization: offerToUpdate.OffersFullTime.specialization,
+ specialization:
+ offerToUpdate.OffersFullTime.specialization,
stocks: {
create: {
- currency: offerToUpdate.OffersFullTime.stocks?.currency,
+ currency:
+ offerToUpdate.OffersFullTime.stocks?.currency,
value: offerToUpdate.OffersFullTime.stocks?.value,
},
},
title: offerToUpdate.OffersFullTime.title,
totalCompensation: {
create: {
- currency: offerToUpdate.OffersFullTime.totalCompensation?.currency,
- value: offerToUpdate.OffersFullTime.totalCompensation?.value,
+ currency:
+ offerToUpdate.OffersFullTime.totalCompensation
+ ?.currency,
+ value:
+ offerToUpdate.OffersFullTime.totalCompensation
+ ?.value,
},
},
},
@@ -955,17 +1010,17 @@ export const offersProfileRouter = createRouter()
location: offerToUpdate.location,
monthYearReceived: offerToUpdate.monthYearReceived,
negotiationStrategy: offerToUpdate.negotiationStrategy,
- }
- }
+ },
+ },
},
where: {
id: input.id,
- }
- })
+ },
+ });
}
}
}
- // TODO: add analysis to profile object then return
+
const result = await ctx.prisma.offersProfile.findFirst({
include: {
background: {
@@ -985,7 +1040,7 @@ export const offersProfileRouter = createRouter()
include: {
replies: true,
replyingTo: true,
- user: true
+ user: true,
},
},
offers: {
@@ -1013,7 +1068,7 @@ export const offersProfileRouter = createRouter()
});
if (result) {
- return exclude(computeIsEditable(result, input.token), 'editToken')
+ return createOfferProfileResponseMapper(result, input.token);
}
throw new trpc.TRPCError({
@@ -1036,9 +1091,9 @@ export const offersProfileRouter = createRouter()
}),
async resolve({ ctx, input }) {
const profile = await ctx.prisma.offersProfile.findFirst({
- where: {
- id: input.profileId,
- },
+ where: {
+ id: input.profileId,
+ },
});
const profileEditToken = profile?.editToken;
@@ -1048,25 +1103,21 @@ export const offersProfileRouter = createRouter()
data: {
user: {
connect: {
- id: input.userId
- }
- }
+ id: input.userId,
+ },
+ },
},
where: {
- id: input.profileId
- }
- })
+ id: input.profileId,
+ },
+ });
- return {
- id: updated.id,
- profileName: updated.profileName,
- userId: updated.userId
- }
+ return addToProfileResponseMapper(updated);
}
throw new trpc.TRPCError({
code: 'UNAUTHORIZED',
message: 'Invalid token.',
});
- }
+ },
});
diff --git a/apps/portal/src/server/router/offers/offers.ts b/apps/portal/src/server/router/offers/offers.ts
index ceb1367c..a35e2d2e 100644
--- a/apps/portal/src/server/router/offers/offers.ts
+++ b/apps/portal/src/server/router/offers/offers.ts
@@ -1,6 +1,11 @@
import { z } from 'zod';
import { TRPCError } from '@trpc/server';
+import {
+ dashboardOfferDtoMapper,
+ getOffersResponseMapper,
+} from '~/mappers/offers-mappers';
+
import { createRouter } from '../context';
const yoeCategoryMap: Record = {
@@ -299,14 +304,14 @@ export const offersRouter = createRouter().query('list', {
: data.length;
const paginatedData = data.slice(startRecordIndex, endRecordIndex);
- return {
- data: paginatedData,
- paging: {
- currPage: input.offset,
- numOfItemsInPage: paginatedData.length,
+ return getOffersResponseMapper(
+ paginatedData.map((offer) => dashboardOfferDtoMapper(offer)),
+ {
+ currentPage: input.offset,
+ numOfItems: paginatedData.length,
numOfPages: Math.ceil(data.length / input.limit),
- totalNumberOfOffers: data.length,
+ totalItems: data.length,
},
- };
+ );
},
});
diff --git a/apps/portal/src/types/offers-profile.d.ts b/apps/portal/src/types/offers-profile.d.ts
deleted file mode 100644
index cc431184..00000000
--- a/apps/portal/src/types/offers-profile.d.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-export type OffersProfile = {
- background?: Background | null;
- createdAt: Date;
-// Discussions: Array;
- editToken: string;
- id: string;
- offers: Array;
- profileName: string;
- userId?: string | null;
-};
-
-export type Background = {
- educations: Array;
- experiences: Array;
- id: string;
- offersProfileId: string;
- specificYoes: Array;
- totalYoe?: number | null;
-}
-
-export type Experience = {
- backgroundId: string;
- company?: Company | null;
- companyId?: string | null;
- durationInMonths?: number | null;
- id: string;
- jobType?: string | null;
- level?: string | null;
- monthlySalary?: Valuation | null;
- monthlySalaryId?: string | null;
- specialization?: string | null;
- title?: string | null;
- totalCompensation?: Valuation | null;
- totalCompensationId?: string | null;
-}
-
-export type Company = {
- createdAt: Date;
- description: string | null;
- id: string;
- logoUrl: string | null;
- name: string;
- slug: string;
- updatedAt: Date
-}
-
-export type Valuation = {
- currency: string;
- id: string;
- value: number;
-}
-
-export type Education = {
- backgroundId: string;
- endDate?: Date | null;
- field?: string | null;
- id: string;
- school?: string | null;
- startDate?: Date | null;
- type?: string | null;
-}
-
-export type SpecificYoe = {
- backgroundId: string;
- domain: string;
- id: string;
- yoe: number;
-}
-
-export type Offer = {
- OfferFullTime?: OfferFullTime | null;
- OfferIntern?: OfferIntern | null;
- comments?: string | null;
- company: Company;
- companyId: string;
- id: string;
- jobType: string;
- location: string;
- monthYearReceived: Date;
- negotiationStrategy?: string | null;
- offersFullTimeId?: string | null;
- offersInternId?: string | null;
- profileId: string;
-}
-
-export type OfferFullTime = {
- baseSalary: Valuation;
- baseSalaryId: string;
- bonus: Valuation;
- bonusId: string;
- id: string;
- level: string;
- specialization: string;
- stocks: Valuation;
- stocksId: string;
- title?: string;
- totalCompensation: Valuation;
- totalCompensationId: string;
-}
-
-export type OfferIntern = {
- id: string;
- internshipCycle: string;
- monthlySalary: Valuation;
- monthlySalaryId: string;
- specialization: string;
- startYear: number;
- title?: string;
-}
-
-export type Reply = {
- createdAt: Date;
- id: string;
- message: string;
- // Profile: OffersProfile | null;
- profileId: string;
- replies: Array?;
- replyingTo: Discussion?;
- replyingToId: string | null;
- user: User?;
- userId: string | null;
-}
-
-export type User = {
- email: string?;
- emailVerified: Date?;
- id: string;
- image: string?;
- name: string?;
-}
\ No newline at end of file
diff --git a/apps/portal/src/types/offers.d.ts b/apps/portal/src/types/offers.d.ts
new file mode 100644
index 00000000..35539b45
--- /dev/null
+++ b/apps/portal/src/types/offers.d.ts
@@ -0,0 +1,186 @@
+import type { JobType } from '@prisma/client';
+
+export type Profile = {
+ analysis: ProfileAnalysis?;
+ background: Background?;
+ editToken: string?;
+ id: string;
+ isEditable: boolean;
+ offers: Array;
+ profileName: string;
+};
+
+export type Background = {
+ educations: Array;
+ experiences: Array;
+ id: string;
+ specificYoes: Array;
+ totalYoe: number;
+};
+
+export type Experience = {
+ company: OffersCompany?;
+ durationInMonths: number?;
+ id: string;
+ jobType: JobType?;
+ level: string?;
+ monthlySalary: Valuation?;
+ specialization: string?;
+ title: string?;
+ totalCompensation: Valuation?;
+};
+
+export type OffersCompany = {
+ createdAt: Date;
+ description: string;
+ id: string;
+ logoUrl: string;
+ name: string;
+ slug: string;
+ updatedAt: Date;
+};
+
+export type Valuation = {
+ currency: string;
+ value: number;
+};
+
+export type Education = {
+ endDate: Date?;
+ field: string?;
+ id: string;
+ school: string?;
+ startDate: Date?;
+ type: string?;
+};
+
+export type SpecificYoe = {
+ domain: string;
+ id: string;
+ yoe: number;
+};
+
+export type DashboardOffer = {
+ company: OffersCompany;
+ id: string;
+ income: Valuation;
+ monthYearReceived: Date;
+ profileId: string;
+ title: string;
+ totalYoe: number;
+};
+
+export type ProfileOffer = {
+ comments: string;
+ company: OffersCompany;
+ id: string;
+ jobType: JobType;
+ location: string;
+ monthYearReceived: Date;
+ negotiationStrategy: string;
+ offersFullTime: FullTime?;
+ offersIntern: Intern?;
+};
+
+export type FullTime = {
+ baseSalary: Valuation;
+ bonus: Valuation;
+ id: string;
+ level: string;
+ specialization: string;
+ stocks: Valuation;
+ title: string;
+ totalCompensation: Valuation;
+};
+
+export type Intern = {
+ id: string;
+ internshipCycle: string;
+ monthlySalary: Valuation;
+ specialization: string;
+ startYear: number;
+ title: string;
+};
+
+export type Reply = {
+ createdAt: Date;
+ id: string;
+ message: string;
+ replies: Array?;
+ replyingToId: string?;
+ user: User?;
+};
+
+export type User = {
+ email: string?;
+ emailVerified: Date?;
+ id: string;
+ image: string?;
+ name: string?;
+};
+
+export type GetOffersResponse = {
+ data: Array;
+ paging: Paging;
+};
+
+export type Paging = {
+ currentPage: number;
+ numOfItems: number;
+ numOfPages: number;
+ totalItems: number;
+};
+
+export type CreateOfferProfileResponse = {
+ id: string;
+ token: string;
+};
+
+export type OffersDiscussion = {
+ data: Array;
+};
+
+export type ProfileAnalysis = {
+ companyAnalysis: Array;
+ id: string;
+ overallAnalysis: Analysis;
+ overallHighestOffer: AnalysisHighestOffer;
+ profileId: string;
+};
+
+export type Analysis = {
+ noOfOffers: number;
+ percentile: number;
+ topPercentileOffers: Array;
+};
+
+export type AnalysisHighestOffer = {
+ company: OffersCompany;
+ id: string;
+ level: string;
+ location: string;
+ specialization: string;
+ totalYoe: number;
+};
+
+export type AnalysisOffer = {
+ company: OffersCompany;
+ id: string;
+ income: number;
+ jobType: JobType;
+ level: string;
+ location: string;
+ monthYearReceived: Date;
+ negotiationStrategy: string;
+ previousCompanies: Array;
+ profileName: string;
+ specialization: string;
+ title: string;
+ totalYoe: number;
+};
+
+export type AddToProfileResponse = {
+ id: string;
+ profileName: string;
+ userId: string;
+};
|