diff --git a/apps/portal/prisma/migrations/20221102121331_update_location_for_offers/migration.sql b/apps/portal/prisma/migrations/20221102121331_update_location_for_offers/migration.sql
new file mode 100644
index 00000000..06a7d7af
--- /dev/null
+++ b/apps/portal/prisma/migrations/20221102121331_update_location_for_offers/migration.sql
@@ -0,0 +1,21 @@
+/*
+ Warnings:
+
+ - You are about to drop the column `location` on the `OffersExperience` table. All the data in the column will be lost.
+ - You are about to drop the column `location` on the `OffersOffer` table. All the data in the column will be lost.
+ - Added the required column `cityId` to the `OffersOffer` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- AlterTable
+ALTER TABLE "OffersExperience" DROP COLUMN "location",
+ADD COLUMN "cityId" TEXT;
+
+-- AlterTable
+ALTER TABLE "OffersOffer" DROP COLUMN "location",
+ADD COLUMN "cityId" TEXT NOT NULL;
+
+-- AddForeignKey
+ALTER TABLE "OffersExperience" ADD CONSTRAINT "OffersExperience_cityId_fkey" FOREIGN KEY ("cityId") REFERENCES "City"("id") ON DELETE SET NULL ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "OffersOffer" ADD CONSTRAINT "OffersOffer_cityId_fkey" FOREIGN KEY ("cityId") REFERENCES "City"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
diff --git a/apps/portal/prisma/schema.prisma b/apps/portal/prisma/schema.prisma
index b2820c3c..b6873fde 100644
--- a/apps/portal/prisma/schema.prisma
+++ b/apps/portal/prisma/schema.prisma
@@ -131,6 +131,8 @@ model City {
stateId String
state State @relation(fields: [stateId], references: [id])
questionsQuestionEncounters QuestionsQuestionEncounter[]
+ OffersExperience OffersExperience[]
+ OffersOffer OffersOffer[]
@@unique([name, stateId])
}
@@ -265,7 +267,8 @@ model OffersExperience {
// Add more fields
durationInMonths Int?
- location String?
+ location City? @relation(fields: [cityId], references: [id])
+ cityId String?
// FULLTIME fields
level String?
@@ -348,8 +351,9 @@ model OffersOffer {
company Company @relation(fields: [companyId], references: [id])
companyId String
+ location City @relation(fields: [cityId], references: [id])
+ cityId String
monthYearReceived DateTime
- location String
negotiationStrategy String
comments String
diff --git a/apps/portal/src/components/offers/constants.ts b/apps/portal/src/components/offers/constants.ts
index e2b14d96..d49dca1a 100644
--- a/apps/portal/src/components/offers/constants.ts
+++ b/apps/portal/src/components/offers/constants.ts
@@ -2,21 +2,6 @@ import { EducationBackgroundType } from './types';
export const emptyOption = '----';
-export const locationOptions = [
- {
- label: 'Singapore, Singapore',
- value: 'Singapore, Singapore',
- },
- {
- label: 'New York, US',
- value: 'New York, US',
- },
- {
- label: 'San Francisco, US',
- value: 'San Francisco, US',
- },
-];
-
export const internshipCycleOptions = [
{
label: 'Summer',
diff --git a/apps/portal/src/components/offers/dashboard/DashboardOfferCard.tsx b/apps/portal/src/components/offers/dashboard/DashboardOfferCard.tsx
index d76bcd60..722263b6 100644
--- a/apps/portal/src/components/offers/dashboard/DashboardOfferCard.tsx
+++ b/apps/portal/src/components/offers/dashboard/DashboardOfferCard.tsx
@@ -51,7 +51,7 @@ export default function DashboardProfileCard({
aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400"
/>
- {location}
+ {location.cityName}
)}
{level && (
diff --git a/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx b/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx
index 59a2019f..bdf9a1b3 100644
--- a/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx
+++ b/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx
@@ -69,9 +69,7 @@ export default function OfferProfileCard({
{getLabelForJobTitleType(title as JobTitleType)}{' '}
{`(${JobTypeLabel[jobType]})`}
-
- Company: {company.name}, {location}
-
+ {`Company: ${company.name}, ${location}`}
{level && Level: {level}
}
diff --git a/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx b/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx
index c6156137..06415aad 100644
--- a/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx
+++ b/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx
@@ -26,11 +26,11 @@ import { getCurrentMonth, getCurrentYear } from '~/utils/offers/time';
import { trpc } from '~/utils/trpc';
const defaultOfferValues = {
+ cityId: '',
comments: '',
companyId: '',
jobTitle: '',
jobType: JobType.FULLTIME,
- location: '',
monthYearReceived: {
month: getCurrentMonth() as Month,
year: getCurrentYear(),
diff --git a/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx b/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx
index d0d718ba..bfe5ee5f 100644
--- a/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx
+++ b/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx
@@ -7,9 +7,9 @@ import {
educationLevelOptions,
emptyOption,
FieldError,
- locationOptions,
} from '~/components/offers/constants';
import type { BackgroundPostData } from '~/components/offers/types';
+import CitiesTypeahead from '~/components/shared/CitiesTypeahead';
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
@@ -102,6 +102,12 @@ function FullTimeJobFields() {
const watchCompanyName = useWatch({
name: 'background.experiences.0.companyName',
});
+ const watchCityId = useWatch({
+ name: 'background.experiences.0.cityId',
+ });
+ const watchCityName = useWatch({
+ name: 'background.experiences.0.cityName',
+ });
return (
<>
@@ -166,11 +172,22 @@ function FullTimeJobFields() {
placeholder="e.g. L4, Junior"
{...register(`background.experiences.0.level`)}
/>
- {
+ if (option) {
+ setValue('background.experiences.0.cityId', option.value);
+ setValue('background.experiences.0.cityName', option.label);
+ } else {
+ setValue('background.experiences.0.cityId', '');
+ setValue('background.experiences.0.cityName', '');
+ }
+ }}
/>
@@ -256,12 +279,22 @@ function InternshipJobFields() {
})}
/>
- {
+ if (option) {
+ setValue('background.experiences.0.cityId', option.value);
+ setValue('background.experiences.0.cityName', option.label);
+ } else {
+ setValue('background.experiences.0.cityId', '');
+ setValue('background.experiences.0.cityName', '');
+ }
+ }}
/>
>
diff --git a/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx b/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx
index b1a438f7..7c9e52e6 100644
--- a/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx
+++ b/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx
@@ -12,6 +12,7 @@ import { TrashIcon } from '@heroicons/react/24/outline';
import { JobType } from '@prisma/client';
import { Button, Dialog, HorizontalDivider } from '@tih/ui';
+import CitiesTypeahead from '~/components/shared/CitiesTypeahead';
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
@@ -25,7 +26,6 @@ import {
emptyOption,
FieldError,
internshipCycleOptions,
- locationOptions,
yearOptions,
} from '../../constants';
import FormMonthYearPicker from '../../forms/FormMonthYearPicker';
@@ -64,6 +64,12 @@ function FullTimeOfferDetailsForm({
const watchCompanyName = useWatch({
name: `offers.${index}.companyName`,
});
+ const watchCityId = useWatch({
+ name: `offers.${index}.cityId`,
+ });
+ const watchCityName = useWatch({
+ name: `offers.${index}.cityName`,
+ });
const watchCurrency = useWatch({
name: `offers.${index}.offersFullTime.totalCompensation.currency`,
});
@@ -119,16 +125,23 @@ function FullTimeOfferDetailsForm({
}
}}
/>
- {
+ if (option) {
+ setValue(`offers.${index}.cityId`, option.value);
+ setValue(`offers.${index}.cityName`, option.label);
+ } else {
+ setValue(`offers.${index}.cityId`, '');
+ setValue(`offers.${index}.cityName`, '');
+ }
+ }}
/>
@@ -308,6 +321,12 @@ function InternshipOfferDetailsForm({
const watchCompanyName = useWatch({
name: `offers.${index}.companyName`,
});
+ const watchCityId = useWatch({
+ name: `offers.${index}.cityId`,
+ });
+ const watchCityName = useWatch({
+ name: `offers.${index}.cityName`,
+ });
return (
@@ -341,16 +360,23 @@ function InternshipOfferDetailsForm({
}
}}
/>
- {
+ if (option) {
+ setValue(`offers.${index}.cityId`, option.value);
+ setValue(`offers.${index}.cityName`, option.label);
+ } else {
+ setValue(`offers.${index}.cityId`, '');
+ setValue(`offers.${index}.cityName`, '');
+ }
+ }}
/>
diff --git a/apps/portal/src/components/offers/profile/OfferCard.tsx b/apps/portal/src/components/offers/profile/OfferCard.tsx
index 5e5df4c4..3d03e1ef 100644
--- a/apps/portal/src/components/offers/profile/OfferCard.tsx
+++ b/apps/portal/src/components/offers/profile/OfferCard.tsx
@@ -40,7 +40,7 @@ export default function OfferCard({
- {location ? `${companyName}, ${location}` : companyName}
+ {location ? `${companyName}, ${location.cityName}` : companyName}
@@ -92,11 +92,11 @@ export default function OfferCard({
)}
- {totalCompensation && (
+ {(base || stocks || bonus) && totalCompensation && (
- Base / year: {base} ⋅ Stocks / year: {stocks} ⋅ Bonus / year:{' '}
- {bonus}
+ Base / year: {base ?? 'N/A'} ⋅ Stocks / year:{' '}
+ {stocks ?? 'N/A'} ⋅ Bonus / year: {bonus ?? 'N/A'}
)}
diff --git a/apps/portal/src/components/offers/table/OffersTable.tsx b/apps/portal/src/components/offers/table/OffersTable.tsx
index dc091ac2..e31ce619 100644
--- a/apps/portal/src/components/offers/table/OffersTable.tsx
+++ b/apps/portal/src/components/offers/table/OffersTable.tsx
@@ -21,10 +21,12 @@ import type { DashboardOffer, GetOffersResponse, Paging } from '~/types/offers';
const NUMBER_OF_OFFERS_IN_PAGE = 10;
export type OffersTableProps = Readonly<{
+ cityFilter: string;
companyFilter: string;
jobTitleFilter: string;
}>;
export default function OffersTable({
+ cityFilter,
companyFilter,
jobTitleFilter,
}: OffersTableProps) {
@@ -53,10 +55,11 @@ export default function OffersTable({
[
'offers.list',
{
+ // Location: 'Singapore, Singapore', // TODO: Geolocation
+ cityId: cityFilter,
companyId: companyFilter,
currency,
limit: NUMBER_OF_OFFERS_IN_PAGE,
- location: 'Singapore, Singapore', // TODO: Geolocation
offset: pagination.currentPage,
sortBy: OfferTableSortBy[selectedFilter] ?? '-monthYearReceived',
title: jobTitleFilter,
@@ -97,7 +100,7 @@ export default function OffersTable({
- View all offers in
+ Display offers in
setCurrency(value)}
diff --git a/apps/portal/src/components/offers/types.ts b/apps/portal/src/components/offers/types.ts
index 366ca25b..0e963a17 100644
--- a/apps/portal/src/components/offers/types.ts
+++ b/apps/portal/src/components/offers/types.ts
@@ -2,6 +2,8 @@ import type { JobType } from '@prisma/client';
import type { MonthYear } from '~/components/shared/MonthYearPicker';
+import type { Location } from '~/types/offers';
+
export const HOME_URL = '/offers';
/*
@@ -44,13 +46,14 @@ export type BackgroundPostData = {
};
type ExperiencePostData = {
+ cityId?: string | null;
+ cityName?: string | null;
companyId?: string | null;
companyName?: string | null;
durationInMonths?: number | null;
id?: string;
jobType?: string | null;
level?: string | null;
- location?: string | null;
monthlySalary?: Money | null;
title?: string | null;
totalCompensation?: Money | null;
@@ -75,12 +78,13 @@ type SpecificYoePostData = {
type SpecificYoe = SpecificYoePostData;
export type OfferPostData = {
+ cityId: string;
+ cityName?: string;
comments: string;
companyId: string;
companyName?: string;
id?: string;
jobType: JobType;
- location: string;
monthYearReceived: Date;
negotiationStrategy: string;
offersFullTime?: OfferFullTimePostData | null;
@@ -132,7 +136,7 @@ export type OfferDisplayData = {
jobLevel?: string | null;
jobTitle?: string | null;
jobType?: JobType;
- location?: string | null;
+ location?: Location | null;
monthlySalary?: string | null;
negotiationStrategy?: string | null;
otherComment?: string | null;
diff --git a/apps/portal/src/mappers/offers-mappers.ts b/apps/portal/src/mappers/offers-mappers.ts
index 7ce52626..e0cea797 100644
--- a/apps/portal/src/mappers/offers-mappers.ts
+++ b/apps/portal/src/mappers/offers-mappers.ts
@@ -1,5 +1,7 @@
import type {
+ City,
Company,
+ Country,
OffersAnalysis,
OffersAnalysisUnit,
OffersBackground,
@@ -12,6 +14,7 @@ import type {
OffersProfile,
OffersReply,
OffersSpecificYoe,
+ State,
User,
} from '@prisma/client';
import { JobType } from '@prisma/client';
@@ -28,6 +31,7 @@ import type {
Education,
Experience,
GetOffersResponse,
+ Location,
OffersCompany,
Paging,
Profile,
@@ -42,6 +46,7 @@ import type {
const analysisOfferDtoMapper = (
offer: OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -49,7 +54,14 @@ const analysisOfferDtoMapper = (
profile: OffersProfile & {
background:
| (OffersBackground & {
- experiences: Array;
+ experiences: Array<
+ OffersExperience & {
+ company: Company | null;
+ location:
+ | (City & { state: State & { country: Country } })
+ | null;
+ }
+ >;
})
| null;
};
@@ -68,7 +80,7 @@ const analysisOfferDtoMapper = (
},
jobType: offer.jobType,
level: offer.offersFullTime?.level ?? '',
- location: offer.location,
+ location: locationDtoMapper(offer.location),
monthYearReceived: offer.monthYearReceived,
negotiationStrategy: offer.negotiationStrategy,
previousCompanies:
@@ -117,6 +129,7 @@ const analysisUnitDtoMapper = (
topSimilarOffers: Array<
OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -125,7 +138,12 @@ const analysisUnitDtoMapper = (
background:
| (OffersBackground & {
experiences: Array<
- OffersExperience & { company: Company | null }
+ OffersExperience & {
+ company: Company | null;
+ location:
+ | (City & { state: State & { country: Country } })
+ | null;
+ }
>;
})
| null;
@@ -148,6 +166,7 @@ const analysisUnitDtoMapper = (
const analysisHighestOfferDtoMapper = (
offer: OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -159,7 +178,7 @@ const analysisHighestOfferDtoMapper = (
company: offersCompanyDtoMapper(offer.company),
id: offer.id,
level: offer.offersFullTime?.level ?? '',
- location: offer.location,
+ location: locationDtoMapper(offer.location),
totalYoe: offer.profile.background?.totalYoe ?? -1,
};
return analysisHighestOfferDto;
@@ -173,6 +192,7 @@ export const profileAnalysisDtoMapper = (
topSimilarOffers: Array<
OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -183,7 +203,12 @@ export const profileAnalysisDtoMapper = (
background:
| (OffersBackground & {
experiences: Array<
- OffersExperience & { company: Company | null }
+ OffersExperience & {
+ company: Company | null;
+ location:
+ | (City & { state: State & { country: Country } })
+ | null;
+ }
>;
})
| null;
@@ -196,6 +221,7 @@ export const profileAnalysisDtoMapper = (
topSimilarOffers: Array<
OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -206,7 +232,12 @@ export const profileAnalysisDtoMapper = (
background:
| (OffersBackground & {
experiences: Array<
- OffersExperience & { company: Company | null }
+ OffersExperience & {
+ company: Company | null;
+ location:
+ | (City & { state: State & { country: Country } })
+ | null;
+ }
>;
})
| null;
@@ -216,6 +247,7 @@ export const profileAnalysisDtoMapper = (
};
overallHighestOffer: OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -247,6 +279,23 @@ export const profileAnalysisDtoMapper = (
return profileAnalysisDto;
};
+export const locationDtoMapper = (
+ city: City & { state: State & { country: Country } },
+) => {
+ const { state } = city;
+ const { country } = state;
+ const locationDto: Location = {
+ cityId: city.id,
+ cityName: city.name,
+ countryCode: country.code,
+ countryId: country.id,
+ countryName: country.name,
+ stateId: state.id,
+ stateName: state.name,
+ };
+ return locationDto;
+};
+
export const valuationDtoMapper = (currency: {
baseCurrency: string;
baseValue: number;
@@ -300,6 +349,7 @@ export const educationDtoMapper = (education: {
export const experienceDtoMapper = (
experience: OffersExperience & {
company: Company | null;
+ location: (City & { state: State & { country: Country } }) | null;
monthlySalary: OffersCurrency | null;
totalCompensation: OffersCurrency | null;
},
@@ -312,7 +362,10 @@ export const experienceDtoMapper = (
id: experience.id,
jobType: experience.jobType,
level: experience.level,
- location: experience.location,
+ location:
+ experience.location != null
+ ? locationDtoMapper(experience.location)
+ : null,
monthlySalary: experience.monthlySalary
? valuationDtoMapper(experience.monthlySalary)
: null,
@@ -345,6 +398,7 @@ export const backgroundDtoMapper = (
experiences: Array<
OffersExperience & {
company: Company | null;
+ location: (City & { state: State & { country: Country } }) | null;
monthlySalary: OffersCurrency | null;
totalCompensation: OffersCurrency | null;
}
@@ -383,6 +437,7 @@ export const backgroundDtoMapper = (
export const profileOfferDtoMapper = (
offer: OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & {
baseSalary: OffersCurrency | null;
@@ -399,7 +454,7 @@ export const profileOfferDtoMapper = (
company: offersCompanyDtoMapper(offer.company),
id: offer.id,
jobType: offer.jobType,
- location: offer.location,
+ location: locationDtoMapper(offer.location),
monthYearReceived: offer.monthYearReceived,
negotiationStrategy: offer.negotiationStrategy,
offersFullTime: offer.offersFullTime,
@@ -449,6 +504,7 @@ export const profileDtoMapper = (
topSimilarOffers: Array<
OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -459,7 +515,14 @@ export const profileDtoMapper = (
background:
| (OffersBackground & {
experiences: Array<
- OffersExperience & { company: Company | null }
+ OffersExperience & {
+ company: Company | null;
+ location:
+ | (City & {
+ state: State & { country: Country };
+ })
+ | null;
+ }
>;
})
| null;
@@ -472,6 +535,7 @@ export const profileDtoMapper = (
topSimilarOffers: Array<
OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -482,7 +546,12 @@ export const profileDtoMapper = (
background:
| (OffersBackground & {
experiences: Array<
- OffersExperience & { company: Company | null }
+ OffersExperience & {
+ company: Company | null;
+ location:
+ | (City & { state: State & { country: Country } })
+ | null;
+ }
>;
})
| null;
@@ -492,6 +561,7 @@ export const profileDtoMapper = (
};
overallHighestOffer: OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -508,6 +578,7 @@ export const profileDtoMapper = (
experiences: Array<
OffersExperience & {
company: Company | null;
+ location: (City & { state: State & { country: Country } }) | null;
monthlySalary: OffersCurrency | null;
totalCompensation: OffersCurrency | null;
}
@@ -525,6 +596,7 @@ export const profileDtoMapper = (
offers: Array<
OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & {
baseSalary: OffersCurrency | null;
@@ -656,6 +728,7 @@ export const getUserProfileResponseMapper = (
offers: Array<
OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -691,6 +764,7 @@ export const getUserProfileResponseMapper = (
const userProfileOfferDtoMapper = (
offer: OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
| (OffersFullTime & { totalCompensation: OffersCurrency })
| null;
@@ -709,7 +783,7 @@ const userProfileOfferDtoMapper = (
},
jobType: offer.jobType,
level: offer.offersFullTime?.level ?? '',
- location: offer.location,
+ location: locationDtoMapper(offer.location),
monthYearReceived: offer.monthYearReceived,
title:
offer.jobType === JobType.FULLTIME
diff --git a/apps/portal/src/pages/offers/index.tsx b/apps/portal/src/pages/offers/index.tsx
index 2bc90e0c..f1581e01 100644
--- a/apps/portal/src/pages/offers/index.tsx
+++ b/apps/portal/src/pages/offers/index.tsx
@@ -1,9 +1,11 @@
import Link from 'next/link';
import { useState } from 'react';
+import { MapPinIcon } from '@heroicons/react/24/outline';
import { Banner } from '@tih/ui';
import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
import OffersTable from '~/components/offers/table/OffersTable';
+import CitiesTypeahead from '~/components/shared/CitiesTypeahead';
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
import Container from '~/components/shared/Container';
import type { JobTitleType } from '~/components/shared/JobTitles';
@@ -14,6 +16,7 @@ export default function OffersHomePage() {
'software-engineer',
);
const [companyFilter, setCompanyFilter] = useState('');
+ const [cityFilter, setCityFilter] = useState('');
const { event: gaEvent } = useGoogleAnalytics();
return (
@@ -25,6 +28,25 @@ export default function OffersHomePage() {
. ⭐
+
+
+
+
+ {
+ if (option) {
+ setCityFilter(option.value);
+ gaEvent({
+ action: `offers.table_filter_city_${option.value}`,
+ category: 'engagement',
+ label: 'Filter by city',
+ });
+ }
+ }}
+ />
+
@@ -66,7 +88,7 @@ export default function OffersHomePage() {
if (option) {
setCompanyFilter(option.value);
gaEvent({
- action: 'offers.table_filter_company',
+ action: `offers.table_filter_company_${option.value}`,
category: 'engagement',
label: 'Filter by company',
});
@@ -80,6 +102,7 @@ export default function OffersHomePage() {
diff --git a/apps/portal/src/pages/offers/profile/edit/[offerProfileId].tsx b/apps/portal/src/pages/offers/profile/edit/[offerProfileId].tsx
index 05e47b7c..829acb28 100644
--- a/apps/portal/src/pages/offers/profile/edit/[offerProfileId].tsx
+++ b/apps/portal/src/pages/offers/profile/edit/[offerProfileId].tsx
@@ -36,13 +36,14 @@ export default function OffersEditPage() {
experiences.length === 0
? [{ jobType: JobType.FULLTIME }]
: experiences.map((exp) => ({
+ cityId: exp.location?.cityId,
+ cityName: exp.location?.cityName,
companyId: exp.company?.id,
companyName: exp.company?.name,
durationInMonths: exp.durationInMonths,
id: exp.id,
jobType: exp.jobType,
level: exp.level,
- location: exp.location,
monthlySalary: exp.monthlySalary,
title: exp.title,
totalCompensation: exp.totalCompensation,
@@ -53,12 +54,13 @@ export default function OffersEditPage() {
},
id: data.id,
offers: data.offers.map((offer) => ({
+ cityId: offer.location.cityId,
+ cityName: offer.location.cityName,
comments: offer.comments,
companyId: offer.company.id,
companyName: offer.company.name,
id: offer.id,
jobType: offer.jobType,
- location: offer.location,
monthYearReceived: convertToMonthYear(offer.monthYearReceived),
negotiationStrategy: offer.negotiationStrategy,
offersFullTime: offer.offersFullTime,
diff --git a/apps/portal/src/pages/offers/test/createProfile.tsx b/apps/portal/src/pages/offers/test/createProfile.tsx
deleted file mode 100644
index 610d4e00..00000000
--- a/apps/portal/src/pages/offers/test/createProfile.tsx
+++ /dev/null
@@ -1,412 +0,0 @@
-import React, { useState } from 'react';
-
-import { trpc } from '~/utils/trpc';
-
-function Test() {
- const [createdData, setCreatedData] = useState('');
- const [error, setError] = useState('');
-
- const createMutation = trpc.useMutation(['offers.profile.create'], {
- onError(err) {
- alert(err);
- },
- onSuccess(data) {
- setCreatedData(JSON.stringify(data));
- },
- });
-
- const addToUserProfileMutation = trpc.useMutation(
- ['offers.user.profile.addToUserProfile'],
- {
- onError(err) {
- alert(err);
- },
- onSuccess(data) {
- setCreatedData(JSON.stringify(data));
- },
- },
- );
-
- const deleteCommentMutation = trpc.useMutation(['offers.comments.delete'], {
- onError(err) {
- alert(err);
- },
- onSuccess(data) {
- setCreatedData(JSON.stringify(data));
- },
- });
-
- const handleDeleteComment = () => {
- deleteCommentMutation.mutate({
- id: 'cl97fprun001j7iyg6ev9x983',
- profileId: 'cl96stky5002ew32gx2kale2x',
- token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
- userId: 'cl97dl51k001e7iygd5v5gt58',
- });
- };
-
- const updateCommentMutation = trpc.useMutation(['offers.comments.update'], {
- onError(err) {
- alert(err);
- },
- onSuccess(data) {
- setCreatedData(JSON.stringify(data));
- },
- });
-
- const handleUpdateComment = () => {
- updateCommentMutation.mutate({
- id: 'cl97fxb0y001l7iyg14sdobt2',
- message: 'hello hello',
- profileId: 'cl96stky5002ew32gx2kale2x',
- token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba',
- });
- };
-
- const createCommentMutation = trpc.useMutation(['offers.comments.create'], {
- onError(err) {
- alert(err);
- },
- onSuccess(data) {
- setCreatedData(JSON.stringify(data));
- },
- });
-
- const handleCreate = () => {
- createCommentMutation.mutate({
- message: 'wassup bro',
- profileId: 'cl9efyn9p004ww3u42mjgl1vn',
- replyingToId: 'cl9el4xj10001w3w21o3p2iny',
- userId: 'cl9ehvpng0000w3ec2mpx0bdd',
- });
- };
-
- const handleLink = () => {
- addToUserProfileMutation.mutate({
- profileId: 'cl9efyn9p004ww3u42mjgl1vn',
- token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
- // UserId: 'cl9ehvpng0000w3ec2mpx0bdd',
- });
- };
-
- const handleClick = () => {
- createMutation.mutate({
- background: {
- educations: [
- {
- endDate: new Date('2018-09-30T07:58:54.000Z'),
- field: 'Computer Science',
- school: 'National University of Singapore',
- startDate: new Date('2014-09-30T07:58:54.000Z'),
- type: 'Bachelors',
- },
- ],
- experiences: [
- {
- companyId: 'cl9j4yawz0003utlp1uaa1t8o',
- durationInMonths: 24,
- jobType: 'FULLTIME',
- level: 'Junior',
- title: 'software-engineer',
- totalCompensation: {
- currency: 'SGD',
- value: 104100,
- },
- },
- ],
- specificYoes: [
- {
- domain: 'Front End',
- yoe: 2,
- },
- {
- domain: 'Full Stack',
- yoe: 2,
- },
- ],
- totalYoe: 4,
- },
- offers: [
- {
- comments: 'I am a Raffles Institution almumni',
- // Comments: '',
- companyId: 'cl9j4yawz0003utlp1uaa1t8o',
- jobType: 'FULLTIME',
- location: 'Singapore, Singapore',
- monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
- negotiationStrategy: 'Leveraged having multiple offers',
- offersFullTime: {
- baseSalary: {
- currency: 'SGD',
- value: 2222,
- },
- bonus: {
- currency: 'SGD',
- value: 2222,
- },
- level: 'Junior',
- stocks: {
- currency: 'SGD',
- value: 0,
- },
- title: 'software-engineer',
- totalCompensation: {
- currency: 'SGD',
- value: 4444,
- },
- },
- },
- {
- comments: '',
- companyId: 'cl9j4yawz0003utlp1uaa1t8o',
- jobType: 'FULLTIME',
- location: 'Singapore, Singapore',
- monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
- negotiationStrategy: 'Leveraged having multiple offers',
- offersFullTime: {
- baseSalary: {
- currency: 'SGD',
- value: 84000,
- },
- bonus: {
- currency: 'SGD',
- value: 20000,
- },
- level: 'Junior',
- stocks: {
- currency: 'SGD',
- value: 100,
- },
- title: 'software-engineer',
- totalCompensation: {
- currency: 'SGD',
- value: 104100,
- },
- },
- },
- ],
- });
- };
-
- const profileId = 'cl9j50xzk008vutfqg6mta2ey'; // Remember to change this filed after testing deleting
- const data = trpc.useQuery(
- [
- `offers.profile.listOne`,
- {
- profileId,
- token:
- '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
- },
- ],
- {
- onError(err) {
- setError(err.shape?.message || '');
- },
- },
- );
-
- trpc.useQuery(
- [
- `offers.profile.isValidToken`,
- {
- profileId: 'cl9scdzuh0000tt727ipone1k',
- token:
- 'aa628d0db3ad7a5f84895537d4cca38edd0a9b8b96d869cddeb967fccf068c08',
- },
- ],
- {
- onError(err) {
- setError(err.shape?.message || '');
- },
- },
- );
-
- const replies = trpc.useQuery(
- ['offers.comments.getComments', { profileId }],
- {
- onError(err) {
- setError(err.shape?.message || '');
- },
- },
- );
-
- const deleteMutation = trpc.useMutation(['offers.profile.delete']);
-
- const handleDelete = (id: string) => {
- deleteMutation.mutate({
- profileId: id,
- token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
- });
- };
-
- const updateMutation = trpc.useMutation(['offers.profile.update'], {
- onError(err) {
- alert(err);
- },
- onSuccess(response) {
- setCreatedData(JSON.stringify(response));
- },
- });
-
- const handleUpdate = () => {
- updateMutation.mutate({
- background: {
- educations: [
- {
- backgroundId: 'cl9i68fv60001tthj23g9tuv4',
- endDate: new Date('2018-09-30T07:58:54.000Z'),
- field: 'Computer Science',
- id: 'cl9i87y7z004otthjmpsd48wo',
- school: 'National University of Singapore',
- startDate: new Date('2014-09-30T07:58:54.000Z'),
- type: 'Bachelors',
- },
- ],
- experiences: [
- {
- backgroundId: 'cl9i68fv60001tthj23g9tuv4',
- company: {
- createdAt: new Date('2022-10-12T16:19:05.196Z'),
- description:
- 'Meta Platforms, Inc., doing business as Meta and formerly named Facebook, Inc., and TheFacebook, Inc., is an American multinational technology conglomerate based in Menlo Park, California. The company owns Facebook, Instagram, and WhatsApp, among other products and services.',
- id: 'cl9j4yawz0003utlp1uaa1t8o',
- logoUrl: 'https://logo.clearbit.com/meta.com',
- name: 'Meta',
- slug: 'meta',
- updatedAt: new Date('2022-10-12T16:19:05.196Z'),
- },
- companyId: 'cl9j4yawz0003utlp1uaa1t8o',
- durationInMonths: 24,
- // Id: 'cl9j4yawz0003utlp1uaa1t8o',
- jobType: 'FULLTIME',
- level: 'Junior',
- monthlySalary: null,
- monthlySalaryId: null,
- title: 'software-engineer',
- totalCompensation: {
- currency: 'SGD',
- id: 'cl9i68fvc0005tthj7r1rhvb1',
- value: 100,
- },
- totalCompensationId: 'cl9i68fvc0005tthj7r1rhvb1',
- },
- ],
- id: 'cl9i68fv60001tthj23g9tuv4',
- offersProfileId: 'cl9i68fv60000tthj8t3zkox0',
- specificYoes: [
- {
- backgroundId: 'cl9i68fv60001tthj23g9tuv4',
- domain: 'Backend',
- id: 'cl9i68fvc0008tthjlxslzfo4',
- yoe: 5,
- },
- {
- backgroundId: 'cl9i68fv60001tthj23g9tuv4',
- domain: 'Backend',
- id: 'cl9i68fvc0009tthjwol3285l',
- yoe: 4,
- },
- ],
- totalYoe: 1,
- },
- createdAt: '2022-10-13T08:28:13.518Z',
- // Discussion: [],
- id: 'cl9i68fv60000tthj8t3zkox0',
- isEditable: true,
- offers: [
- {
- comments: 'this IS SO IEUHDAEUIGDI',
- company: {
- createdAt: new Date('2022-10-12T16:19:05.196Z'),
- description:
- 'Meta Platforms, Inc., doing business as Meta and formerly named Facebook, Inc., and TheFacebook, Inc., is an American multinational technology conglomerate based in Menlo Park, California. The company owns Facebook, Instagram, and WhatsApp, among other products and services.',
- id: 'cl9j4yawz0003utlp1uaa1t8o',
- logoUrl: 'https://logo.clearbit.com/meta.com',
- name: 'Meta',
- slug: 'meta',
- updatedAt: new Date('2022-10-12T16:19:05.196Z'),
- },
- companyId: 'cl9j4yawz0003utlp1uaa1t8o',
- id: 'cl9i68fve000ntthj5h9yvqnh',
- jobType: 'FULLTIME',
- location: 'Singapore, Singapore',
- monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
- negotiationStrategy: 'Charmed the guy with my face',
- offersFullTime: {
- baseSalary: {
- currency: 'SGD',
- id: 'cl9i68fve000ptthjn55hpoe4',
- value: 1999999999,
- },
- baseSalaryId: 'cl9i68fve000ptthjn55hpoe4',
- bonus: {
- currency: 'SGD',
- id: 'cl9i68fve000rtthjqo2ktljt',
- value: 1410065407,
- },
- bonusId: 'cl9i68fve000rtthjqo2ktljt',
- id: 'cl9i68fve000otthjqk0g01k0',
- level: 'EXPERT',
- stocks: {
- currency: 'SGD',
- id: 'cl9i68fvf000ttthjt2ode0cc',
- value: -558038585,
- },
- stocksId: 'cl9i68fvf000ttthjt2ode0cc',
- title: 'software-engineer',
- totalCompensation: {
- currency: 'SGD',
- id: 'cl9i68fvf000vtthjg90s48nj',
- value: 55555555,
- },
- totalCompensationId: 'cl9i68fvf000vtthjg90s48nj',
- },
- offersFullTimeId: 'cl9i68fve000otthjqk0g01k0',
- offersIntern: null,
- offersInternId: null,
- profileId: 'cl9i68fv60000tthj8t3zkox0',
- },
- ],
-
- token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
- userId: null,
- });
- };
-
- return (
- <>
- {createdData}
- {JSON.stringify(replies.data?.data)}
-
-
-
-
-
-
-
- {JSON.stringify(data.data)}
- {JSON.stringify(error)}
- >
- );
-}
-
-export default Test;
diff --git a/apps/portal/src/pages/offers/test/generateAnalysis.tsx b/apps/portal/src/pages/offers/test/generateAnalysis.tsx
deleted file mode 100644
index 87c4cfbb..00000000
--- a/apps/portal/src/pages/offers/test/generateAnalysis.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-
-import { trpc } from '~/utils/trpc';
-
-function GenerateAnalysis() {
- const analysisMutation = trpc.useMutation(['offers.analysis.generate']);
-
- return (
-
- {JSON.stringify(
- analysisMutation.mutate({ profileId: 'cl9jj2ks1001li9fn9np47wjr' }),
- )}
-
- );
-}
-
-export default GenerateAnalysis;
diff --git a/apps/portal/src/pages/offers/test/getAnalysis.tsx b/apps/portal/src/pages/offers/test/getAnalysis.tsx
deleted file mode 100644
index 8ad7bff0..00000000
--- a/apps/portal/src/pages/offers/test/getAnalysis.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-
-import { trpc } from '~/utils/trpc';
-
-function GetAnalysis() {
- const analysis = trpc.useQuery([
- 'offers.analysis.get',
- { profileId: 'cl9jj2ks1001li9fn9np47wjr' },
- ]);
-
- return {JSON.stringify(analysis.data)}
;
-}
-
-export default GetAnalysis;
diff --git a/apps/portal/src/pages/offers/test/listOffers.tsx b/apps/portal/src/pages/offers/test/listOffers.tsx
deleted file mode 100644
index b59f50c6..00000000
--- a/apps/portal/src/pages/offers/test/listOffers.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-
-import { trpc } from '~/utils/trpc';
-
-function Test() {
- const data = trpc.useQuery([
- 'offers.list',
- {
- currency: 'SGD',
- limit: 100,
- location: 'Singapore, Singapore',
- offset: 0,
- sortBy: '-totalCompensation',
- yoeCategory: 2,
- },
- ]);
-
- const deleteMutation = trpc.useMutation(['offers.profile.delete']);
-
- const handleDelete = (id: string) => {
- deleteMutation.mutate({ profileId: id, token: ' dadaadad' });
- };
-
- return (
-
- -
- {JSON.stringify(data.data?.paging)}
-
- -
-
- {data.data?.data.map((offer) => {
- return (
- -
-
-
{JSON.stringify(offer)}
-
-
- );
- })}
-
-
-
- );
-}
-
-export default Test;
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 0b22c8a7..06e8db8c 100644
--- a/apps/portal/src/server/router/offers/offers-analysis-router.ts
+++ b/apps/portal/src/server/router/offers/offers-analysis-router.ts
@@ -19,6 +19,15 @@ export const offersAnalysisRouter = createRouter()
topSimilarOffers: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
@@ -36,6 +45,15 @@ export const offersAnalysisRouter = createRouter()
experiences: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
},
},
},
@@ -51,6 +69,15 @@ export const offersAnalysisRouter = createRouter()
topSimilarOffers: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
@@ -68,6 +95,15 @@ export const offersAnalysisRouter = createRouter()
experiences: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
},
},
},
@@ -81,6 +117,15 @@ export const offersAnalysisRouter = createRouter()
overallHighestOffer: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
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 e25bb076..d669c85c 100644
--- a/apps/portal/src/server/router/offers/offers-profile-router.ts
+++ b/apps/portal/src/server/router/offers/offers-profile-router.ts
@@ -35,12 +35,12 @@ const company = z.object({
});
const offer = z.object({
+ cityId: z.string(),
comments: z.string(),
company: company.nullish(),
companyId: z.string(),
id: z.string().optional(),
jobType: z.string().regex(createValidationRegex(Object.keys(JobType), null)),
- location: z.string(),
monthYearReceived: z.date(),
negotiationStrategy: z.string(),
offersFullTime: z
@@ -75,6 +75,7 @@ const offer = z.object({
const experience = z.object({
backgroundId: z.string().nullish(),
+ cityId: z.string().nullish(),
company: company.nullish(),
companyId: z.string().nullish(),
durationInMonths: z.number().nullish(),
@@ -84,7 +85,6 @@ const experience = z.object({
.regex(createValidationRegex(Object.keys(JobType), null))
.nullish(),
level: z.string().nullish(),
- location: z.string().nullish(),
monthlySalary: valuation.nullish(),
monthlySalaryId: z.string().nullish(),
title: z.string().nullish(),
@@ -171,6 +171,15 @@ export const offersProfileRouter = createRouter()
topSimilarOffers: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
@@ -188,6 +197,15 @@ export const offersProfileRouter = createRouter()
experiences: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
},
},
},
@@ -203,6 +221,15 @@ export const offersProfileRouter = createRouter()
topSimilarOffers: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
@@ -220,6 +247,15 @@ export const offersProfileRouter = createRouter()
experiences: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
},
},
},
@@ -233,6 +269,15 @@ export const offersProfileRouter = createRouter()
overallHighestOffer: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
@@ -258,6 +303,15 @@ export const offersProfileRouter = createRouter()
experiences: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
monthlySalary: true,
totalCompensation: true,
},
@@ -275,6 +329,15 @@ export const offersProfileRouter = createRouter()
offers: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
baseSalary: true,
@@ -350,6 +413,39 @@ export const offersProfileRouter = createRouter()
input.background.experiences.map(async (x) => {
if (x.jobType === JobType.FULLTIME) {
if (x.companyId) {
+ if (x.cityId) {
+ return {
+ company: {
+ connect: {
+ id: x.companyId,
+ },
+ },
+ durationInMonths: x.durationInMonths,
+ jobType: x.jobType,
+ level: x.level,
+ location: {
+ connect: {
+ id: x.cityId
+ }
+ },
+ title: x.title,
+ totalCompensation:
+ x.totalCompensation != null
+ ? {
+ create: {
+ baseCurrency: baseCurrencyString,
+ baseValue: await convert(
+ x.totalCompensation.value,
+ x.totalCompensation.currency,
+ baseCurrencyString,
+ ),
+ currency: x.totalCompensation.currency,
+ value: x.totalCompensation.value,
+ },
+ }
+ : undefined,
+ };
+ }
return {
company: {
connect: {
@@ -377,11 +473,40 @@ export const offersProfileRouter = createRouter()
: undefined,
};
}
+ if (x.cityId) {
+ return {
+ durationInMonths: x.durationInMonths,
+ jobType: x.jobType,
+ level: x.level,
+ location: {
+ connect: {
+ where: {
+ id: x.cityId
+ }
+ }
+ },
+ title: x.title,
+ totalCompensation:
+ x.totalCompensation != null
+ ? {
+ create: {
+ baseCurrency: baseCurrencyString,
+ baseValue: await convert(
+ x.totalCompensation.value,
+ x.totalCompensation.currency,
+ baseCurrencyString,
+ ),
+ currency: x.totalCompensation.currency,
+ value: x.totalCompensation.value,
+ },
+ }
+ : undefined,
+ };
+ }
return {
durationInMonths: x.durationInMonths,
jobType: x.jobType,
level: x.level,
- location: x.location,
title: x.title,
totalCompensation:
x.totalCompensation != null
@@ -402,6 +527,40 @@ export const offersProfileRouter = createRouter()
}
if (x.jobType === JobType.INTERN) {
if (x.companyId) {
+ if (x.cityId) {
+ return {
+ company: {
+ connect: {
+ id: x.companyId,
+ },
+ },
+ durationInMonths: x.durationInMonths,
+ jobType: x.jobType,
+ location: {
+ connect: {
+ where: {
+ id: x.cityId
+ }
+ }
+ },
+ monthlySalary:
+ x.monthlySalary != null
+ ? {
+ create: {
+ baseCurrency: baseCurrencyString,
+ baseValue: await convert(
+ x.monthlySalary.value,
+ x.monthlySalary.currency,
+ baseCurrencyString,
+ ),
+ currency: x.monthlySalary.currency,
+ value: x.monthlySalary.value,
+ },
+ }
+ : undefined,
+ title: x.title,
+ };
+ }
return {
company: {
connect: {
@@ -428,6 +587,37 @@ export const offersProfileRouter = createRouter()
title: x.title,
};
}
+
+ if (x.cityId) {
+ return {
+ durationInMonths: x.durationInMonths,
+ jobType: x.jobType,
+ location: {
+ connect: {
+ where: {
+ id: x.cityId
+ }
+ }
+ },
+ monthlySalary:
+ x.monthlySalary != null
+ ? {
+ create: {
+ baseCurrency: baseCurrencyString,
+ baseValue: await convert(
+ x.monthlySalary.value,
+ x.monthlySalary.currency,
+ baseCurrencyString,
+ ),
+ currency: x.monthlySalary.currency,
+ value: x.monthlySalary.value,
+ },
+ }
+ : undefined,
+ title: x.title,
+ };
+ }
+
return {
durationInMonths: x.durationInMonths,
jobType: x.jobType,
@@ -488,7 +678,13 @@ export const offersProfileRouter = createRouter()
},
},
jobType: x.jobType,
- location: x.location,
+ location: {
+ connect: {
+ where: {
+ id: x.cityId
+ }
+ }
+ },
monthYearReceived: x.monthYearReceived,
negotiationStrategy: x.negotiationStrategy,
offersIntern: {
@@ -528,7 +724,13 @@ export const offersProfileRouter = createRouter()
},
},
jobType: x.jobType,
- location: x.location,
+ location: {
+ connect: {
+ where: {
+ id: x.cityId
+ }
+ }
+ },
monthYearReceived: x.monthYearReceived,
negotiationStrategy: x.negotiationStrategy,
offersFullTime: {
@@ -809,14 +1011,14 @@ export const offersProfileRouter = createRouter()
),
currency: exp.monthlySalary.currency,
value: exp.monthlySalary.value,
- }
- }
- }
+ },
+ },
+ },
},
where: {
- id: exp.id
- }
- })
+ id: exp.id,
+ },
+ });
}
if (exp.totalCompensation) {
@@ -843,14 +1045,14 @@ export const offersProfileRouter = createRouter()
),
currency: exp.totalCompensation.currency,
value: exp.totalCompensation.value,
- }
- }
- }
+ },
+ },
+ },
},
where: {
- id: exp.id
- }
- })
+ id: exp.id,
+ },
+ });
}
} else if (!exp.id) {
// Create new experience
@@ -859,35 +1061,110 @@ export const offersProfileRouter = createRouter()
exp.totalCompensation?.currency != null &&
exp.totalCompensation?.value != null
) {
+ // FULLTIME
if (exp.companyId) {
+ if (exp.cityId) {
+ await ctx.prisma.offersBackground.update({
+ data: {
+ experiences: {
+ create: {
+ company: {
+ connect: {
+ id: exp.companyId,
+ },
+ },
+ durationInMonths: exp.durationInMonths,
+ jobType: exp.jobType,
+ level: exp.level,
+ location: {
+ connect: {
+ id: exp.cityId
+ }
+ },
+ title: exp.title,
+ totalCompensation: exp.totalCompensation
+ ? {
+ create: {
+ baseCurrency: baseCurrencyString,
+ baseValue: await convert(
+ exp.totalCompensation.value,
+ exp.totalCompensation.currency,
+ baseCurrencyString,
+ ),
+ currency: exp.totalCompensation.currency,
+ value: exp.totalCompensation.value,
+ },
+ }
+ : undefined,
+ },
+ },
+ },
+ where: {
+ id: input.background.id,
+ },
+ });
+ } else {
+ await ctx.prisma.offersBackground.update({
+ data: {
+ experiences: {
+ create: {
+ company: {
+ connect: {
+ id: exp.companyId,
+ },
+ },
+ durationInMonths: exp.durationInMonths,
+ jobType: exp.jobType,
+ level: exp.level,
+ title: exp.title,
+ totalCompensation: exp.totalCompensation
+ ? {
+ create: {
+ baseCurrency: baseCurrencyString,
+ baseValue: await convert(
+ exp.totalCompensation.value,
+ exp.totalCompensation.currency,
+ baseCurrencyString,
+ ),
+ currency: exp.totalCompensation.currency,
+ value: exp.totalCompensation.value,
+ },
+ }
+ : undefined,
+ },
+ },
+ },
+ where: {
+ id: input.background.id,
+ },
+ });
+ }
+ } else if (exp.cityId) {
await ctx.prisma.offersBackground.update({
data: {
experiences: {
create: {
- company: {
- connect: {
- id: exp.companyId,
- },
- },
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
level: exp.level,
- location: exp.location,
+ location: {
+ connect: {
+ id: exp.cityId
+ }
+ },
title: exp.title,
- totalCompensation: exp.totalCompensation
- ? {
- create: {
- baseCurrency: baseCurrencyString,
- baseValue: await convert(
- exp.totalCompensation.value,
- exp.totalCompensation.currency,
- baseCurrencyString,
- ),
- currency: exp.totalCompensation.currency,
- value: exp.totalCompensation.value,
- },
- }
- : undefined,
+ totalCompensation: {
+ create: {
+ baseCurrency: baseCurrencyString,
+ baseValue: await convert(
+ exp.totalCompensation.value,
+ exp.totalCompensation.currency,
+ baseCurrencyString,
+ ),
+ currency: exp.totalCompensation.currency,
+ value: exp.totalCompensation.value,
+ },
+ },
},
},
},
@@ -903,7 +1180,6 @@ export const offersProfileRouter = createRouter()
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
level: exp.level,
- location: exp.location,
title: exp.title,
totalCompensation: {
create: {
@@ -926,19 +1202,67 @@ export const offersProfileRouter = createRouter()
});
}
} else if (exp.companyId) {
+ if (exp.cityId) {
+ await ctx.prisma.offersBackground.update({
+ data: {
+ experiences: {
+ create: {
+ company: {
+ connect: {
+ id: exp.companyId,
+ },
+ },
+ durationInMonths: exp.durationInMonths,
+ jobType: exp.jobType,
+ level: exp.level,
+ location: {
+ connect: {
+ id: exp.cityId
+ }
+ },
+ title: exp.title,
+ },
+ },
+ },
+ where: {
+ id: input.background.id,
+ },
+ });
+ } else {
+ await ctx.prisma.offersBackground.update({
+ data: {
+ experiences: {
+ create: {
+ company: {
+ connect: {
+ id: exp.companyId,
+ },
+ },
+ durationInMonths: exp.durationInMonths,
+ jobType: exp.jobType,
+ level: exp.level,
+ title: exp.title,
+ },
+ },
+ },
+ where: {
+ id: input.background.id,
+ },
+ });
+ }
+ } else if (exp.cityId) {
await ctx.prisma.offersBackground.update({
data: {
experiences: {
create: {
- company: {
- connect: {
- id: exp.companyId,
- },
- },
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
level: exp.level,
- location: exp.location,
+ location: {
+ connect: {
+ id: exp.cityId
+ }
+ },
title: exp.title,
},
},
@@ -955,7 +1279,6 @@ export const offersProfileRouter = createRouter()
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
level: exp.level,
- location: exp.location,
title: exp.title,
},
},
@@ -970,19 +1293,90 @@ export const offersProfileRouter = createRouter()
exp.monthlySalary?.currency != null &&
exp.monthlySalary?.value != null
) {
+ // INTERN
if (exp.companyId) {
+ if (exp.cityId) {
+ await ctx.prisma.offersBackground.update({
+ data: {
+ experiences: {
+ create: {
+ company: {
+ connect: {
+ id: exp.companyId,
+ },
+ },
+ durationInMonths: exp.durationInMonths,
+ jobType: exp.jobType,
+ location: {
+ connect: {
+ id: exp.cityId
+ }
+ },
+ monthlySalary: {
+ create: {
+ baseCurrency: baseCurrencyString,
+ baseValue: await convert(
+ exp.monthlySalary.value,
+ exp.monthlySalary.currency,
+ baseCurrencyString,
+ ),
+ currency: exp.monthlySalary.currency,
+ value: exp.monthlySalary.value,
+ },
+ },
+ title: exp.title,
+ },
+ },
+ },
+ where: {
+ id: input.background.id,
+ },
+ });
+ } else {
+ await ctx.prisma.offersBackground.update({
+ data: {
+ experiences: {
+ create: {
+ company: {
+ connect: {
+ id: exp.companyId,
+ },
+ },
+ durationInMonths: exp.durationInMonths,
+ jobType: exp.jobType,
+ monthlySalary: {
+ create: {
+ baseCurrency: baseCurrencyString,
+ baseValue: await convert(
+ exp.monthlySalary.value,
+ exp.monthlySalary.currency,
+ baseCurrencyString,
+ ),
+ currency: exp.monthlySalary.currency,
+ value: exp.monthlySalary.value,
+ },
+ },
+ title: exp.title,
+ },
+ },
+ },
+ where: {
+ id: input.background.id,
+ },
+ });
+ }
+ } else if (exp.cityId) {
await ctx.prisma.offersBackground.update({
data: {
experiences: {
create: {
- company: {
- connect: {
- id: exp.companyId,
- },
- },
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
- location: exp.location,
+ location: {
+ connect: {
+ id: exp.cityId
+ }
+ },
monthlySalary: {
create: {
baseCurrency: baseCurrencyString,
@@ -1010,7 +1404,6 @@ export const offersProfileRouter = createRouter()
create: {
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
- location: exp.location,
monthlySalary: {
create: {
baseCurrency: baseCurrencyString,
@@ -1033,18 +1426,64 @@ export const offersProfileRouter = createRouter()
});
}
} else if (exp.companyId) {
+ if (exp.cityId) {
+ await ctx.prisma.offersBackground.update({
+ data: {
+ experiences: {
+ create: {
+ company: {
+ connect: {
+ id: exp.companyId,
+ },
+ },
+ durationInMonths: exp.durationInMonths,
+ jobType: exp.jobType,
+ location: {
+ connect: {
+ id: exp.cityId,
+ }
+ },
+ title: exp.title,
+ },
+ },
+ },
+ where: {
+ id: input.background.id,
+ },
+ });
+ } else {
+ await ctx.prisma.offersBackground.update({
+ data: {
+ experiences: {
+ create: {
+ company: {
+ connect: {
+ id: exp.companyId,
+ },
+ },
+ durationInMonths: exp.durationInMonths,
+ jobType: exp.jobType,
+ title: exp.title,
+ },
+ },
+ },
+ where: {
+ id: input.background.id,
+ },
+ });
+ }
+ } else if (exp.cityId) {
await ctx.prisma.offersBackground.update({
data: {
experiences: {
create: {
- company: {
- connect: {
- id: exp.companyId,
- },
- },
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
- location: exp.location,
+ location: {
+ connect: {
+ id: exp.cityId
+ }
+ },
title: exp.title,
},
},
@@ -1060,7 +1499,6 @@ export const offersProfileRouter = createRouter()
create: {
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
- location: exp.location,
title: exp.title,
},
},
@@ -1148,12 +1586,20 @@ export const offersProfileRouter = createRouter()
await ctx.prisma.offersOffer.update({
data: {
comments: offerToUpdate.comments,
- companyId: offerToUpdate.companyId,
+ company: {
+ connect: {
+ id: offerToUpdate.companyId
+ }
+ },
jobType:
offerToUpdate.jobType === JobType.FULLTIME
? JobType.FULLTIME
: JobType.INTERN,
- location: offerToUpdate.location,
+ location: {
+ connect: {
+ id: offerToUpdate.cityId
+ }
+ },
monthYearReceived: offerToUpdate.monthYearReceived,
negotiationStrategy: offerToUpdate.negotiationStrategy,
},
@@ -1176,7 +1622,8 @@ export const offersProfileRouter = createRouter()
offerToUpdate.offersIntern.monthlySalary.currency,
baseCurrencyString,
),
- currency: offerToUpdate.offersIntern.monthlySalary.currency,
+ currency:
+ offerToUpdate.offersIntern.monthlySalary.currency,
value: offerToUpdate.offersIntern.monthlySalary.value,
},
update: {
@@ -1186,13 +1633,14 @@ export const offersProfileRouter = createRouter()
offerToUpdate.offersIntern.monthlySalary.currency,
baseCurrencyString,
),
- currency: offerToUpdate.offersIntern.monthlySalary.currency,
+ currency:
+ offerToUpdate.offersIntern.monthlySalary.currency,
value: offerToUpdate.offersIntern.monthlySalary.value,
- }
- }
+ },
+ },
},
startYear: offerToUpdate.offersIntern.startYear ?? undefined,
- title: offerToUpdate.offersIntern.title
+ title: offerToUpdate.offersIntern.title,
},
where: {
id: offerToUpdate.offersIntern.id,
@@ -1222,7 +1670,8 @@ export const offersProfileRouter = createRouter()
offerToUpdate.offersFullTime.baseSalary.currency,
baseCurrencyString,
),
- currency: offerToUpdate.offersFullTime.baseSalary.currency,
+ currency:
+ offerToUpdate.offersFullTime.baseSalary.currency,
value: offerToUpdate.offersFullTime.baseSalary.value,
},
update: {
@@ -1232,11 +1681,12 @@ export const offersProfileRouter = createRouter()
offerToUpdate.offersFullTime.baseSalary.currency,
baseCurrencyString,
),
- currency: offerToUpdate.offersFullTime.baseSalary.currency,
+ currency:
+ offerToUpdate.offersFullTime.baseSalary.currency,
value: offerToUpdate.offersFullTime.baseSalary.value,
- }
- }
- }
+ },
+ },
+ },
},
where: {
id: offerToUpdate.offersFullTime.id,
@@ -1267,9 +1717,9 @@ export const offersProfileRouter = createRouter()
),
currency: offerToUpdate.offersFullTime.bonus.currency,
value: offerToUpdate.offersFullTime.bonus.value,
- }
- }
- }
+ },
+ },
+ },
},
where: {
id: offerToUpdate.offersFullTime.id,
@@ -1288,7 +1738,8 @@ export const offersProfileRouter = createRouter()
offerToUpdate.offersFullTime.stocks.currency,
baseCurrencyString,
),
- currency: offerToUpdate.offersFullTime.stocks.currency,
+ currency:
+ offerToUpdate.offersFullTime.stocks.currency,
value: offerToUpdate.offersFullTime.stocks.value,
},
update: {
@@ -1298,11 +1749,12 @@ export const offersProfileRouter = createRouter()
offerToUpdate.offersFullTime.stocks.currency,
baseCurrencyString,
),
- currency: offerToUpdate.offersFullTime.stocks.currency,
+ currency:
+ offerToUpdate.offersFullTime.stocks.currency,
value: offerToUpdate.offersFullTime.stocks.value,
- }
- }
- }
+ },
+ },
+ },
},
where: {
id: offerToUpdate.offersFullTime.id,
@@ -1317,24 +1769,32 @@ export const offersProfileRouter = createRouter()
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.totalCompensation.value,
- offerToUpdate.offersFullTime.totalCompensation.currency,
+ offerToUpdate.offersFullTime.totalCompensation
+ .currency,
baseCurrencyString,
),
- currency: offerToUpdate.offersFullTime.totalCompensation.currency,
- value: offerToUpdate.offersFullTime.totalCompensation.value,
+ currency:
+ offerToUpdate.offersFullTime.totalCompensation
+ .currency,
+ value:
+ offerToUpdate.offersFullTime.totalCompensation.value,
},
update: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.totalCompensation.value,
- offerToUpdate.offersFullTime.totalCompensation.currency,
+ offerToUpdate.offersFullTime.totalCompensation
+ .currency,
baseCurrencyString,
),
- currency: offerToUpdate.offersFullTime.totalCompensation.currency,
- value: offerToUpdate.offersFullTime.totalCompensation.value,
- }
- }
- }
+ currency:
+ offerToUpdate.offersFullTime.totalCompensation
+ .currency,
+ value:
+ offerToUpdate.offersFullTime.totalCompensation.value,
+ },
+ },
+ },
},
where: {
id: offerToUpdate.offersFullTime.id,
@@ -1362,7 +1822,11 @@ export const offersProfileRouter = createRouter()
},
},
jobType: offerToUpdate.jobType,
- location: offerToUpdate.location,
+ location: {
+ connect: {
+ id: offerToUpdate.cityId
+ }
+ },
monthYearReceived: offerToUpdate.monthYearReceived,
negotiationStrategy: offerToUpdate.negotiationStrategy,
offersIntern: {
@@ -1416,7 +1880,11 @@ export const offersProfileRouter = createRouter()
},
},
jobType: offerToUpdate.jobType,
- location: offerToUpdate.location,
+ location: {
+ connect: {
+ id: offerToUpdate.cityId
+ }
+ },
monthYearReceived: offerToUpdate.monthYearReceived,
negotiationStrategy: offerToUpdate.negotiationStrategy,
offersFullTime: {
diff --git a/apps/portal/src/server/router/offers/offers-user-profile-router.ts b/apps/portal/src/server/router/offers/offers-user-profile-router.ts
index 48994044..ae816261 100644
--- a/apps/portal/src/server/router/offers/offers-user-profile-router.ts
+++ b/apps/portal/src/server/router/offers/offers-user-profile-router.ts
@@ -57,6 +57,15 @@ export const offersUserProfileRouter = createProtectedRouter()
offers: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
diff --git a/apps/portal/src/server/router/offers/offers.ts b/apps/portal/src/server/router/offers/offers.ts
index cac77069..515cad3f 100644
--- a/apps/portal/src/server/router/offers/offers.ts
+++ b/apps/portal/src/server/router/offers/offers.ts
@@ -40,12 +40,12 @@ const getYoeRange = (yoeCategory: number) => {
export const offersRouter = createRouter().query('list', {
input: z.object({
+ cityId: z.string(),
companyId: z.string().nullish(),
currency: z.string().nullish(),
dateEnd: z.date().nullish(),
dateStart: z.date().nullish(),
limit: z.number().positive(),
- location: z.string(),
offset: z.number().nonnegative(),
salaryMax: z.number().nonnegative().nullish(),
salaryMin: z.number().nonnegative().nullish(),
@@ -129,8 +129,7 @@ export const offersRouter = createRouter().query('list', {
where: {
AND: [
{
- location:
- input.location.length === 0 ? undefined : input.location,
+ cityId: input.cityId.length === 0 ? undefined : input.cityId,
},
{
offersIntern: {
@@ -243,8 +242,7 @@ export const offersRouter = createRouter().query('list', {
where: {
AND: [
{
- location:
- input.location.length === 0 ? undefined : input.location,
+ cityId: input.cityId.length === 0 ? undefined : input.cityId,
},
{
offersIntern: {
diff --git a/apps/portal/src/types/offers.d.ts b/apps/portal/src/types/offers.d.ts
index 2ff82a16..3dcba938 100644
--- a/apps/portal/src/types/offers.d.ts
+++ b/apps/portal/src/types/offers.d.ts
@@ -25,7 +25,7 @@ export type Experience = {
id: string;
jobType: JobType?;
level: string?;
- location: string?;
+ location: Location?;
monthlySalary: Valuation?;
title: string?;
totalCompensation: Valuation?;
@@ -79,7 +79,7 @@ export type ProfileOffer = {
company: OffersCompany;
id: string;
jobType: JobType;
- location: string;
+ location: Location;
monthYearReceived: Date;
negotiationStrategy: string;
offersFullTime: FullTime?;
@@ -163,7 +163,7 @@ export type AnalysisHighestOffer = {
company: OffersCompany;
id: string;
level: string;
- location: string;
+ location: Location;
totalYoe: number;
};
@@ -173,7 +173,7 @@ export type AnalysisOffer = {
income: Valuation;
jobType: JobType;
level: string;
- location: string;
+ location: Location;
monthYearReceived: Date;
negotiationStrategy: string;
previousCompanies: Array;
@@ -202,7 +202,17 @@ export type UserProfileOffer = {
income: Valuation;
jobType: JobType;
level: string;
- location: string;
+ location: Location;
monthYearReceived: Date;
title: string;
};
+
+export type Location = {
+ cityId: string;
+ cityName: string;
+ countryCode: string;
+ countryId: string;
+ countryName: string;
+ stateId: string;
+ stateName: string;
+};
diff --git a/apps/portal/src/utils/offers/analysisGeneration.ts b/apps/portal/src/utils/offers/analysisGeneration.ts
index 75ba4f46..a2594079 100644
--- a/apps/portal/src/utils/offers/analysisGeneration.ts
+++ b/apps/portal/src/utils/offers/analysisGeneration.ts
@@ -1,6 +1,8 @@
import type { Session } from 'next-auth';
import type {
+ City,
Company,
+ Country,
OffersBackground,
OffersCurrency,
OffersFullTime,
@@ -9,6 +11,7 @@ import type {
OffersProfile,
Prisma,
PrismaClient,
+ State,
} from '@prisma/client';
import { TRPCError } from '@trpc/server';
@@ -16,8 +19,14 @@ import { profileAnalysisDtoMapper } from '../../mappers/offers-mappers';
type Offer = OffersOffer & {
company: Company;
+ location: City & { state: State & { country: Country } };
offersFullTime:
- | (OffersFullTime & { totalCompensation: OffersCurrency })
+ | (OffersFullTime & {
+ baseSalary: OffersCurrency | null;
+ bonus: OffersCurrency | null;
+ stocks: OffersCurrency | null;
+ totalCompensation: OffersCurrency;
+ })
| null;
offersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
profile: OffersProfile & { background: OffersBackground | null };
@@ -68,6 +77,15 @@ export const generateAnalysis = async (params: {
const offers = await ctx.prisma.offersOffer.findMany({
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
baseSalary: true,
@@ -131,9 +149,18 @@ export const generateAnalysis = async (params: {
const monthYearReceived = new Date(overallHighestOffer.monthYearReceived);
monthYearReceived.setFullYear(monthYearReceived.getFullYear() - 1);
- const similarOffers = await ctx.prisma.offersOffer.findMany({
+ let similarOffers = await ctx.prisma.offersOffer.findMany({
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
@@ -151,6 +178,15 @@ export const generateAnalysis = async (params: {
experiences: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
},
},
},
@@ -225,7 +261,7 @@ export const generateAnalysis = async (params: {
const companyAnalysis = Array.from(companyMap.values()).map(
(companyOffer) => {
// TODO: Refactor calculating analysis into a function
- const similarCompanyOffers = similarOffers.filter(
+ let similarCompanyOffers = similarOffers.filter(
(offer) => offer.companyId === companyOffer.companyId,
);
@@ -239,23 +275,21 @@ export const generateAnalysis = async (params: {
: 100 - (100 * companyIndex) / (similarCompanyOffers.length - 1);
// Get top offers (excluding user's offer)
- const similarCompanyOffersWithoutUsersOffers =
- similarCompanyOffers.filter(
- (offer) => offer.profileId !== input.profileId,
- );
+ similarCompanyOffers = similarCompanyOffers.filter(
+ (offer) => offer.id !== companyOffer.id,
+ );
- const noOfSimilarCompanyOffers =
- similarCompanyOffersWithoutUsersOffers.length;
+ const noOfSimilarCompanyOffers = similarCompanyOffers.length;
const similarCompanyOffers90PercentileIndex = Math.ceil(
noOfSimilarCompanyOffers * 0.1,
);
const topPercentileCompanyOffers =
noOfSimilarCompanyOffers > 2
- ? similarCompanyOffersWithoutUsersOffers.slice(
+ ? similarCompanyOffers.slice(
similarCompanyOffers90PercentileIndex,
similarCompanyOffers90PercentileIndex + 2,
)
- : similarCompanyOffersWithoutUsersOffers;
+ : similarCompanyOffers;
return {
companyName: companyOffer.company.name,
@@ -276,19 +310,19 @@ export const generateAnalysis = async (params: {
? 100
: 100 - (100 * overallIndex) / (similarOffers.length - 1);
- const similarOffersWithoutUsersOffers = similarOffers.filter(
- (similarOffer) => similarOffer.profileId !== input.profileId,
+ similarOffers = similarOffers.filter(
+ (offer) => offer.id !== overallHighestOffer.id,
);
- const noOfSimilarOffers = similarOffersWithoutUsersOffers.length;
+ const noOfSimilarOffers = similarOffers.length;
const similarOffers90PercentileIndex = Math.ceil(noOfSimilarOffers * 0.1);
const topPercentileOffers =
noOfSimilarOffers > 2
- ? similarOffersWithoutUsersOffers.slice(
+ ? similarOffers.slice(
similarOffers90PercentileIndex,
similarOffers90PercentileIndex + 2,
)
- : similarOffersWithoutUsersOffers;
+ : similarOffers;
const analysis = await ctx.prisma.offersAnalysis.create({
data: {
@@ -335,6 +369,15 @@ export const generateAnalysis = async (params: {
topSimilarOffers: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
@@ -352,6 +395,15 @@ export const generateAnalysis = async (params: {
experiences: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
},
},
},
@@ -367,6 +419,15 @@ export const generateAnalysis = async (params: {
topSimilarOffers: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,
@@ -384,6 +445,15 @@ export const generateAnalysis = async (params: {
experiences: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
},
},
},
@@ -397,6 +467,15 @@ export const generateAnalysis = async (params: {
overallHighestOffer: {
include: {
company: true,
+ location: {
+ include: {
+ state: {
+ include: {
+ country: true,
+ },
+ },
+ },
+ },
offersFullTime: {
include: {
totalCompensation: true,