[offers][fix] Fix analysis and offers API to accommodate new fields in OffersCurrency

pull/413/head
Bryann Yeap Kok Keong 2 years ago
parent bb97c4dea6
commit be594c7513

@ -56,7 +56,7 @@ const analysisOfferDtoMapper = (
location: offer.location, location: offer.location,
monthYearReceived: offer.monthYearReceived, monthYearReceived: offer.monthYearReceived,
negotiationStrategy: offer.negotiationStrategy, negotiationStrategy: offer.negotiationStrategy,
previousCompanies: [], previousCompanies: [], // TODO: Fill this up
profileName, profileName,
specialization: specialization:
offer.jobType === JobType.FULLTIME offer.jobType === JobType.FULLTIME
@ -74,10 +74,18 @@ const analysisOfferDtoMapper = (
offer.offersFullTime.totalCompensation.value; offer.offersFullTime.totalCompensation.value;
analysisOfferDto.income.currency = analysisOfferDto.income.currency =
offer.offersFullTime.totalCompensation.currency; offer.offersFullTime.totalCompensation.currency;
analysisOfferDto.income.baseValue =
offer.offersFullTime.totalCompensation.baseValue;
analysisOfferDto.income.baseCurrency =
offer.offersFullTime.totalCompensation.baseCurrency;
} else if (offer.offersIntern?.monthlySalary) { } else if (offer.offersIntern?.monthlySalary) {
analysisOfferDto.income.value = offer.offersIntern.monthlySalary.value; analysisOfferDto.income.value = offer.offersIntern.monthlySalary.value;
analysisOfferDto.income.currency = analysisOfferDto.income.currency =
offer.offersIntern.monthlySalary.currency; offer.offersIntern.monthlySalary.currency;
analysisOfferDto.income.baseValue =
offer.offersIntern.monthlySalary.baseValue;
analysisOfferDto.income.baseCurrency =
offer.offersIntern.monthlySalary.baseCurrency;
} else { } else {
throw new TRPCError({ throw new TRPCError({
code: 'NOT_FOUND', code: 'NOT_FOUND',

@ -8,7 +8,7 @@ function GenerateAnalysis() {
return ( return (
<div> <div>
{JSON.stringify( {JSON.stringify(
analysisMutation.mutate({ profileId: 'cl9h23fb1002ftxysli5iziu2' }), analysisMutation.mutate({ profileId: 'cl9j50xzk008vutfqg6mta2ey' }),
)} )}
</div> </div>
); );

@ -5,7 +5,7 @@ import { trpc } from '~/utils/trpc';
function GetAnalysis() { function GetAnalysis() {
const analysis = trpc.useQuery([ const analysis = trpc.useQuery([
'offers.analysis.get', 'offers.analysis.get',
{ profileId: 'cl9h23fb1002ftxysli5iziu2' }, { profileId: 'cl9j50xzk008vutfqg6mta2ey' },
]); ]);
return <div>{JSON.stringify(analysis.data)}</div>; return <div>{JSON.stringify(analysis.data)}</div>;

@ -6,6 +6,7 @@ function Test() {
const data = trpc.useQuery([ const data = trpc.useQuery([
'offers.list', 'offers.list',
{ {
currency: 'SGD',
limit: 100, limit: 100,
location: 'Singapore, Singapore', location: 'Singapore, Singapore',
offset: 0, offset: 0,

@ -187,14 +187,14 @@ export const offersAnalysisRouter = createRouter()
{ {
offersFullTime: { offersFullTime: {
totalCompensation: { totalCompensation: {
value: 'desc', baseValue: 'desc',
}, },
}, },
}, },
{ {
offersIntern: { offersIntern: {
monthlySalary: { monthlySalary: {
value: 'desc', baseValue: 'desc',
}, },
}, },
}, },
@ -216,11 +216,11 @@ export const offersAnalysisRouter = createRouter()
// TODO: Shift yoe out of background to make it mandatory // TODO: Shift yoe out of background to make it mandatory
if ( if (
!overallHighestOffer.profile.background || !overallHighestOffer.profile.background ||
overallHighestOffer.profile.background.totalYoe === undefined overallHighestOffer.profile.background.totalYoe == null
) { ) {
throw new TRPCError({ throw new TRPCError({
code: 'BAD_REQUEST', code: 'NOT_FOUND',
message: 'Cannot analyse without YOE', message: 'YOE not found',
}); });
} }
@ -257,14 +257,14 @@ export const offersAnalysisRouter = createRouter()
{ {
offersFullTime: { offersFullTime: {
totalCompensation: { totalCompensation: {
value: 'desc', baseValue: 'desc',
}, },
}, },
}, },
{ {
offersIntern: { offersIntern: {
monthlySalary: { monthlySalary: {
value: 'desc', baseValue: 'desc',
}, },
}, },
}, },
@ -279,12 +279,10 @@ export const offersAnalysisRouter = createRouter()
{ {
offersFullTime: { offersFullTime: {
level: overallHighestOffer.offersFullTime?.level, level: overallHighestOffer.offersFullTime?.level,
specialization: title: overallHighestOffer.offersFullTime?.title,
overallHighestOffer.offersFullTime?.specialization,
}, },
offersIntern: { offersIntern: {
specialization: title: overallHighestOffer.offersIntern?.title,
overallHighestOffer.offersIntern?.specialization,
}, },
}, },
], ],
@ -317,7 +315,7 @@ export const offersAnalysisRouter = createRouter()
similarOffers, similarOffers,
); );
const overallPercentile = const overallPercentile =
similarOffers.length === 0 ? 0 : overallIndex / similarOffers.length; similarOffers.length === 0 ? 1.0 : overallIndex / similarOffers.length;
const companyIndex = searchOfferPercentile( const companyIndex = searchOfferPercentile(
overallHighestOffer, overallHighestOffer,
@ -325,10 +323,11 @@ export const offersAnalysisRouter = createRouter()
); );
const companyPercentile = const companyPercentile =
similarCompanyOffers.length === 0 similarCompanyOffers.length === 0
? 0 ? 1.0
: companyIndex / similarCompanyOffers.length; : companyIndex / similarCompanyOffers.length;
// FIND TOP >=90 PERCENTILE OFFERS // FIND TOP >=90 PERCENTILE OFFERS, DOESN'T GIVE 100th PERCENTILE
// e.g. If there only 4 offers, it gives the 2nd and 3rd offer
similarOffers = similarOffers.filter( similarOffers = similarOffers.filter(
(offer) => offer.id !== overallHighestOffer.id, (offer) => offer.id !== overallHighestOffer.id,
); );
@ -337,10 +336,9 @@ export const offersAnalysisRouter = createRouter()
); );
const noOfSimilarOffers = similarOffers.length; const noOfSimilarOffers = similarOffers.length;
const similarOffers90PercentileIndex = const similarOffers90PercentileIndex = Math.ceil(noOfSimilarOffers * 0.1);
Math.floor(noOfSimilarOffers * 0.9) - 1;
const topPercentileOffers = const topPercentileOffers =
noOfSimilarOffers > 1 noOfSimilarOffers > 2
? similarOffers.slice( ? similarOffers.slice(
similarOffers90PercentileIndex, similarOffers90PercentileIndex,
similarOffers90PercentileIndex + 2, similarOffers90PercentileIndex + 2,
@ -348,10 +346,11 @@ export const offersAnalysisRouter = createRouter()
: similarOffers; : similarOffers;
const noOfSimilarCompanyOffers = similarCompanyOffers.length; const noOfSimilarCompanyOffers = similarCompanyOffers.length;
const similarCompanyOffers90PercentileIndex = const similarCompanyOffers90PercentileIndex = Math.ceil(
Math.floor(noOfSimilarCompanyOffers * 0.9) - 1; noOfSimilarCompanyOffers * 0.1,
);
const topPercentileCompanyOffers = const topPercentileCompanyOffers =
noOfSimilarCompanyOffers > 1 noOfSimilarCompanyOffers > 2
? similarCompanyOffers.slice( ? similarCompanyOffers.slice(
similarCompanyOffers90PercentileIndex, similarCompanyOffers90PercentileIndex,
similarCompanyOffers90PercentileIndex + 2, similarCompanyOffers90PercentileIndex + 2,

@ -5,7 +5,7 @@ import {
dashboardOfferDtoMapper, dashboardOfferDtoMapper,
getOffersResponseMapper, getOffersResponseMapper,
} from '~/mappers/offers-mappers'; } from '~/mappers/offers-mappers';
import { convert } from '~/utils/offers/currency/currency-exchange'; import { convertWithDate } from '~/utils/offers/currency/currency-exchange';
import { Currency } from '~/utils/offers/currency/CurrencyEnum'; import { Currency } from '~/utils/offers/currency/CurrencyEnum';
import { createValidationRegex } from '~/utils/offers/zodRegex'; import { createValidationRegex } from '~/utils/offers/zodRegex';
@ -106,7 +106,7 @@ export const offersRouter = createRouter().query('list', {
? { ? {
offersIntern: { offersIntern: {
monthlySalary: { monthlySalary: {
value: order, baseValue: order,
}, },
}, },
} }
@ -141,7 +141,7 @@ export const offersRouter = createRouter().query('list', {
{ {
offersIntern: { offersIntern: {
monthlySalary: { monthlySalary: {
value: { baseValue: {
gte: input.salaryMin ?? undefined, gte: input.salaryMin ?? undefined,
lte: input.salaryMax ?? undefined, lte: input.salaryMax ?? undefined,
}, },
@ -210,7 +210,7 @@ export const offersRouter = createRouter().query('list', {
? { ? {
offersFullTime: { offersFullTime: {
totalCompensation: { totalCompensation: {
value: order, baseValue: order,
}, },
}, },
} }
@ -250,7 +250,7 @@ export const offersRouter = createRouter().query('list', {
{ {
offersFullTime: { offersFullTime: {
totalCompensation: { totalCompensation: {
value: { baseValue: {
gte: input.salaryMin ?? undefined, gte: input.salaryMin ?? undefined,
lte: input.salaryMax ?? undefined, lte: input.salaryMax ?? undefined,
}, },
@ -288,36 +288,42 @@ export const offersRouter = createRouter().query('list', {
if (currency != null && currency in Currency) { if (currency != null && currency in Currency) {
data = await Promise.all( data = await Promise.all(
data.map(async (offer) => { data.map(async (offer) => {
if (offer.offersFullTime?.totalCompensation) { if (offer.offersFullTime?.totalCompensation != null) {
offer.offersFullTime.totalCompensation.value = await convert( offer.offersFullTime.totalCompensation.value =
offer.offersFullTime.totalCompensation.value, await convertWithDate(
offer.offersFullTime.totalCompensation.currency, offer.offersFullTime.totalCompensation.value,
currency, offer.offersFullTime.totalCompensation.currency,
); currency,
offer.offersFullTime.totalCompensation.updatedAt,
);
offer.offersFullTime.totalCompensation.currency = currency; offer.offersFullTime.totalCompensation.currency = currency;
offer.offersFullTime.baseSalary.value = await convert( offer.offersFullTime.baseSalary.value = await convertWithDate(
offer.offersFullTime.totalCompensation.value, offer.offersFullTime.baseSalary.value,
offer.offersFullTime.totalCompensation.currency, offer.offersFullTime.baseSalary.currency,
currency, currency,
offer.offersFullTime.baseSalary.updatedAt,
); );
offer.offersFullTime.baseSalary.currency = currency; offer.offersFullTime.baseSalary.currency = currency;
offer.offersFullTime.stocks.value = await convert( offer.offersFullTime.stocks.value = await convertWithDate(
offer.offersFullTime.totalCompensation.value, offer.offersFullTime.stocks.value,
offer.offersFullTime.totalCompensation.currency, offer.offersFullTime.stocks.currency,
currency, currency,
offer.offersFullTime.stocks.updatedAt,
); );
offer.offersFullTime.stocks.currency = currency; offer.offersFullTime.stocks.currency = currency;
offer.offersFullTime.bonus.value = await convert( offer.offersFullTime.bonus.value = await convertWithDate(
offer.offersFullTime.totalCompensation.value, offer.offersFullTime.bonus.value,
offer.offersFullTime.totalCompensation.currency, offer.offersFullTime.bonus.currency,
currency, currency,
offer.offersFullTime.bonus.updatedAt,
); );
offer.offersFullTime.bonus.currency = currency; offer.offersFullTime.bonus.currency = currency;
} else if (offer.offersIntern?.monthlySalary) { } else if (offer.offersIntern?.monthlySalary != null) {
offer.offersIntern.monthlySalary.value = await convert( offer.offersIntern.monthlySalary.value = await convertWithDate(
offer.offersIntern.monthlySalary.value, offer.offersIntern.monthlySalary.value,
offer.offersIntern.monthlySalary.currency, offer.offersIntern.monthlySalary.currency,
currency, currency,
offer.offersIntern.monthlySalary.updatedAt,
); );
offer.offersIntern.monthlySalary.currency = currency; offer.offersIntern.monthlySalary.currency = currency;
} else { } else {

@ -1,4 +1,5 @@
// API from https://github.com/fawazahmed0/currency-api#readme // API from https://github.com/fawazahmed0/currency-api#readme
export const convert = async ( export const convert = async (
value: number, value: number,
fromCurrency: string, fromCurrency: string,
@ -16,3 +17,33 @@ export const convert = async (
.then((res) => res.json()) .then((res) => res.json())
.then((data) => value * data[toCurrency]); .then((data) => value * data[toCurrency]);
}; };
// https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@{apiVersion}/{date}/{endpoint}
export const convertWithDate = async (
value: number,
fromCurrency: string,
toCurrency: string,
date: Date,
) => {
if (new Date().toDateString === date.toDateString) {
return await convert(value, fromCurrency, toCurrency);
}
fromCurrency = fromCurrency.trim().toLowerCase();
toCurrency = toCurrency.trim().toLowerCase();
// Format date to YYYY-MM-DD
const formattedDate = date.toJSON().substring(0, 10);
const url = [
'https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1',
formattedDate,
'currencies',
fromCurrency,
toCurrency,
].join('/');
return await fetch(url + '.json')
.then((res) => res.json())
.then((data) => value * data[toCurrency]);
};

Loading…
Cancel
Save