[offers][chore] Add a relative base value to the currency model in schema

pull/413/head
Bryann Yeap Kok Keong 2 years ago
parent f8d22632ec
commit 2c7f349043

@ -0,0 +1,12 @@
/*
Warnings:
- Added the required column `baseValue` to the `OffersCurrency` table without a default value. This is not possible if the table is not empty.
- Added the required column `updatedAt` to the `OffersCurrency` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "OffersCurrency" ADD COLUMN "baseCurrency" TEXT NOT NULL DEFAULT 'USD',
ADD COLUMN "baseValue" INTEGER NOT NULL,
ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL;

@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "OffersCurrency" ALTER COLUMN "value" SET DATA TYPE DOUBLE PRECISION,
ALTER COLUMN "baseValue" SET DATA TYPE DOUBLE PRECISION;

@ -205,9 +205,9 @@ model OffersBackground {
totalYoe Int
specificYoes OffersSpecificYoe[]
experiences OffersExperience[] // For extensibility in the future
experiences OffersExperience[]
educations OffersEducation[] // For extensibility in the future
educations OffersEducation[]
profile OffersProfile @relation(fields: [offersProfileId], references: [id], onDelete: Cascade)
offersProfileId String @unique
@ -251,10 +251,16 @@ model OffersExperience {
}
model OffersCurrency {
id String @id @default(cuid())
value Int
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
value Float
currency String
baseValue Float
baseCurrency String @default("USD")
// Experience
OffersExperienceTotalCompensation OffersExperience? @relation("ExperienceTotalCompensation")
OffersExperienceMonthlySalary OffersExperience? @relation("ExperienceMonthlySalary")

@ -40,7 +40,7 @@ function Test() {
deleteCommentMutation.mutate({
id: 'cl97fprun001j7iyg6ev9x983',
profileId: 'cl96stky5002ew32gx2kale2x',
token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1',
token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
userId: 'cl97dl51k001e7iygd5v5gt58',
});
};
@ -84,7 +84,7 @@ function Test() {
const handleLink = () => {
addToUserProfileMutation.mutate({
profileId: 'cl9efyn9p004ww3u42mjgl1vn',
token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba',
token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
userId: 'cl9ehvpng0000w3ec2mpx0bdd',
});
};
@ -103,11 +103,10 @@ function Test() {
],
experiences: [
{
companyId: 'cl9h0bqu50000txxwkhmshhxz',
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
durationInMonths: 24,
jobType: 'FULLTIME',
level: 'Junior',
// "monthlySalary": undefined,
specialization: 'Front End',
title: 'Software Engineer',
totalCompensation: {
@ -132,7 +131,7 @@ function Test() {
{
comments: 'I am a Raffles Institution almumni',
// Comments: '',
companyId: 'cl9h0bqu50000txxwkhmshhxz',
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
jobType: 'FULLTIME',
location: 'Singapore, Singapore',
monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
@ -161,7 +160,7 @@ function Test() {
},
{
comments: '',
companyId: 'cl9h0bqu50000txxwkhmshhxz',
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
jobType: 'FULLTIME',
location: 'Singapore, Singapore',
monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
@ -192,14 +191,14 @@ function Test() {
});
};
const profileId = 'cl9i68fv60000tthj8t3zkox0'; // Remember to change this filed after testing deleting
const profileId = 'cl9j50xzk008vutfqg6mta2ey'; // Remember to change this filed after testing deleting
const data = trpc.useQuery(
[
`offers.profile.listOne`,
{
profileId,
token:
'd14666ff76e267c9e99445844b41410e83874936d0c07e664db73ff0ea76919e',
'24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
},
],
{
@ -223,7 +222,7 @@ function Test() {
const handleDelete = (id: string) => {
deleteMutation.mutate({
profileId: id,
token: 'e7effd2a40adba2deb1ddea4fb9f1e6c3c98ab0a85a88ed1567fc2a107fdb445',
token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
});
};
@ -257,15 +256,15 @@ function Test() {
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: 'cl9h0bqug0003txxwgkac0x40',
id: 'cl9j4yawz0003utlp1uaa1t8o',
logoUrl: 'https://logo.clearbit.com/meta.com',
name: 'Meta',
slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
},
companyId: 'cl9h0bqug0003txxwgkac0x40',
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
durationInMonths: 24,
// Id: 'cl9h0bqug0003txxwgkac0x40',
// Id: 'cl9j4yawz0003utlp1uaa1t8o',
jobType: 'FULLTIME',
level: 'Junior',
monthlySalary: null,
@ -309,13 +308,13 @@ function Test() {
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: 'cl9h0bqug0003txxwgkac0x40',
id: 'cl9j4yawz0003utlp1uaa1t8o',
logoUrl: 'https://logo.clearbit.com/meta.com',
name: 'Meta',
slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
},
companyId: 'cl9h0bqug0003txxwgkac0x40',
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
id: 'cl9i68fve000ntthj5h9yvqnh',
jobType: 'FULLTIME',
location: 'Singapore, Singapore',
@ -362,13 +361,13 @@ function Test() {
// 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: 'cl9h0bqug0003txxwgkac0x40',
// id: 'cl9j4yawz0003utlp1uaa1t8o',
// logoUrl: 'https://logo.clearbit.com/meta.com',
// name: 'Meta',
// slug: 'meta',
// updatedAt: new Date('2022-10-12T16:19:05.196Z'),
// },
// companyId: 'cl9h0bqug0003txxwgkac0x40',
// companyId: 'cl9j4yawz0003utlp1uaa1t8o',
// id: 'cl9i68fvf000ytthj0ltsqt1d',
// jobType: 'FULLTIME',
// location: 'Singapore, Singapore',
@ -415,13 +414,13 @@ function Test() {
// 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: 'cl9h0bqug0003txxwgkac0x40',
// id: 'cl9j4yawz0003utlp1uaa1t8o',
// logoUrl: 'https://logo.clearbit.com/meta.com',
// name: 'Meta',
// slug: 'meta',
// updatedAt: new Date('2022-10-12T16:19:05.196Z'),
// },
// companyId: 'cl9h0bqug0003txxwgkac0x40',
// companyId: 'cl9j4yawz0003utlp1uaa1t8o',
// id: 'cl96stky9003bw32gc3l955vr',
// jobType: 'FULLTIME',
// location: 'Singapore, Singapore',
@ -468,13 +467,13 @@ function Test() {
// 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: 'cl9h0bqug0003txxwgkac0x40',
// id: 'cl9j4yawz0003utlp1uaa1t8o',
// logoUrl: 'https://logo.clearbit.com/meta.com',
// name: 'Meta',
// slug: 'meta',
// updatedAt: new Date('2022-10-12T16:19:05.196Z'),
// },
// companyId: 'cl9h0bqug0003txxwgkac0x40',
// companyId: 'cl9j4yawz0003utlp1uaa1t8o',
// id: 'cl976wf28000t7iyga4noyz7s',
// jobType: 'FULLTIME',
// location: 'Singapore, Singapore',
@ -521,13 +520,13 @@ function Test() {
// 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: 'cl9h0bqug0003txxwgkac0x40',
// id: 'cl9j4yawz0003utlp1uaa1t8o',
// logoUrl: 'https://logo.clearbit.com/meta.com',
// name: 'Meta',
// slug: 'meta',
// updatedAt: new Date('2022-10-12T16:19:05.196Z'),
// },
// companyId: 'cl9h0bqug0003txxwgkac0x40',
// companyId: 'cl9j4yawz0003utlp1uaa1t8o',
// id: 'cl96tbb3o0051w32gjrpaiiit',
// jobType: 'FULLTIME',
// location: 'Singapore, Singapore',
@ -570,7 +569,7 @@ function Test() {
// },
],
// ProfileName: 'ailing bryann stuart ziqing',
token: 'd3509cb890f0bae0a785afdd6c1c074a140706ab1d155ed338ec22dcca5c92f1',
token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
userId: null,
});
};

@ -1,5 +1,6 @@
import crypto, { randomUUID } from 'crypto';
import { z } from 'zod';
import { JobType } from '@prisma/client';
import * as trpc from '@trpc/server';
import {
@ -7,6 +8,9 @@ import {
createOfferProfileResponseMapper,
profileDtoMapper,
} from '~/mappers/offers-mappers';
import { baseCurrencyString } from '~/utils/offers/currency';
import { convert } from '~/utils/offers/currency/currency-exchange';
import { createValidationRegex } from '~/utils/offers/zodRegex';
import { createRouter } from '../context';
@ -31,7 +35,7 @@ const offer = z.object({
company: company.nullish(),
companyId: z.string(),
id: z.string().optional(),
jobType: z.string(),
jobType: z.string().regex(createValidationRegex(Object.keys(JobType), null)),
location: z.string(),
monthYearReceived: z.date(),
negotiationStrategy: z.string(),
@ -73,7 +77,10 @@ const experience = z.object({
companyId: z.string().nullish(),
durationInMonths: z.number().nullish(),
id: z.string().optional(),
jobType: z.string().nullish(),
jobType: z
.string()
.regex(createValidationRegex(Object.keys(JobType), null))
.nullish(),
level: z.string().nullish(),
location: z.string().nullish(),
monthlySalary: valuation.nullish(),
@ -94,15 +101,6 @@ const education = z.object({
type: z.string().nullish(),
});
// Const reply = z.object({
// createdAt: z.date().nullish(),
// id: z.string().optional(),
// messages: z.string().nullish(),
// profileId: z.string().nullish(),
// replyingToId: z.string().nullish(),
// userId: z.string().nullish(),
// });
export const offersProfileRouter = createRouter()
.query('listOne', {
input: z.object({
@ -282,11 +280,11 @@ export const offersProfileRouter = createRouter()
})),
},
experiences: {
create: input.background.experiences.map((x) => {
create: input.background.experiences.map(async (x) => {
if (
x.jobType === 'FULLTIME' &&
x.totalCompensation?.currency !== undefined &&
x.totalCompensation.value !== undefined
x.jobType === JobType.FULLTIME &&
x.totalCompensation?.currency != null &&
x.totalCompensation?.value != null
) {
if (x.companyId) {
return {
@ -302,8 +300,14 @@ export const offersProfileRouter = createRouter()
title: x.title,
totalCompensation: {
create: {
currency: x.totalCompensation?.currency,
value: x.totalCompensation?.value,
baseCurrency: baseCurrencyString,
baseValue: await convert(
x.totalCompensation.value,
x.totalCompensation.currency,
baseCurrencyString,
),
currency: x.totalCompensation.currency,
value: x.totalCompensation.value,
},
},
};
@ -312,20 +316,27 @@ export const offersProfileRouter = createRouter()
durationInMonths: x.durationInMonths,
jobType: x.jobType,
level: x.level,
location: x.location,
specialization: x.specialization,
title: x.title,
totalCompensation: {
create: {
currency: x.totalCompensation?.currency,
value: x.totalCompensation?.value,
baseCurrency: baseCurrencyString,
baseValue: await convert(
x.totalCompensation.value,
x.totalCompensation.currency,
baseCurrencyString,
),
currency: x.totalCompensation.currency,
value: x.totalCompensation.value,
},
},
};
}
if (
x.jobType === 'INTERN' &&
x.monthlySalary?.currency !== undefined &&
x.monthlySalary.value !== undefined
x.jobType === JobType.INTERN &&
x.monthlySalary?.currency != null &&
x.monthlySalary?.value != null
) {
if (x.companyId) {
return {
@ -338,8 +349,14 @@ export const offersProfileRouter = createRouter()
jobType: x.jobType,
monthlySalary: {
create: {
currency: x.monthlySalary?.currency,
value: x.monthlySalary?.value,
baseCurrency: baseCurrencyString,
baseValue: await convert(
x.monthlySalary.value,
x.monthlySalary.currency,
baseCurrencyString,
),
currency: x.monthlySalary.currency,
value: x.monthlySalary.value,
},
},
specialization: x.specialization,
@ -351,8 +368,14 @@ export const offersProfileRouter = createRouter()
jobType: x.jobType,
monthlySalary: {
create: {
currency: x.monthlySalary?.currency,
value: x.monthlySalary?.value,
baseCurrency: baseCurrencyString,
baseValue: await convert(
x.monthlySalary.value,
x.monthlySalary.currency,
baseCurrencyString,
),
currency: x.monthlySalary.currency,
value: x.monthlySalary.value,
},
},
specialization: x.specialization,
@ -379,107 +402,141 @@ export const offersProfileRouter = createRouter()
},
editToken: token,
offers: {
create: input.offers.map((x) => {
if (
x.jobType === 'INTERN' &&
x.offersIntern &&
x.offersIntern.internshipCycle &&
x.offersIntern.monthlySalary?.currency &&
x.offersIntern.monthlySalary.value &&
x.offersIntern.startYear
) {
return {
comments: x.comments,
company: {
connect: {
id: x.companyId,
create: await Promise.all(
input.offers.map(async (x) => {
if (
x.jobType === JobType.INTERN &&
x.offersIntern &&
x.offersIntern.internshipCycle != null &&
x.offersIntern.monthlySalary?.currency != null &&
x.offersIntern.monthlySalary?.value != null &&
x.offersIntern.startYear != null
) {
return {
comments: x.comments,
company: {
connect: {
id: x.companyId,
},
},
},
jobType: x.jobType,
location: x.location,
monthYearReceived: x.monthYearReceived,
negotiationStrategy: x.negotiationStrategy,
offersIntern: {
create: {
internshipCycle: x.offersIntern.internshipCycle,
monthlySalary: {
create: {
currency: x.offersIntern.monthlySalary?.currency,
value: x.offersIntern.monthlySalary?.value,
jobType: x.jobType,
location: x.location,
monthYearReceived: x.monthYearReceived,
negotiationStrategy: x.negotiationStrategy,
offersIntern: {
create: {
internshipCycle: x.offersIntern.internshipCycle,
monthlySalary: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
x.offersIntern.monthlySalary.value,
x.offersIntern.monthlySalary.currency,
baseCurrencyString,
),
currency: x.offersIntern.monthlySalary.currency,
value: x.offersIntern.monthlySalary.value,
},
},
specialization: x.offersIntern.specialization,
startYear: x.offersIntern.startYear,
title: x.offersIntern.title,
},
specialization: x.offersIntern.specialization,
startYear: x.offersIntern.startYear,
title: x.offersIntern.title,
},
},
};
}
if (
x.jobType === 'FULLTIME' &&
x.offersFullTime &&
x.offersFullTime.baseSalary?.currency &&
x.offersFullTime.baseSalary?.value &&
x.offersFullTime.bonus?.currency &&
x.offersFullTime.bonus?.value &&
x.offersFullTime.stocks?.currency &&
x.offersFullTime.stocks?.value &&
x.offersFullTime.totalCompensation?.currency &&
x.offersFullTime.totalCompensation?.value &&
x.offersFullTime.level
) {
return {
comments: x.comments,
company: {
connect: {
id: x.companyId,
};
}
if (
x.jobType === JobType.FULLTIME &&
x.offersFullTime &&
x.offersFullTime.baseSalary?.currency != null &&
x.offersFullTime.baseSalary?.value != null &&
x.offersFullTime.bonus?.currency != null &&
x.offersFullTime.bonus?.value != null &&
x.offersFullTime.stocks?.currency != null &&
x.offersFullTime.stocks?.value != null &&
x.offersFullTime.totalCompensation?.currency != null &&
x.offersFullTime.totalCompensation?.value != null &&
x.offersFullTime.level != null &&
x.offersFullTime.title != null &&
x.offersFullTime.specialization != null
) {
return {
comments: x.comments,
company: {
connect: {
id: x.companyId,
},
},
},
jobType: x.jobType,
location: x.location,
monthYearReceived: x.monthYearReceived,
negotiationStrategy: x.negotiationStrategy,
offersFullTime: {
create: {
baseSalary: {
create: {
currency: x.offersFullTime.baseSalary?.currency,
value: x.offersFullTime.baseSalary?.value,
jobType: x.jobType,
location: x.location,
monthYearReceived: x.monthYearReceived,
negotiationStrategy: x.negotiationStrategy,
offersFullTime: {
create: {
baseSalary: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
x.offersFullTime.baseSalary.value,
x.offersFullTime.baseSalary.currency,
baseCurrencyString,
),
currency: x.offersFullTime.baseSalary.currency,
value: x.offersFullTime.baseSalary.value,
},
},
},
bonus: {
create: {
currency: x.offersFullTime.bonus?.currency,
value: x.offersFullTime.bonus?.value,
bonus: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
x.offersFullTime.bonus.value,
x.offersFullTime.bonus.currency,
baseCurrencyString,
),
currency: x.offersFullTime.bonus.currency,
value: x.offersFullTime.bonus.value,
},
},
},
level: x.offersFullTime.level,
specialization: x.offersFullTime.specialization,
stocks: {
create: {
currency: x.offersFullTime.stocks?.currency,
value: x.offersFullTime.stocks?.value,
level: x.offersFullTime.level,
specialization: x.offersFullTime.specialization,
stocks: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
x.offersFullTime.stocks.value,
x.offersFullTime.stocks.currency,
baseCurrencyString,
),
currency: x.offersFullTime.stocks.currency,
value: x.offersFullTime.stocks.value,
},
},
},
title: x.offersFullTime.title,
totalCompensation: {
create: {
currency:
x.offersFullTime.totalCompensation?.currency,
value: x.offersFullTime.totalCompensation?.value,
title: x.offersFullTime.title,
totalCompensation: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
x.offersFullTime.totalCompensation.value,
x.offersFullTime.totalCompensation.currency,
baseCurrencyString,
),
currency:
x.offersFullTime.totalCompensation.currency,
value: x.offersFullTime.totalCompensation.value,
},
},
},
},
},
};
}
};
}
// Throw error
throw new trpc.TRPCError({
code: 'BAD_REQUEST',
message: 'Missing fields.',
});
}),
// Throw error
throw new trpc.TRPCError({
code: 'BAD_REQUEST',
message: 'Missing fields.',
});
}),
),
},
profileName: randomUUID().substring(0, 10),
},
@ -510,7 +567,7 @@ export const offersProfileRouter = createRouter()
return deletedProfile.id;
}
// TODO: Throw 401
throw new trpc.TRPCError({
code: 'UNAUTHORIZED',
message: 'Invalid token.',
@ -535,7 +592,6 @@ export const offersProfileRouter = createRouter()
totalYoe: z.number(),
}),
createdAt: z.string().optional(),
// Discussion: z.array(reply),
id: z.string(),
isEditable: z.boolean().nullish(),
offers: z.array(offer),
@ -573,19 +629,21 @@ export const offersProfileRouter = createRouter()
});
// Delete educations
const educationsId = (await ctx.prisma.offersEducation.findMany({
where: {
backgroundId: input.background.id
}
})).map((x) => x.id)
const educationsId = (
await ctx.prisma.offersEducation.findMany({
where: {
backgroundId: input.background.id,
},
})
).map((x) => x.id);
for (const id of educationsId) {
if (!input.background.educations.map((x) => x.id).includes(id)) {
await ctx.prisma.offersEducation.delete({
where: {
id
}
})
id,
},
});
}
}
@ -626,19 +684,21 @@ export const offersProfileRouter = createRouter()
}
// Delete experiences
const experiencesId = (await ctx.prisma.offersExperience.findMany({
where: {
backgroundId: input.background.id
}
})).map((x) => x.id)
const experiencesId = (
await ctx.prisma.offersExperience.findMany({
where: {
backgroundId: input.background.id,
},
})
).map((x) => x.id);
for (const id of experiencesId) {
if (!input.background.experiences.map((x) => x.id).includes(id)) {
await ctx.prisma.offersExperience.delete({
where: {
id
}
})
id,
},
});
}
}
@ -660,6 +720,12 @@ export const offersProfileRouter = createRouter()
if (exp.monthlySalary) {
await ctx.prisma.offersCurrency.update({
data: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
exp.monthlySalary.value,
exp.monthlySalary.currency,
baseCurrencyString,
),
currency: exp.monthlySalary.currency,
value: exp.monthlySalary.value,
},
@ -672,6 +738,12 @@ export const offersProfileRouter = createRouter()
if (exp.totalCompensation) {
await ctx.prisma.offersCurrency.update({
data: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
exp.totalCompensation.value,
exp.totalCompensation.currency,
baseCurrencyString,
),
currency: exp.totalCompensation.currency,
value: exp.totalCompensation.value,
},
@ -683,9 +755,9 @@ export const offersProfileRouter = createRouter()
} else if (!exp.id) {
// Create new experience
if (
exp.jobType === 'FULLTIME' &&
exp.totalCompensation?.currency !== undefined &&
exp.totalCompensation.value !== undefined
exp.jobType === JobType.FULLTIME &&
exp.totalCompensation?.currency != null &&
exp.totalCompensation?.value != null
) {
if (exp.companyId) {
await ctx.prisma.offersBackground.update({
@ -700,12 +772,19 @@ export const offersProfileRouter = createRouter()
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
level: exp.level,
location: exp.location,
specialization: exp.specialization,
title: exp.title,
totalCompensation: {
create: {
currency: exp.totalCompensation?.currency,
value: exp.totalCompensation?.value,
baseCurrency: baseCurrencyString,
baseValue: await convert(
exp.totalCompensation.value,
exp.totalCompensation.currency,
baseCurrencyString,
),
currency: exp.totalCompensation.currency,
value: exp.totalCompensation.value,
},
},
},
@ -723,12 +802,19 @@ export const offersProfileRouter = createRouter()
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
level: exp.level,
location: exp.location,
specialization: exp.specialization,
title: exp.title,
totalCompensation: {
create: {
currency: exp.totalCompensation?.currency,
value: exp.totalCompensation?.value,
baseCurrency: baseCurrencyString,
baseValue: await convert(
exp.totalCompensation.value,
exp.totalCompensation.currency,
baseCurrencyString,
),
currency: exp.totalCompensation.currency,
value: exp.totalCompensation.value,
},
},
},
@ -740,9 +826,9 @@ export const offersProfileRouter = createRouter()
});
}
} else if (
exp.jobType === 'INTERN' &&
exp.monthlySalary?.currency !== undefined &&
exp.monthlySalary.value !== undefined
exp.jobType === JobType.INTERN &&
exp.monthlySalary?.currency != null &&
exp.monthlySalary?.value != null
) {
if (exp.companyId) {
await ctx.prisma.offersBackground.update({
@ -756,10 +842,17 @@ export const offersProfileRouter = createRouter()
},
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
location: exp.location,
monthlySalary: {
create: {
currency: exp.monthlySalary?.currency,
value: exp.monthlySalary?.value,
baseCurrency: baseCurrencyString,
baseValue: await convert(
exp.monthlySalary.value,
exp.monthlySalary.currency,
baseCurrencyString,
),
currency: exp.monthlySalary.currency,
value: exp.monthlySalary.value,
},
},
specialization: exp.specialization,
@ -778,10 +871,17 @@ export const offersProfileRouter = createRouter()
create: {
durationInMonths: exp.durationInMonths,
jobType: exp.jobType,
location: exp.location,
monthlySalary: {
create: {
currency: exp.monthlySalary?.currency,
value: exp.monthlySalary?.value,
baseCurrency: baseCurrencyString,
baseValue: await convert(
exp.monthlySalary.value,
exp.monthlySalary.currency,
baseCurrencyString,
),
currency: exp.monthlySalary.currency,
value: exp.monthlySalary.value,
},
},
specialization: exp.specialization,
@ -799,19 +899,21 @@ export const offersProfileRouter = createRouter()
}
// Delete specific yoes
const yoesId = (await ctx.prisma.offersSpecificYoe.findMany({
where: {
backgroundId: input.background.id
}
})).map((x) => x.id)
const yoesId = (
await ctx.prisma.offersSpecificYoe.findMany({
where: {
backgroundId: input.background.id,
},
})
).map((x) => x.id);
for (const id of yoesId) {
if (!input.background.specificYoes.map((x) => x.id).includes(id)) {
await ctx.prisma.offersSpecificYoe.delete({
where: {
id
}
})
id,
},
});
}
}
@ -845,19 +947,21 @@ export const offersProfileRouter = createRouter()
}
// Delete specific offers
const offers = (await ctx.prisma.offersOffer.findMany({
where: {
profileId: input.id
}
})).map((x) => x.id)
const offers = (
await ctx.prisma.offersOffer.findMany({
where: {
profileId: input.id,
},
})
).map((x) => x.id);
for (const id of offers) {
if (!input.offers.map((x) => x.id).includes(id)) {
await ctx.prisma.offersOffer.delete({
where: {
id
}
})
id,
},
});
}
}
@ -869,6 +973,10 @@ export const offersProfileRouter = createRouter()
data: {
comments: offerToUpdate.comments,
companyId: offerToUpdate.companyId,
jobType:
offerToUpdate.jobType === JobType.FULLTIME
? JobType.FULLTIME
: JobType.INTERN,
location: offerToUpdate.location,
monthYearReceived: offerToUpdate.monthYearReceived,
negotiationStrategy: offerToUpdate.negotiationStrategy,
@ -878,21 +986,7 @@ export const offersProfileRouter = createRouter()
},
});
if (
offerToUpdate.jobType === 'INTERN' ||
offerToUpdate.jobType === 'FULLTIME'
) {
await ctx.prisma.offersOffer.update({
data: {
jobType: offerToUpdate.jobType,
},
where: {
id: offerToUpdate.id,
},
});
}
if (offerToUpdate.offersIntern?.monthlySalary) {
if (offerToUpdate.offersIntern?.monthlySalary != null) {
await ctx.prisma.offersIntern.update({
data: {
internshipCycle:
@ -907,6 +1001,12 @@ export const offersProfileRouter = createRouter()
});
await ctx.prisma.offersCurrency.update({
data: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersIntern.monthlySalary.value,
offerToUpdate.offersIntern.monthlySalary.currency,
baseCurrencyString,
),
currency: offerToUpdate.offersIntern.monthlySalary.currency,
value: offerToUpdate.offersIntern.monthlySalary.value,
},
@ -916,7 +1016,7 @@ export const offersProfileRouter = createRouter()
});
}
if (offerToUpdate.offersFullTime?.totalCompensation) {
if (offerToUpdate.offersFullTime?.totalCompensation != null) {
await ctx.prisma.offersFullTime.update({
data: {
level: offerToUpdate.offersFullTime.level ?? undefined,
@ -927,9 +1027,15 @@ export const offersProfileRouter = createRouter()
id: offerToUpdate.offersFullTime.id,
},
});
if (offerToUpdate.offersFullTime.baseSalary) {
if (offerToUpdate.offersFullTime.baseSalary != null) {
await ctx.prisma.offersCurrency.update({
data: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.baseSalary.value,
offerToUpdate.offersFullTime.baseSalary.currency,
baseCurrencyString,
),
currency: offerToUpdate.offersFullTime.baseSalary.currency,
value: offerToUpdate.offersFullTime.baseSalary.value,
},
@ -941,6 +1047,12 @@ export const offersProfileRouter = createRouter()
if (offerToUpdate.offersFullTime.bonus) {
await ctx.prisma.offersCurrency.update({
data: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.bonus.value,
offerToUpdate.offersFullTime.bonus.currency,
baseCurrencyString,
),
currency: offerToUpdate.offersFullTime.bonus.currency,
value: offerToUpdate.offersFullTime.bonus.value,
},
@ -952,6 +1064,12 @@ export const offersProfileRouter = createRouter()
if (offerToUpdate.offersFullTime.stocks) {
await ctx.prisma.offersCurrency.update({
data: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.stocks.value,
offerToUpdate.offersFullTime.stocks.currency,
baseCurrencyString,
),
currency: offerToUpdate.offersFullTime.stocks.currency,
value: offerToUpdate.offersFullTime.stocks.value,
},
@ -962,6 +1080,12 @@ export const offersProfileRouter = createRouter()
}
await ctx.prisma.offersCurrency.update({
data: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.totalCompensation.value,
offerToUpdate.offersFullTime.totalCompensation.currency,
baseCurrencyString,
),
currency:
offerToUpdate.offersFullTime.totalCompensation.currency,
value: offerToUpdate.offersFullTime.totalCompensation.value,
@ -974,12 +1098,12 @@ export const offersProfileRouter = createRouter()
} else {
// Create new offer
if (
offerToUpdate.jobType === 'INTERN' &&
offerToUpdate.jobType === JobType.INTERN &&
offerToUpdate.offersIntern &&
offerToUpdate.offersIntern.internshipCycle &&
offerToUpdate.offersIntern.monthlySalary?.currency &&
offerToUpdate.offersIntern.monthlySalary.value &&
offerToUpdate.offersIntern.startYear
offerToUpdate.offersIntern.internshipCycle != null &&
offerToUpdate.offersIntern.monthlySalary?.currency != null &&
offerToUpdate.offersIntern.monthlySalary?.value != null &&
offerToUpdate.offersIntern.startYear != null
) {
await ctx.prisma.offersProfile.update({
data: {
@ -1001,11 +1125,18 @@ export const offersProfileRouter = createRouter()
offerToUpdate.offersIntern.internshipCycle,
monthlySalary: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersIntern.monthlySalary.value,
offerToUpdate.offersIntern.monthlySalary
.currency,
baseCurrencyString,
),
currency:
offerToUpdate.offersIntern.monthlySalary
?.currency,
.currency,
value:
offerToUpdate.offersIntern.monthlySalary?.value,
offerToUpdate.offersIntern.monthlySalary.value,
},
},
specialization:
@ -1023,17 +1154,18 @@ export const offersProfileRouter = createRouter()
});
}
if (
offerToUpdate.jobType === 'FULLTIME' &&
offerToUpdate.jobType === JobType.FULLTIME &&
offerToUpdate.offersFullTime &&
offerToUpdate.offersFullTime.baseSalary?.currency &&
offerToUpdate.offersFullTime.baseSalary?.value &&
offerToUpdate.offersFullTime.bonus?.currency &&
offerToUpdate.offersFullTime.bonus?.value &&
offerToUpdate.offersFullTime.stocks?.currency &&
offerToUpdate.offersFullTime.stocks?.value &&
offerToUpdate.offersFullTime.totalCompensation?.currency &&
offerToUpdate.offersFullTime.totalCompensation?.value &&
offerToUpdate.offersFullTime.level
offerToUpdate.offersFullTime.baseSalary?.currency != null &&
offerToUpdate.offersFullTime.baseSalary?.value != null &&
offerToUpdate.offersFullTime.bonus?.currency != null &&
offerToUpdate.offersFullTime.bonus?.value != null &&
offerToUpdate.offersFullTime.stocks?.currency != null &&
offerToUpdate.offersFullTime.stocks?.value != null &&
offerToUpdate.offersFullTime.totalCompensation?.currency !=
null &&
offerToUpdate.offersFullTime.totalCompensation?.value != null &&
offerToUpdate.offersFullTime.level != null
) {
await ctx.prisma.offersProfile.update({
data: {
@ -1053,18 +1185,31 @@ export const offersProfileRouter = createRouter()
create: {
baseSalary: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.baseSalary.value,
offerToUpdate.offersFullTime.baseSalary
.currency,
baseCurrencyString,
),
currency:
offerToUpdate.offersFullTime.baseSalary
?.currency,
.currency,
value:
offerToUpdate.offersFullTime.baseSalary?.value,
offerToUpdate.offersFullTime.baseSalary.value,
},
},
bonus: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.bonus.value,
offerToUpdate.offersFullTime.bonus.currency,
baseCurrencyString,
),
currency:
offerToUpdate.offersFullTime.bonus?.currency,
value: offerToUpdate.offersFullTime.bonus?.value,
offerToUpdate.offersFullTime.bonus.currency,
value: offerToUpdate.offersFullTime.bonus.value,
},
},
level: offerToUpdate.offersFullTime.level,
@ -1072,20 +1217,34 @@ export const offersProfileRouter = createRouter()
offerToUpdate.offersFullTime.specialization,
stocks: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.stocks.value,
offerToUpdate.offersFullTime.stocks.currency,
baseCurrencyString,
),
currency:
offerToUpdate.offersFullTime.stocks?.currency,
value: offerToUpdate.offersFullTime.stocks?.value,
offerToUpdate.offersFullTime.stocks.currency,
value: offerToUpdate.offersFullTime.stocks.value,
},
},
title: offerToUpdate.offersFullTime.title,
totalCompensation: {
create: {
baseCurrency: baseCurrencyString,
baseValue: await convert(
offerToUpdate.offersFullTime.totalCompensation
.value,
offerToUpdate.offersFullTime.totalCompensation
.currency,
baseCurrencyString,
),
currency:
offerToUpdate.offersFullTime.totalCompensation
?.currency,
.currency,
value:
offerToUpdate.offersFullTime.totalCompensation
?.value,
.value,
},
},
},
@ -1102,46 +1261,6 @@ export const offersProfileRouter = createRouter()
}
const result = await ctx.prisma.offersProfile.findFirst({
include: {
background: {
include: {
educations: true,
experiences: {
include: {
company: true,
monthlySalary: true,
totalCompensation: true,
},
},
specificYoes: true,
},
},
discussion: {
include: {
replies: true,
replyingTo: true,
user: true,
},
},
offers: {
include: {
company: true,
offersFullTime: {
include: {
baseSalary: true,
bonus: true,
stocks: true,
totalCompensation: true,
},
},
offersIntern: {
include: {
monthlySalary: true,
},
},
},
},
},
where: {
id: input.id,
},

@ -7,6 +7,7 @@ import {
} from '~/mappers/offers-mappers';
import { convert } from '~/utils/offers/currency/currency-exchange';
import { Currency } from '~/utils/offers/currency/CurrencyEnum';
import { createValidationRegex } from '~/utils/offers/zodRegex';
import { createRouter } from '../context';
@ -23,14 +24,6 @@ const sortingKeysMap = {
totalYoe: 'totalYoe',
};
const createSortByValidationRegex = () => {
const startsWithPlusOrMinusOnly = '^[+-]{1}';
const sortingKeysRegex = Object.entries(sortingKeysMap)
.map((entry) => entry[0])
.join('|');
return new RegExp(startsWithPlusOrMinusOnly + '(' + sortingKeysRegex + ')');
};
const yoeCategoryMap: Record<number, string> = {
0: 'Internship',
1: 'Fresh Grad',
@ -59,7 +52,10 @@ export const offersRouter = createRouter().query('list', {
offset: z.number().nonnegative(),
salaryMax: z.number().nonnegative().nullish(),
salaryMin: z.number().nonnegative().nullish(),
sortBy: z.string().regex(createSortByValidationRegex()).nullish(),
sortBy: z
.string()
.regex(createValidationRegex(Object.keys(sortingKeysMap), '[+-]{1}'))
.nullish(),
title: z.string().nullish(),
yoeCategory: z.number().min(0).max(3),
yoeMax: z.number().max(100).nullish(),
@ -70,8 +66,6 @@ export const offersRouter = createRouter().query('list', {
const yoeMin = input.yoeMin ? input.yoeMin : yoeRange?.minYoe;
const yoeMax = input.yoeMax ? input.yoeMax : yoeRange?.maxYoe;
// Const orderBy = getSortingOrderAndKey(input.sortBy, input.yoeCategory);
if (!input.sortBy) {
input.sortBy = '-' + sortingKeysMap.monthYearReceived;
}
@ -338,112 +332,6 @@ export const offersRouter = createRouter().query('list', {
);
}
// SORTING
// data = data.sort((offer1, offer2) => {
// const defaultReturn =
// offer2.monthYearReceived.getTime() - offer1.monthYearReceived.getTime();
// if (!input.sortBy) {
// return defaultReturn;
// }
// const order = input.sortBy.charAt(0);
// const sortingKey = input.sortBy.substring(1);
// if (order === ascOrder) {
// return (() => {
// if (sortingKey === 'monthYearReceived') {
// return (
// offer1.monthYearReceived.getTime() -
// offer2.monthYearReceived.getTime()
// );
// }
// if (sortingKey === 'totalCompensation') {
// const salary1 = offer1.offersFullTime?.totalCompensation.value
// ? offer1.offersFullTime?.totalCompensation.value
// : offer1.offersIntern?.monthlySalary.value;
// const salary2 = offer2.offersFullTime?.totalCompensation.value
// ? offer2.offersFullTime?.totalCompensation.value
// : offer2.offersIntern?.monthlySalary.value;
// if (salary1 == null || salary2 == null) {
// throw new TRPCError({
// code: 'NOT_FOUND',
// message: 'Total Compensation or Salary not found',
// });
// }
// return salary1 - salary2;
// }
// if (sortingKey === 'totalYoe') {
// const yoe1 = offer1.profile.background?.totalYoe;
// const yoe2 = offer2.profile.background?.totalYoe;
// if (yoe1 == null || yoe2 == null) {
// throw new TRPCError({
// code: 'NOT_FOUND',
// message: 'Total years of experience not found',
// });
// }
// return yoe1 - yoe2;
// }
// return defaultReturn;
// })();
// }
// if (order === descOrder) {
// return (() => {
// if (sortingKey === 'monthYearReceived') {
// return (
// offer2.monthYearReceived.getTime() -
// offer1.monthYearReceived.getTime()
// );
// }
// if (sortingKey === 'totalCompensation') {
// const salary1 = offer1.offersFullTime?.totalCompensation.value
// ? offer1.offersFullTime?.totalCompensation.value
// : offer1.offersIntern?.monthlySalary.value;
// const salary2 = offer2.offersFullTime?.totalCompensation.value
// ? offer2.offersFullTime?.totalCompensation.value
// : offer2.offersIntern?.monthlySalary.value;
// if (salary1 == null || salary2 == null) {
// throw new TRPCError({
// code: 'NOT_FOUND',
// message: 'Total Compensation or Salary not found',
// });
// }
// return salary2 - salary1;
// }
// if (sortingKey === 'totalYoe') {
// const yoe1 = offer1.profile.background?.totalYoe;
// const yoe2 = offer2.profile.background?.totalYoe;
// if (yoe1 == null || yoe2 == null) {
// throw new TRPCError({
// code: 'NOT_FOUND',
// message: 'Total years of experience not found',
// });
// }
// return yoe2 - yoe1;
// }
// return defaultReturn;
// })();
// }
// return defaultReturn;
// });
const startRecordIndex: number = input.limit * input.offset;
const endRecordIndex: number =
startRecordIndex + input.limit <= data.length

@ -6,7 +6,11 @@ export const convert = async (
) => {
fromCurrency = fromCurrency.trim().toLowerCase();
toCurrency = toCurrency.trim().toLowerCase();
const url = ['https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies', fromCurrency, toCurrency].join('/');
const url = [
'https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies',
fromCurrency,
toCurrency,
].join('/');
return await fetch(url + '.json')
.then((res) => res.json())

@ -1,5 +1,9 @@
import type { Money } from '~/components/offers/types';
import { Currency } from './CurrencyEnum';
export const baseCurrencyString = Currency.USD.toString();
export function convertMoneyToString({ currency, value }: Money) {
if (!value) {
return '-';

@ -0,0 +1,8 @@
export const createValidationRegex = (
keywordArray: Array<string>,
prepend: string | null | undefined,
) => {
const sortingKeysRegex = keywordArray.join('|');
prepend = prepend != null ? prepend : '';
return new RegExp('^' + prepend + '(' + sortingKeysRegex + ')$');
};
Loading…
Cancel
Save