mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-28 12:43:12 +08:00
[offers][feat] Add get offers analysis API
This commit is contained in:
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
|
|
||||||
import { trpc } from '~/utils/trpc';
|
import { trpc } from '~/utils/trpc';
|
||||||
|
|
||||||
function profileAnalysis() {
|
function GenerateAnalysis() {
|
||||||
const analysis = trpc.useQuery([
|
const analysis = trpc.useQuery([
|
||||||
'offers.analysis.generate',
|
'offers.analysis.generate',
|
||||||
{ profileId: 'cl98yxuei002htx1s8lrmwzmy' },
|
{ profileId: 'cl98yxuei002htx1s8lrmwzmy' },
|
||||||
@ -11,4 +11,4 @@ function profileAnalysis() {
|
|||||||
return <div>{JSON.stringify(analysis.data)}</div>;
|
return <div>{JSON.stringify(analysis.data)}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default profileAnalysis;
|
export default GenerateAnalysis;
|
14
apps/portal/src/pages/offers/test/getAnalysis.tsx
Normal file
14
apps/portal/src/pages/offers/test/getAnalysis.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { trpc } from '~/utils/trpc';
|
||||||
|
|
||||||
|
function GetAnalysis() {
|
||||||
|
const analysis = trpc.useQuery([
|
||||||
|
'offers.analysis.get',
|
||||||
|
{ profileId: 'cl98yxuei002htx1s8lrmwzmy' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return <div>{JSON.stringify(analysis.data)}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GetAnalysis;
|
@ -121,12 +121,7 @@ const specificAnalysisDtoMapper = (
|
|||||||
const highestOfferDtoMapper = (
|
const highestOfferDtoMapper = (
|
||||||
offer: OffersOffer & {
|
offer: OffersOffer & {
|
||||||
OffersFullTime:
|
OffersFullTime:
|
||||||
| (OffersFullTime & {
|
| (OffersFullTime & { totalCompensation: OffersCurrency })
|
||||||
baseSalary: OffersCurrency;
|
|
||||||
bonus: OffersCurrency;
|
|
||||||
stocks: OffersCurrency;
|
|
||||||
totalCompensation: OffersCurrency;
|
|
||||||
})
|
|
||||||
| null;
|
| null;
|
||||||
OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
|
OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
|
||||||
company: Company;
|
company: Company;
|
||||||
@ -146,279 +141,344 @@ const highestOfferDtoMapper = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const offersAnalysisRouter = createRouter().query('generate', {
|
const profileAnalysisDtoMapper = (
|
||||||
input: z.object({
|
analysisId: string,
|
||||||
profileId: z.string(),
|
profileId: string,
|
||||||
}),
|
overallHighestOffer: OffersOffer & {
|
||||||
async resolve({ ctx, input }) {
|
OffersFullTime:
|
||||||
await ctx.prisma.offersAnalysis.deleteMany({
|
| (OffersFullTime & { totalCompensation: OffersCurrency })
|
||||||
where: {
|
| null;
|
||||||
profileId: input.profileId,
|
OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
|
||||||
},
|
company: Company;
|
||||||
});
|
profile: OffersProfile & { background: OffersBackground | null };
|
||||||
|
},
|
||||||
|
noOfSimilarOffers: number,
|
||||||
|
overallPercentile: number,
|
||||||
|
topPercentileOffers: Array<any>,
|
||||||
|
noOfSimilarCompanyOffers: number,
|
||||||
|
companyPercentile: number,
|
||||||
|
topPercentileCompanyOffers: Array<any>,
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
companyAnalysis: specificAnalysisDtoMapper(
|
||||||
|
noOfSimilarCompanyOffers,
|
||||||
|
companyPercentile,
|
||||||
|
topPercentileCompanyOffers,
|
||||||
|
),
|
||||||
|
id: analysisId,
|
||||||
|
overallAnalysis: specificAnalysisDtoMapper(
|
||||||
|
noOfSimilarOffers,
|
||||||
|
overallPercentile,
|
||||||
|
topPercentileOffers,
|
||||||
|
),
|
||||||
|
overallHighestOffer: highestOfferDtoMapper(overallHighestOffer),
|
||||||
|
profileId,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const offers = await ctx.prisma.offersOffer.findMany({
|
export const offersAnalysisRouter = createRouter()
|
||||||
include: {
|
.query('generate', {
|
||||||
OffersFullTime: {
|
input: z.object({
|
||||||
include: {
|
profileId: z.string(),
|
||||||
baseSalary: true,
|
}),
|
||||||
bonus: true,
|
async resolve({ ctx, input }) {
|
||||||
stocks: true,
|
await ctx.prisma.offersAnalysis.deleteMany({
|
||||||
totalCompensation: true,
|
where: {
|
||||||
},
|
profileId: input.profileId,
|
||||||
},
|
},
|
||||||
OffersIntern: {
|
});
|
||||||
include: {
|
|
||||||
monthlySalary: true,
|
const offers = await ctx.prisma.offersOffer.findMany({
|
||||||
},
|
include: {
|
||||||
},
|
|
||||||
company: true,
|
|
||||||
profile: {
|
|
||||||
include: {
|
|
||||||
background: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: [
|
|
||||||
{
|
|
||||||
OffersFullTime: {
|
OffersFullTime: {
|
||||||
totalCompensation: {
|
include: {
|
||||||
value: 'desc',
|
baseSalary: true,
|
||||||
|
bonus: true,
|
||||||
|
stocks: true,
|
||||||
|
totalCompensation: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
{
|
|
||||||
OffersIntern: {
|
OffersIntern: {
|
||||||
monthlySalary: {
|
include: {
|
||||||
value: 'desc',
|
monthlySalary: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
company: true,
|
||||||
|
profile: {
|
||||||
|
include: {
|
||||||
|
background: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
orderBy: [
|
||||||
where: {
|
{
|
||||||
profileId: input.profileId,
|
OffersFullTime: {
|
||||||
},
|
totalCompensation: {
|
||||||
});
|
value: 'desc',
|
||||||
|
|
||||||
if (!offers || offers.length === 0) {
|
|
||||||
throw new TRPCError({
|
|
||||||
code: 'NOT_FOUND',
|
|
||||||
message: 'No offers found on this profile',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const overallHighestOffer = offers[0];
|
|
||||||
|
|
||||||
// TODO: Shift yoe to background to make it mandatory
|
|
||||||
if (
|
|
||||||
!overallHighestOffer.profile.background ||
|
|
||||||
!overallHighestOffer.profile.background.totalYoe
|
|
||||||
) {
|
|
||||||
throw new TRPCError({
|
|
||||||
code: 'BAD_REQUEST',
|
|
||||||
message: 'Cannot analyse without YOE',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const yoe = overallHighestOffer.profile.background.totalYoe as number;
|
|
||||||
|
|
||||||
let similarOffers = await ctx.prisma.offersOffer.findMany({
|
|
||||||
include: {
|
|
||||||
OffersFullTime: {
|
|
||||||
include: {
|
|
||||||
totalCompensation: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
OffersIntern: {
|
|
||||||
include: {
|
|
||||||
monthlySalary: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
company: true,
|
|
||||||
profile: {
|
|
||||||
include: {
|
|
||||||
background: {
|
|
||||||
include: {
|
|
||||||
experiences: {
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: [
|
|
||||||
{
|
|
||||||
OffersFullTime: {
|
|
||||||
totalCompensation: {
|
|
||||||
value: 'desc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
OffersIntern: {
|
|
||||||
monthlySalary: {
|
|
||||||
value: 'desc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
where: {
|
|
||||||
AND: [
|
|
||||||
{
|
{
|
||||||
location: overallHighestOffer.location,
|
OffersIntern: {
|
||||||
},
|
monthlySalary: {
|
||||||
{
|
value: 'desc',
|
||||||
OR: [
|
|
||||||
{
|
|
||||||
OffersFullTime: {
|
|
||||||
level: overallHighestOffer.OffersFullTime?.level,
|
|
||||||
specialization:
|
|
||||||
overallHighestOffer.OffersFullTime?.specialization,
|
|
||||||
},
|
|
||||||
OffersIntern: {
|
|
||||||
specialization:
|
|
||||||
overallHighestOffer.OffersIntern?.specialization,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
profile: {
|
|
||||||
background: {
|
|
||||||
AND: [
|
|
||||||
{
|
|
||||||
totalYoe: {
|
|
||||||
gte: Math.max(yoe - 1, 0),
|
|
||||||
lte: yoe + 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
where: {
|
||||||
});
|
profileId: input.profileId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
let similarCompanyOffers = similarOffers.filter(
|
if (!offers || offers.length === 0) {
|
||||||
(offer: { companyId: string }) =>
|
throw new TRPCError({
|
||||||
offer.companyId === overallHighestOffer.companyId,
|
code: 'NOT_FOUND',
|
||||||
);
|
message: 'No offers found on this profile',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// CALCULATE PERCENTILES
|
const overallHighestOffer = offers[0];
|
||||||
const overallIndex = binarySearchOfferPercentile(
|
|
||||||
overallHighestOffer,
|
|
||||||
similarOffers,
|
|
||||||
);
|
|
||||||
const overallPercentile = overallIndex / similarOffers.length;
|
|
||||||
|
|
||||||
const companyIndex = binarySearchOfferPercentile(
|
// TODO: Shift yoe to background to make it mandatory
|
||||||
overallHighestOffer,
|
if (
|
||||||
similarCompanyOffers,
|
!overallHighestOffer.profile.background ||
|
||||||
);
|
!overallHighestOffer.profile.background.totalYoe
|
||||||
const companyPercentile = companyIndex / similarCompanyOffers.length;
|
) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: 'BAD_REQUEST',
|
||||||
|
message: 'Cannot analyse without YOE',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// FIND TOP >=90 PERCENTILE OFFERS
|
const yoe = overallHighestOffer.profile.background.totalYoe as number;
|
||||||
similarOffers = similarOffers.filter(
|
|
||||||
(offer: { id: string }) => offer.id !== overallHighestOffer.id,
|
|
||||||
);
|
|
||||||
similarCompanyOffers = similarCompanyOffers.filter(
|
|
||||||
(offer: { id: string }) => offer.id !== overallHighestOffer.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
const noOfSimilarOffers = similarOffers.length;
|
let similarOffers = await ctx.prisma.offersOffer.findMany({
|
||||||
const similarOffers90PercentileIndex =
|
include: {
|
||||||
Math.floor(noOfSimilarOffers * 0.9) - 1;
|
OffersFullTime: {
|
||||||
const topPercentileOffers =
|
include: {
|
||||||
noOfSimilarOffers > 1
|
totalCompensation: true,
|
||||||
? similarOffers.slice(
|
},
|
||||||
similarOffers90PercentileIndex,
|
},
|
||||||
similarOffers90PercentileIndex + 2,
|
OffersIntern: {
|
||||||
)
|
include: {
|
||||||
: similarOffers;
|
monthlySalary: true,
|
||||||
|
},
|
||||||
const noOfSimilarCompanyOffers = similarCompanyOffers.length;
|
},
|
||||||
const similarCompanyOffers90PercentileIndex =
|
company: true,
|
||||||
Math.floor(noOfSimilarCompanyOffers * 0.9) - 1;
|
profile: {
|
||||||
const topPercentileCompanyOffers =
|
include: {
|
||||||
noOfSimilarCompanyOffers > 1
|
background: {
|
||||||
? similarCompanyOffers.slice(
|
include: {
|
||||||
similarCompanyOffers90PercentileIndex,
|
experiences: {
|
||||||
similarCompanyOffers90PercentileIndex + 2,
|
include: {
|
||||||
)
|
company: true,
|
||||||
: similarCompanyOffers;
|
},
|
||||||
|
},
|
||||||
const analysis = await ctx.prisma.offersAnalysis.create({
|
},
|
||||||
data: {
|
},
|
||||||
companyPercentile,
|
},
|
||||||
noOfSimilarCompanyOffers,
|
|
||||||
noOfSimilarOffers,
|
|
||||||
overallHighestOffer: {
|
|
||||||
connect: {
|
|
||||||
id: overallHighestOffer.id,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
overallPercentile,
|
orderBy: [
|
||||||
profile: {
|
{
|
||||||
connect: {
|
|
||||||
id: input.profileId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
topCompanyOffers: {
|
|
||||||
connect: topPercentileCompanyOffers.map((offer) => {
|
|
||||||
return { id: offer.id };
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
topOverallOffers: {
|
|
||||||
connect: topPercentileOffers.map((offer) => {
|
|
||||||
return { id: offer.id };
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
overallHighestOffer: {
|
|
||||||
include: {
|
|
||||||
OffersFullTime: {
|
OffersFullTime: {
|
||||||
include: {
|
totalCompensation: {
|
||||||
totalCompensation: true,
|
value: 'desc',
|
||||||
},
|
|
||||||
},
|
|
||||||
OffersIntern: {
|
|
||||||
include: {
|
|
||||||
monthlySalary: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
company: true,
|
|
||||||
profile: {
|
|
||||||
include: {
|
|
||||||
background: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
topCompanyOffers: {
|
|
||||||
include: {
|
|
||||||
OffersFullTime: {
|
|
||||||
include: {
|
|
||||||
totalCompensation: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
OffersIntern: {
|
OffersIntern: {
|
||||||
include: {
|
monthlySalary: {
|
||||||
monthlySalary: true,
|
value: 'desc',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
company: true,
|
},
|
||||||
profile: {
|
],
|
||||||
include: {
|
where: {
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
location: overallHighestOffer.location,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
OR: [
|
||||||
|
{
|
||||||
|
OffersFullTime: {
|
||||||
|
level: overallHighestOffer.OffersFullTime?.level,
|
||||||
|
specialization:
|
||||||
|
overallHighestOffer.OffersFullTime?.specialization,
|
||||||
|
},
|
||||||
|
OffersIntern: {
|
||||||
|
specialization:
|
||||||
|
overallHighestOffer.OffersIntern?.specialization,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
profile: {
|
||||||
background: {
|
background: {
|
||||||
include: {
|
AND: [
|
||||||
experiences: {
|
{
|
||||||
include: {
|
totalYoe: {
|
||||||
company: true,
|
gte: Math.max(yoe - 1, 0),
|
||||||
|
lte: yoe + 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let similarCompanyOffers = similarOffers.filter(
|
||||||
|
(offer: { companyId: string }) =>
|
||||||
|
offer.companyId === overallHighestOffer.companyId,
|
||||||
|
);
|
||||||
|
|
||||||
|
// CALCULATE PERCENTILES
|
||||||
|
const overallIndex = binarySearchOfferPercentile(
|
||||||
|
overallHighestOffer,
|
||||||
|
similarOffers,
|
||||||
|
);
|
||||||
|
const overallPercentile = overallIndex / similarOffers.length;
|
||||||
|
|
||||||
|
const companyIndex = binarySearchOfferPercentile(
|
||||||
|
overallHighestOffer,
|
||||||
|
similarCompanyOffers,
|
||||||
|
);
|
||||||
|
const companyPercentile = companyIndex / similarCompanyOffers.length;
|
||||||
|
|
||||||
|
// FIND TOP >=90 PERCENTILE OFFERS
|
||||||
|
similarOffers = similarOffers.filter(
|
||||||
|
(offer: { id: string }) => offer.id !== overallHighestOffer.id,
|
||||||
|
);
|
||||||
|
similarCompanyOffers = similarCompanyOffers.filter(
|
||||||
|
(offer: { id: string }) => offer.id !== overallHighestOffer.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
const noOfSimilarOffers = similarOffers.length;
|
||||||
|
const similarOffers90PercentileIndex =
|
||||||
|
Math.floor(noOfSimilarOffers * 0.9) - 1;
|
||||||
|
const topPercentileOffers =
|
||||||
|
noOfSimilarOffers > 1
|
||||||
|
? similarOffers.slice(
|
||||||
|
similarOffers90PercentileIndex,
|
||||||
|
similarOffers90PercentileIndex + 2,
|
||||||
|
)
|
||||||
|
: similarOffers;
|
||||||
|
|
||||||
|
const noOfSimilarCompanyOffers = similarCompanyOffers.length;
|
||||||
|
const similarCompanyOffers90PercentileIndex =
|
||||||
|
Math.floor(noOfSimilarCompanyOffers * 0.9) - 1;
|
||||||
|
const topPercentileCompanyOffers =
|
||||||
|
noOfSimilarCompanyOffers > 1
|
||||||
|
? similarCompanyOffers.slice(
|
||||||
|
similarCompanyOffers90PercentileIndex,
|
||||||
|
similarCompanyOffers90PercentileIndex + 2,
|
||||||
|
)
|
||||||
|
: similarCompanyOffers;
|
||||||
|
|
||||||
|
const analysis = await ctx.prisma.offersAnalysis.create({
|
||||||
|
data: {
|
||||||
|
companyPercentile,
|
||||||
|
noOfSimilarCompanyOffers,
|
||||||
|
noOfSimilarOffers,
|
||||||
|
overallHighestOffer: {
|
||||||
|
connect: {
|
||||||
|
id: overallHighestOffer.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
overallPercentile,
|
||||||
|
profile: {
|
||||||
|
connect: {
|
||||||
|
id: input.profileId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
topCompanyOffers: {
|
||||||
|
connect: topPercentileCompanyOffers.map((offer) => {
|
||||||
|
return { id: offer.id };
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
topOverallOffers: {
|
||||||
|
connect: topPercentileOffers.map((offer) => {
|
||||||
|
return { id: offer.id };
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -427,51 +487,127 @@ export const offersAnalysisRouter = createRouter().query('generate', {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
topOverallOffers: {
|
});
|
||||||
include: {
|
|
||||||
OffersFullTime: {
|
|
||||||
include: {
|
|
||||||
totalCompensation: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
OffersIntern: {
|
|
||||||
include: {
|
|
||||||
monthlySalary: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
company: true,
|
|
||||||
profile: {
|
|
||||||
include: {
|
|
||||||
background: {
|
|
||||||
include: {
|
|
||||||
experiences: {
|
|
||||||
include: {
|
|
||||||
company: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return profileAnalysisDtoMapper(
|
||||||
companyAnalysis: specificAnalysisDtoMapper(
|
analysis.id,
|
||||||
noOfSimilarCompanyOffers,
|
analysis.profileId,
|
||||||
companyPercentile,
|
overallHighestOffer,
|
||||||
topPercentileCompanyOffers,
|
|
||||||
),
|
|
||||||
id: analysis.id,
|
|
||||||
overallAnalysis: specificAnalysisDtoMapper(
|
|
||||||
noOfSimilarOffers,
|
noOfSimilarOffers,
|
||||||
overallPercentile,
|
overallPercentile,
|
||||||
topPercentileOffers,
|
topPercentileOffers,
|
||||||
),
|
noOfSimilarCompanyOffers,
|
||||||
overallHighestOffer: highestOfferDtoMapper(overallHighestOffer),
|
companyPercentile,
|
||||||
profileId: analysis.profileId,
|
topPercentileCompanyOffers,
|
||||||
};
|
);
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
.query('get', {
|
||||||
|
input: z.object({
|
||||||
|
profileId: z.string(),
|
||||||
|
}),
|
||||||
|
async resolve({ ctx, input }) {
|
||||||
|
const analysis = await ctx.prisma.offersAnalysis.findFirst({
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
profileId: input.profileId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!analysis) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: 'NOT_FOUND',
|
||||||
|
message: 'No analysis found on this profile',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return profileAnalysisDtoMapper(
|
||||||
|
analysis.id,
|
||||||
|
analysis.profileId,
|
||||||
|
analysis.overallHighestOffer,
|
||||||
|
analysis.noOfSimilarOffers,
|
||||||
|
analysis.overallPercentile,
|
||||||
|
analysis.topOverallOffers,
|
||||||
|
analysis.noOfSimilarCompanyOffers,
|
||||||
|
analysis.companyPercentile,
|
||||||
|
analysis.topCompanyOffers,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Reference in New Issue
Block a user