[offers][feat] Create Offer Analysis API

pull/379/head
BryannYeap 3 years ago
parent 7b51ee7e88
commit b7e0d8ff90

@ -1,105 +1,105 @@
// Refer to the Prisma schema docs: https://pris.ly/d/prisma-schema // Refer to the Prisma schema docs: https://pris.ly/d/prisma-schema
generator client { generator client {
provider = "prisma-client-js" provider = "prisma-client-js"
} }
datasource db { datasource db {
provider = "postgresql" provider = "postgresql"
url = env("DATABASE_URL") url = env("DATABASE_URL")
} }
// Necessary for NextAuth. // Necessary for NextAuth.
model Account { model Account {
id String @id @default(cuid()) id String @id @default(cuid())
userId String userId String
type String type String
provider String provider String
providerAccountId String providerAccountId String
refresh_token String? @db.Text refresh_token String? @db.Text
access_token String? @db.Text access_token String? @db.Text
expires_at Int? expires_at Int?
token_type String? token_type String?
scope String? scope String?
id_token String? @db.Text id_token String? @db.Text
session_state String? session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId]) @@unique([provider, providerAccountId])
} }
model Session { model Session {
id String @id @default(cuid()) id String @id @default(cuid())
sessionToken String @unique sessionToken String @unique
userId String userId String
expires DateTime expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade)
} }
model User { model User {
id String @id @default(cuid()) id String @id @default(cuid())
name String? name String?
email String? @unique email String? @unique
emailVerified DateTime? emailVerified DateTime?
image String? image String?
accounts Account[] accounts Account[]
sessions Session[] sessions Session[]
todos Todo[] todos Todo[]
resumesResumes ResumesResume[] resumesResumes ResumesResume[]
resumesStars ResumesStar[] resumesStars ResumesStar[]
resumesComments ResumesComment[] resumesComments ResumesComment[]
resumesCommentVotes ResumesCommentVote[] resumesCommentVotes ResumesCommentVote[]
questionsQuestions QuestionsQuestion[] questionsQuestions QuestionsQuestion[]
questionsQuestionEncounters QuestionsQuestionEncounter[] questionsQuestionEncounters QuestionsQuestionEncounter[]
questionsQuestionVotes QuestionsQuestionVote[] questionsQuestionVotes QuestionsQuestionVote[]
questionsQuestionComments QuestionsQuestionComment[] questionsQuestionComments QuestionsQuestionComment[]
questionsQuestionCommentVotes QuestionsQuestionCommentVote[] questionsQuestionCommentVotes QuestionsQuestionCommentVote[]
questionsAnswers QuestionsAnswer[] questionsAnswers QuestionsAnswer[]
questionsAnswerVotes QuestionsAnswerVote[] questionsAnswerVotes QuestionsAnswerVote[]
questionsAnswerComments QuestionsAnswerComment[] questionsAnswerComments QuestionsAnswerComment[]
questionsAnswerCommentVotes QuestionsAnswerCommentVote[] questionsAnswerCommentVotes QuestionsAnswerCommentVote[]
OffersProfile OffersProfile[] OffersProfile OffersProfile[]
offersDiscussion OffersReply[] offersDiscussion OffersReply[]
} }
enum Vote { enum Vote {
UPVOTE UPVOTE
DOWNVOTE DOWNVOTE
} }
model VerificationToken { model VerificationToken {
identifier String identifier String
token String @unique token String @unique
expires DateTime expires DateTime
@@unique([identifier, token]) @@unique([identifier, token])
} }
model Todo { model Todo {
id String @id @default(cuid()) id String @id @default(cuid())
userId String userId String
text String @db.Text text String @db.Text
status TodoStatus @default(INCOMPLETE) status TodoStatus @default(INCOMPLETE)
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade)
} }
enum TodoStatus { enum TodoStatus {
INCOMPLETE INCOMPLETE
COMPLETE COMPLETE
} }
model Company { model Company {
id String @id @default(cuid()) id String @id @default(cuid())
name String @db.Text name String @db.Text
slug String @unique slug String @unique
description String? @db.Text description String? @db.Text
logoUrl String? logoUrl String?
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
OffersExperience OffersExperience[] OffersExperience OffersExperience[]
OffersOffer OffersOffer[] OffersOffer OffersOffer[]
} }
// Start of Resumes project models. // Start of Resumes project models.
@ -107,65 +107,65 @@ model Company {
// use camelCase for field names, and try to name them consistently // use camelCase for field names, and try to name them consistently
// across all models in this file. // across all models in this file.
model ResumesResume { model ResumesResume {
id String @id @default(cuid()) id String @id @default(cuid())
userId String userId String
title String @db.Text title String @db.Text
// TODO: Update role, experience, location to use Enums // TODO: Update role, experience, location to use Enums
role String @db.Text role String @db.Text
experience String @db.Text experience String @db.Text
location String @db.Text location String @db.Text
url String url String
additionalInfo String? @db.Text additionalInfo String? @db.Text
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade)
stars ResumesStar[] stars ResumesStar[]
comments ResumesComment[] comments ResumesComment[]
} }
model ResumesStar { model ResumesStar {
id String @id @default(cuid()) id String @id @default(cuid())
userId String userId String
resumeId String resumeId String
createdAt DateTime @default(now()) createdAt DateTime @default(now())
resume ResumesResume @relation(fields: [resumeId], references: [id], onDelete: Cascade) resume ResumesResume @relation(fields: [resumeId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, resumeId]) @@unique([userId, resumeId])
} }
model ResumesComment { model ResumesComment {
id String @id @default(cuid()) id String @id @default(cuid())
userId String userId String
resumeId String resumeId String
description String @db.Text description String @db.Text
section ResumesSection section ResumesSection
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
resume ResumesResume @relation(fields: [resumeId], references: [id], onDelete: Cascade) resume ResumesResume @relation(fields: [resumeId], references: [id], onDelete: Cascade)
votes ResumesCommentVote[] votes ResumesCommentVote[]
user User @relation(fields: [userId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade)
} }
enum ResumesSection { enum ResumesSection {
GENERAL GENERAL
EDUCATION EDUCATION
EXPERIENCE EXPERIENCE
PROJECTS PROJECTS
SKILLS SKILLS
} }
model ResumesCommentVote { model ResumesCommentVote {
id String @id @default(cuid()) id String @id @default(cuid())
userId String userId String
commentId String commentId String
value Vote value Vote
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
comment ResumesComment @relation(fields: [commentId], references: [id], onDelete: Cascade) comment ResumesComment @relation(fields: [commentId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, commentId]) @@unique([userId, commentId])
} }
// End of Resumes project models. // End of Resumes project models.
@ -176,176 +176,176 @@ model ResumesCommentVote {
// across all models in this file. // across all models in this file.
model OffersProfile { model OffersProfile {
id String @id @default(cuid()) id String @id @default(cuid())
profileName String @unique profileName String @unique
createdAt DateTime @default(now()) createdAt DateTime @default(now())
background OffersBackground? background OffersBackground?
editToken String editToken String
discussion OffersReply[] discussion OffersReply[]
offers OffersOffer[] offers OffersOffer[]
user User? @relation(fields: [userId], references: [id]) user User? @relation(fields: [userId], references: [id])
userId String? userId String?
} }
model OffersBackground { model OffersBackground {
id String @id @default(cuid()) id String @id @default(cuid())
totalYoe Int? totalYoe Int?
specificYoes OffersSpecificYoe[] specificYoes OffersSpecificYoe[]
experiences OffersExperience[] // For extensibility in the future experiences OffersExperience[] // For extensibility in the future
educations OffersEducation[] // For extensibility in the future educations OffersEducation[] // For extensibility in the future
profile OffersProfile @relation(fields: [offersProfileId], references: [id], onDelete: Cascade) profile OffersProfile @relation(fields: [offersProfileId], references: [id], onDelete: Cascade)
offersProfileId String @unique offersProfileId String @unique
} }
model OffersSpecificYoe { model OffersSpecificYoe {
id String @id @default(cuid()) id String @id @default(cuid())
yoe Int yoe Int
domain String domain String
background OffersBackground @relation(fields: [backgroundId], references: [id], onDelete: Cascade) background OffersBackground @relation(fields: [backgroundId], references: [id], onDelete: Cascade)
backgroundId String backgroundId String
} }
model OffersExperience { model OffersExperience {
id String @id @default(cuid()) id String @id @default(cuid())
company Company? @relation(fields: [companyId], references: [id]) company Company? @relation(fields: [companyId], references: [id])
companyId String? companyId String?
jobType JobType? jobType JobType?
title String? title String?
// Add more fields // Add more fields
durationInMonths Int? durationInMonths Int?
specialization String? specialization String?
// FULLTIME fields // FULLTIME fields
level String? level String?
totalCompensation OffersCurrency? @relation("ExperienceTotalCompensation", fields: [totalCompensationId], references: [id]) totalCompensation OffersCurrency? @relation("ExperienceTotalCompensation", fields: [totalCompensationId], references: [id])
totalCompensationId String? @unique totalCompensationId String? @unique
// INTERN fields // INTERN fields
monthlySalary OffersCurrency? @relation("ExperienceMonthlySalary", fields: [monthlySalaryId], references: [id]) monthlySalary OffersCurrency? @relation("ExperienceMonthlySalary", fields: [monthlySalaryId], references: [id])
monthlySalaryId String? @unique monthlySalaryId String? @unique
background OffersBackground @relation(fields: [backgroundId], references: [id], onDelete: Cascade) background OffersBackground @relation(fields: [backgroundId], references: [id], onDelete: Cascade)
backgroundId String backgroundId String
} }
model OffersCurrency { model OffersCurrency {
id String @id @default(cuid()) id String @id @default(cuid())
value Int value Int
currency String currency String
// Experience // Experience
OffersExperienceTotalCompensation OffersExperience? @relation("ExperienceTotalCompensation") OffersExperienceTotalCompensation OffersExperience? @relation("ExperienceTotalCompensation")
OffersExperienceMonthlySalary OffersExperience? @relation("ExperienceMonthlySalary") OffersExperienceMonthlySalary OffersExperience? @relation("ExperienceMonthlySalary")
// Full Time // Full Time
OffersTotalCompensation OffersFullTime? @relation("OfferTotalCompensation") OffersTotalCompensation OffersFullTime? @relation("OfferTotalCompensation")
OffersBaseSalary OffersFullTime? @relation("OfferBaseSalary") OffersBaseSalary OffersFullTime? @relation("OfferBaseSalary")
OffersBonus OffersFullTime? @relation("OfferBonus") OffersBonus OffersFullTime? @relation("OfferBonus")
OffersStocks OffersFullTime? @relation("OfferStocks") OffersStocks OffersFullTime? @relation("OfferStocks")
// Intern // Intern
OffersMonthlySalary OffersIntern? OffersMonthlySalary OffersIntern?
} }
enum JobType { enum JobType {
INTERN INTERN
FULLTIME FULLTIME
} }
model OffersEducation { model OffersEducation {
id String @id @default(cuid()) id String @id @default(cuid())
type String? type String?
field String? field String?
school String? school String?
startDate DateTime? startDate DateTime?
endDate DateTime? endDate DateTime?
background OffersBackground @relation(fields: [backgroundId], references: [id], onDelete: Cascade) background OffersBackground @relation(fields: [backgroundId], references: [id], onDelete: Cascade)
backgroundId String backgroundId String
} }
model OffersReply { model OffersReply {
id String @id @default(cuid()) id String @id @default(cuid())
createdAt DateTime @default(now()) createdAt DateTime @default(now())
message String message String
replyingToId String? replyingToId String?
replyingTo OffersReply? @relation("ReplyThread", fields: [replyingToId], references: [id]) replyingTo OffersReply? @relation("ReplyThread", fields: [replyingToId], references: [id])
replies OffersReply[] @relation("ReplyThread") replies OffersReply[] @relation("ReplyThread")
profile OffersProfile @relation(fields: [profileId], references: [id], onDelete: Cascade) profile OffersProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
profileId String profileId String
user User? @relation(fields: [userId], references: [id]) user User? @relation(fields: [userId], references: [id])
userId String? userId String?
} }
model OffersOffer { model OffersOffer {
id String @id @default(cuid()) id String @id @default(cuid())
profile OffersProfile @relation(fields: [profileId], references: [id], onDelete: Cascade) profile OffersProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
profileId String profileId String
company Company @relation(fields: [companyId], references: [id]) company Company @relation(fields: [companyId], references: [id])
companyId String companyId String
monthYearReceived DateTime monthYearReceived DateTime
location String location String
negotiationStrategy String? negotiationStrategy String?
comments String? comments String?
jobType JobType jobType JobType
OffersIntern OffersIntern? @relation(fields: [offersInternId], references: [id], onDelete: Cascade) OffersIntern OffersIntern? @relation(fields: [offersInternId], references: [id], onDelete: Cascade)
offersInternId String? @unique offersInternId String? @unique
OffersFullTime OffersFullTime? @relation(fields: [offersFullTimeId], references: [id], onDelete: Cascade) OffersFullTime OffersFullTime? @relation(fields: [offersFullTimeId], references: [id], onDelete: Cascade)
offersFullTimeId String? @unique offersFullTimeId String? @unique
} }
model OffersIntern { model OffersIntern {
id String @id @default(cuid()) id String @id @default(cuid())
title String title String
specialization String specialization String
internshipCycle String internshipCycle String
startYear Int startYear Int
monthlySalary OffersCurrency @relation(fields: [monthlySalaryId], references: [id], onDelete: Cascade) monthlySalary OffersCurrency @relation(fields: [monthlySalaryId], references: [id], onDelete: Cascade)
monthlySalaryId String @unique monthlySalaryId String @unique
OffersOffer OffersOffer? OffersOffer OffersOffer?
} }
model OffersFullTime { model OffersFullTime {
id String @id @default(cuid()) id String @id @default(cuid())
title String title String
specialization String specialization String
level String level String
totalCompensation OffersCurrency @relation("OfferTotalCompensation", fields: [totalCompensationId], references: [id], onDelete: Cascade) totalCompensation OffersCurrency @relation("OfferTotalCompensation", fields: [totalCompensationId], references: [id], onDelete: Cascade)
totalCompensationId String @unique totalCompensationId String @unique
baseSalary OffersCurrency @relation("OfferBaseSalary", fields: [baseSalaryId], references: [id], onDelete: Cascade) baseSalary OffersCurrency @relation("OfferBaseSalary", fields: [baseSalaryId], references: [id], onDelete: Cascade)
baseSalaryId String @unique baseSalaryId String @unique
bonus OffersCurrency @relation("OfferBonus", fields: [bonusId], references: [id], onDelete: Cascade) bonus OffersCurrency @relation("OfferBonus", fields: [bonusId], references: [id], onDelete: Cascade)
bonusId String @unique bonusId String @unique
stocks OffersCurrency @relation("OfferStocks", fields: [stocksId], references: [id], onDelete: Cascade) stocks OffersCurrency @relation("OfferStocks", fields: [stocksId], references: [id], onDelete: Cascade)
stocksId String @unique stocksId String @unique
OffersOffer OffersOffer? OffersOffer OffersOffer?
} }
// End of Offers project models. // End of Offers project models.
@ -356,136 +356,136 @@ model OffersFullTime {
// across all models in this file. // across all models in this file.
enum QuestionsQuestionType { enum QuestionsQuestionType {
CODING CODING
SYSTEM_DESIGN SYSTEM_DESIGN
BEHAVIORAL BEHAVIORAL
} }
model QuestionsQuestion { model QuestionsQuestion {
id String @id @default(cuid()) id String @id @default(cuid())
userId String? userId String?
content String @db.Text content String @db.Text
questionType QuestionsQuestionType questionType QuestionsQuestionType
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: SetNull) user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
encounters QuestionsQuestionEncounter[] encounters QuestionsQuestionEncounter[]
votes QuestionsQuestionVote[] votes QuestionsQuestionVote[]
comments QuestionsQuestionComment[] comments QuestionsQuestionComment[]
answers QuestionsAnswer[] answers QuestionsAnswer[]
} }
model QuestionsQuestionEncounter { model QuestionsQuestionEncounter {
id String @id @default(cuid()) id String @id @default(cuid())
questionId String questionId String
userId String? userId String?
// TODO: sync with models // TODO: sync with models
company String @db.Text company String @db.Text
location String @db.Text location String @db.Text
role String @db.Text role String @db.Text
seenAt DateTime seenAt DateTime
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: SetNull) user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
question QuestionsQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade) question QuestionsQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
} }
model QuestionsQuestionVote { model QuestionsQuestionVote {
id String @id @default(cuid()) id String @id @default(cuid())
questionId String questionId String
userId String? userId String?
vote Vote vote Vote
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: SetNull) user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
question QuestionsQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade) question QuestionsQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
@@unique([questionId, userId]) @@unique([questionId, userId])
} }
model QuestionsQuestionComment { model QuestionsQuestionComment {
id String @id @default(cuid()) id String @id @default(cuid())
questionId String questionId String
userId String? userId String?
content String @db.Text content String @db.Text
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: SetNull) user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
question QuestionsQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade) question QuestionsQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
votes QuestionsQuestionCommentVote[] votes QuestionsQuestionCommentVote[]
} }
model QuestionsQuestionCommentVote { model QuestionsQuestionCommentVote {
id String @id @default(cuid()) id String @id @default(cuid())
questionCommentId String questionCommentId String
userId String? userId String?
vote Vote vote Vote
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: SetNull) user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
comment QuestionsQuestionComment @relation(fields: [questionCommentId], references: [id], onDelete: Cascade) comment QuestionsQuestionComment @relation(fields: [questionCommentId], references: [id], onDelete: Cascade)
@@unique([questionCommentId, userId]) @@unique([questionCommentId, userId])
} }
model QuestionsAnswer { model QuestionsAnswer {
id String @id @default(cuid()) id String @id @default(cuid())
questionId String questionId String
userId String? userId String?
content String @db.Text content String @db.Text
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: SetNull) user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
question QuestionsQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade) question QuestionsQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
votes QuestionsAnswerVote[] votes QuestionsAnswerVote[]
comments QuestionsAnswerComment[] comments QuestionsAnswerComment[]
} }
model QuestionsAnswerVote { model QuestionsAnswerVote {
id String @id @default(cuid()) id String @id @default(cuid())
answerId String answerId String
userId String? userId String?
vote Vote vote Vote
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: SetNull) user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
answer QuestionsAnswer @relation(fields: [answerId], references: [id], onDelete: Cascade) answer QuestionsAnswer @relation(fields: [answerId], references: [id], onDelete: Cascade)
@@unique([answerId, userId]) @@unique([answerId, userId])
} }
model QuestionsAnswerComment { model QuestionsAnswerComment {
id String @id @default(cuid()) id String @id @default(cuid())
answerId String answerId String
userId String? userId String?
content String @db.Text content String @db.Text
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: SetNull) user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
answer QuestionsAnswer @relation(fields: [answerId], references: [id], onDelete: Cascade) answer QuestionsAnswer @relation(fields: [answerId], references: [id], onDelete: Cascade)
votes QuestionsAnswerCommentVote[] votes QuestionsAnswerCommentVote[]
} }
model QuestionsAnswerCommentVote { model QuestionsAnswerCommentVote {
id String @id @default(cuid()) id String @id @default(cuid())
answerCommentId String answerCommentId String
userId String? userId String?
vote Vote vote Vote
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: SetNull) user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
comment QuestionsAnswerComment @relation(fields: [answerCommentId], references: [id], onDelete: Cascade) comment QuestionsAnswerComment @relation(fields: [answerCommentId], references: [id], onDelete: Cascade)
@@unique([answerCommentId, userId]) @@unique([answerCommentId, userId])
} }
// End of Questions project models. // End of Questions project models.

@ -4,7 +4,7 @@ import { trpc } from '~/utils/trpc';
function Test() { function Test() {
const [createdData, setCreatedData] = useState(''); const [createdData, setCreatedData] = useState('');
const [error, setError] = useState(""); const [error, setError] = useState('');
const createMutation = trpc.useMutation(['offers.profile.create'], { const createMutation = trpc.useMutation(['offers.profile.create'], {
onError(err: any) { onError(err: any) {
@ -15,14 +15,17 @@ function Test() {
}, },
}); });
const addToUserProfileMutation = trpc.useMutation(['offers.profile.addToUserProfile'], { const addToUserProfileMutation = trpc.useMutation(
onError(err: any) { ['offers.profile.addToUserProfile'],
alert(err); {
}, onError(err: any) {
onSuccess(data) { alert(err);
setCreatedData(JSON.stringify(data)); },
onSuccess(data) {
setCreatedData(JSON.stringify(data));
},
}, },
}) );
const deleteCommentMutation = trpc.useMutation(['offers.comments.delete'], { const deleteCommentMutation = trpc.useMutation(['offers.comments.delete'], {
onError(err: any) { onError(err: any) {
@ -38,9 +41,9 @@ function Test() {
id: 'cl97fprun001j7iyg6ev9x983', id: 'cl97fprun001j7iyg6ev9x983',
profileId: 'cl96stky5002ew32gx2kale2x', profileId: 'cl96stky5002ew32gx2kale2x',
token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1', token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1',
userId: 'cl97dl51k001e7iygd5v5gt58' userId: 'cl97dl51k001e7iygd5v5gt58',
}) });
} };
const updateCommentMutation = trpc.useMutation(['offers.comments.update'], { const updateCommentMutation = trpc.useMutation(['offers.comments.update'], {
onError(err: any) { onError(err: any) {
@ -56,9 +59,9 @@ function Test() {
id: 'cl97fxb0y001l7iyg14sdobt2', id: 'cl97fxb0y001l7iyg14sdobt2',
message: 'hello hello', message: 'hello hello',
profileId: 'cl96stky5002ew32gx2kale2x', profileId: 'cl96stky5002ew32gx2kale2x',
token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba' token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba',
}) });
} };
const createCommentMutation = trpc.useMutation(['offers.comments.create'], { const createCommentMutation = trpc.useMutation(['offers.comments.create'], {
onError(err: any) { onError(err: any) {
@ -74,16 +77,16 @@ function Test() {
message: 'hello', message: 'hello',
profileId: 'cl96stky5002ew32gx2kale2x', profileId: 'cl96stky5002ew32gx2kale2x',
// UserId: 'cl97dl51k001e7iygd5v5gt58' // UserId: 'cl97dl51k001e7iygd5v5gt58'
}) });
} };
const handleLink = () => { const handleLink = () => {
addToUserProfileMutation.mutate({ addToUserProfileMutation.mutate({
profileId: 'cl96stky5002ew32gx2kale2x', profileId: 'cl96stky5002ew32gx2kale2x',
token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba', token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba',
userId: 'cl97dl51k001e7iygd5v5gt58' userId: 'cl97dl51k001e7iygd5v5gt58',
}) });
} };
const handleClick = () => { const handleClick = () => {
createMutation.mutate({ createMutation.mutate({
@ -126,7 +129,6 @@ function Test() {
}, },
offers: [ offers: [
{ {
OffersFullTime: { OffersFullTime: {
baseSalary: { baseSalary: {
currency: 'SGD', currency: 'SGD',
@ -189,23 +191,30 @@ function Test() {
}; };
const profileId = 'cl96stky5002ew32gx2kale2x'; // Remember to change this filed after testing deleting const profileId = 'cl96stky5002ew32gx2kale2x'; // Remember to change this filed after testing deleting
const data = trpc.useQuery([ const data = trpc.useQuery(
`offers.profile.listOne`, [
`offers.profile.listOne`,
{
profileId,
token:
'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba',
},
],
{ {
profileId, onError(err) {
token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba', setError(err.shape?.message || '');
},
}, },
], { );
onError(err) {
setError(err.shape?.message || "")
}
});
const replies = trpc.useQuery(['offers.comments.getComments', {profileId: 'cl96stky5002ew32gx2kale2x'}], { const replies = trpc.useQuery(
onError(err) { ['offers.comments.getComments', { profileId: 'cl96stky5002ew32gx2kale2x' }],
setError(err.shape?.message || "") {
onError(err) {
setError(err.shape?.message || '');
},
}, },
}); );
const deleteMutation = trpc.useMutation(['offers.profile.delete']); const deleteMutation = trpc.useMutation(['offers.profile.delete']);
@ -230,357 +239,363 @@ function Test() {
background: { background: {
educations: [ educations: [
{ {
backgroundId: "cl96stky6002fw32g6vj4meyr", backgroundId: 'cl96stky6002fw32g6vj4meyr',
endDate: new Date("2018-09-30T07:58:54.000Z"), endDate: new Date('2018-09-30T07:58:54.000Z'),
field: "Computer Science", field: 'Computer Science',
id: "cl96stky6002gw32gey2ffawd", id: 'cl96stky6002gw32gey2ffawd',
school: "National University of Singapore", school: 'National University of Singapore',
startDate: new Date("2014-09-30T07:58:54.000Z"), startDate: new Date('2014-09-30T07:58:54.000Z'),
type: "Bachelors" type: 'Bachelors',
} },
], ],
experiences: [ experiences: [
{ {
backgroundId: "cl96stky6002fw32g6vj4meyr", backgroundId: 'cl96stky6002fw32g6vj4meyr',
company: { company: {
createdAt: new Date("2022-10-12T16:19:05.196Z"), 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.", description:
id: "cl95u79f000007im531ysjg79", '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.',
logoUrl: "https://logo.clearbit.com/meta.com", id: 'cl95u79f000007im531ysjg79',
name: "Meta", logoUrl: 'https://logo.clearbit.com/meta.com',
slug: "meta", name: 'Meta',
updatedAt: new Date("2022-10-12T16:19:05.196Z") slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
}, },
companyId: "cl95u79f000007im531ysjg79", companyId: 'cl95u79f000007im531ysjg79',
durationInMonths: 24, durationInMonths: 24,
id: "cl96stky6002iw32gpt6t87s2", id: 'cl96stky6002iw32gpt6t87s2',
jobType: "FULLTIME", jobType: 'FULLTIME',
level: "Junior", level: 'Junior',
monthlySalary: null, monthlySalary: null,
monthlySalaryId: null, monthlySalaryId: null,
specialization: "Front End", specialization: 'Front End',
title: "Software Engineer", title: 'Software Engineer',
totalCompensation: { totalCompensation: {
currency: "SGD", currency: 'SGD',
id: "cl96stky6002jw32g73svfacr", id: 'cl96stky6002jw32g73svfacr',
value: 104100 value: 104100,
}, },
totalCompensationId: "cl96stky6002jw32g73svfacr" totalCompensationId: 'cl96stky6002jw32g73svfacr',
} },
], ],
id: "cl96stky6002fw32g6vj4meyr", id: 'cl96stky6002fw32g6vj4meyr',
offersProfileId: "cl96stky5002ew32gx2kale2x", offersProfileId: 'cl96stky5002ew32gx2kale2x',
specificYoes: [ specificYoes: [
{ {
backgroundId: "cl96stky6002fw32g6vj4meyr", backgroundId: 'cl96stky6002fw32g6vj4meyr',
domain: "Backend", domain: 'Backend',
id: "cl96t7890004tw32g5in3px5j", id: 'cl96t7890004tw32g5in3px5j',
yoe: 2 yoe: 2,
}, },
{ {
backgroundId: "cl96stky6002fw32g6vj4meyr", backgroundId: 'cl96stky6002fw32g6vj4meyr',
domain: "Backend", domain: 'Backend',
id: "cl96tb87x004xw32gnu17jbzv", id: 'cl96tb87x004xw32gnu17jbzv',
yoe: 2 yoe: 2,
}, },
{ {
backgroundId: "cl96stky6002fw32g6vj4meyr", backgroundId: 'cl96stky6002fw32g6vj4meyr',
domain: "Backend", domain: 'Backend',
id: "cl976t39z00007iygt3np3cgo", id: 'cl976t39z00007iygt3np3cgo',
yoe: 2 yoe: 2,
}, },
{ {
backgroundId: "cl96stky6002fw32g6vj4meyr", backgroundId: 'cl96stky6002fw32g6vj4meyr',
domain: "Front End", domain: 'Front End',
id: "cl96stky7002mw32gn4jc7uml", id: 'cl96stky7002mw32gn4jc7uml',
yoe: 2 yoe: 2,
}, },
{ {
backgroundId: "cl96stky6002fw32g6vj4meyr", backgroundId: 'cl96stky6002fw32g6vj4meyr',
domain: "Full Stack", domain: 'Full Stack',
id: "cl96stky7002nw32gpprghtxr", id: 'cl96stky7002nw32gpprghtxr',
yoe: 2 yoe: 2,
}, },
{ {
backgroundId: "cl96stky6002fw32g6vj4meyr", backgroundId: 'cl96stky6002fw32g6vj4meyr',
domain: "Backend", domain: 'Backend',
id: "cl976we5h000p7iygiomdo9fh", id: 'cl976we5h000p7iygiomdo9fh',
yoe: 2 yoe: 2,
} },
], ],
totalYoe: 6 totalYoe: 6,
}, },
createdAt: "2022-10-13T08:28:13.518Z", createdAt: '2022-10-13T08:28:13.518Z',
discussion: [], discussion: [],
id: "cl96stky5002ew32gx2kale2x", id: 'cl96stky5002ew32gx2kale2x',
isEditable: true, isEditable: true,
offers: [ offers: [
{ {
OffersFullTime: { OffersFullTime: {
baseSalary: { baseSalary: {
currency: "SGD", currency: 'SGD',
id: "cl976t4de00067iyg3pjir7k9", id: 'cl976t4de00067iyg3pjir7k9',
value: 1999999999 value: 1999999999,
}, },
baseSalaryId: "cl976t4de00067iyg3pjir7k9", baseSalaryId: 'cl976t4de00067iyg3pjir7k9',
bonus: { bonus: {
currency: "SGD", currency: 'SGD',
id: "cl976t4de00087iygcnlmh8aw", id: 'cl976t4de00087iygcnlmh8aw',
value: 1410065407 value: 1410065407,
}, },
bonusId: "cl976t4de00087iygcnlmh8aw", bonusId: 'cl976t4de00087iygcnlmh8aw',
id: "cl976t4de00057iygq3ktce3v", id: 'cl976t4de00057iygq3ktce3v',
level: "EXPERT", level: 'EXPERT',
specialization: "FRONTEND", specialization: 'FRONTEND',
stocks: { stocks: {
currency: "SGD", currency: 'SGD',
id: "cl976t4df000a7iygkrsgr1xh", id: 'cl976t4df000a7iygkrsgr1xh',
value: -558038585 value: -558038585,
}, },
stocksId: "cl976t4df000a7iygkrsgr1xh", stocksId: 'cl976t4df000a7iygkrsgr1xh',
title: "Software Engineer", title: 'Software Engineer',
totalCompensation: { totalCompensation: {
currency: "SGD", currency: 'SGD',
id: "cl976t4df000c7iyg73ryf5uw", id: 'cl976t4df000c7iyg73ryf5uw',
value: 55555555 value: 55555555,
}, },
totalCompensationId: "cl976t4df000c7iyg73ryf5uw" totalCompensationId: 'cl976t4df000c7iyg73ryf5uw',
}, },
OffersIntern: null, OffersIntern: null,
comments: "this IS SO IEUHDAEUIGDI", comments: 'this IS SO IEUHDAEUIGDI',
company: { company: {
createdAt: new Date("2022-10-12T16:19:05.196Z"), 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.", description:
id: "cl95u79f000007im531ysjg79", '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.',
logoUrl: "https://logo.clearbit.com/meta.com", id: 'cl95u79f000007im531ysjg79',
name: "Meta", logoUrl: 'https://logo.clearbit.com/meta.com',
slug: "meta", name: 'Meta',
updatedAt: new Date("2022-10-12T16:19:05.196Z") slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
}, },
companyId: "cl95u79f000007im531ysjg79", companyId: 'cl95u79f000007im531ysjg79',
id: "cl976t4de00047iygl0zbce11", id: 'cl976t4de00047iygl0zbce11',
jobType: "FULLTIME", jobType: 'FULLTIME',
location: "Singapore, Singapore", location: 'Singapore, Singapore',
monthYearReceived: new Date("2022-09-30T07:58:54.000Z"), monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
negotiationStrategy: "Charmed the guy with my face", negotiationStrategy: 'Charmed the guy with my face',
offersFullTimeId: "cl976t4de00057iygq3ktce3v", offersFullTimeId: 'cl976t4de00057iygq3ktce3v',
offersInternId: null, offersInternId: null,
profileId: "cl96stky5002ew32gx2kale2x" profileId: 'cl96stky5002ew32gx2kale2x',
}, },
{ {
OffersFullTime: { OffersFullTime: {
baseSalary: { baseSalary: {
currency: "SGD", currency: 'SGD',
id: "cl96stky80033w32gxw5goc4z", id: 'cl96stky80033w32gxw5goc4z',
value: 84000 value: 84000,
}, },
baseSalaryId: "cl96stky80033w32gxw5goc4z", baseSalaryId: 'cl96stky80033w32gxw5goc4z',
bonus: { bonus: {
currency: "SGD", currency: 'SGD',
id: "cl96stky80035w32gajjwdo1p", id: 'cl96stky80035w32gajjwdo1p',
value: 123456789 value: 123456789,
}, },
bonusId: "cl96stky80035w32gajjwdo1p", bonusId: 'cl96stky80035w32gajjwdo1p',
id: "cl96stky80032w32gep9ovgj3", id: 'cl96stky80032w32gep9ovgj3',
level: "Junior", level: 'Junior',
specialization: "Front End", specialization: 'Front End',
stocks: { stocks: {
currency: "SGD", currency: 'SGD',
id: "cl96stky90037w32gu04t6ybh", id: 'cl96stky90037w32gu04t6ybh',
value: 100 value: 100,
}, },
stocksId: "cl96stky90037w32gu04t6ybh", stocksId: 'cl96stky90037w32gu04t6ybh',
title: "Software Engineer", title: 'Software Engineer',
totalCompensation: { totalCompensation: {
currency: "SGD", currency: 'SGD',
id: "cl96stky90039w32glbpktd0o", id: 'cl96stky90039w32glbpktd0o',
value: 104100 value: 104100,
}, },
totalCompensationId: "cl96stky90039w32glbpktd0o" totalCompensationId: 'cl96stky90039w32glbpktd0o',
}, },
OffersIntern: null, OffersIntern: null,
comments: null, comments: null,
company: { company: {
createdAt: new Date("2022-10-12T16:19:05.196Z"), 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.", description:
id: "cl95u79f000007im531ysjg79", '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.',
logoUrl: "https://logo.clearbit.com/meta.com", id: 'cl95u79f000007im531ysjg79',
name: "Meta", logoUrl: 'https://logo.clearbit.com/meta.com',
slug: "meta", name: 'Meta',
updatedAt: new Date("2022-10-12T16:19:05.196Z") slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
}, },
companyId: "cl95u79f000007im531ysjg79", companyId: 'cl95u79f000007im531ysjg79',
id: "cl96stky80031w32gau9mu1gs", id: 'cl96stky80031w32gau9mu1gs',
jobType: "FULLTIME", jobType: 'FULLTIME',
location: "Singapore, Singapore", location: 'Singapore, Singapore',
monthYearReceived: new Date("2022-09-30T07:58:54.000Z"), monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
negotiationStrategy: "Leveraged having million offers", negotiationStrategy: 'Leveraged having million offers',
offersFullTimeId: "cl96stky80032w32gep9ovgj3", offersFullTimeId: 'cl96stky80032w32gep9ovgj3',
offersInternId: null, offersInternId: null,
profileId: "cl96stky5002ew32gx2kale2x" profileId: 'cl96stky5002ew32gx2kale2x',
}, },
{ {
OffersFullTime: { OffersFullTime: {
baseSalary: { baseSalary: {
currency: "SGD", currency: 'SGD',
id: "cl96stky9003dw32gcvqbijlo", id: 'cl96stky9003dw32gcvqbijlo',
value: 1 value: 1,
}, },
baseSalaryId: "cl96stky9003dw32gcvqbijlo", baseSalaryId: 'cl96stky9003dw32gcvqbijlo',
bonus: { bonus: {
currency: "SGD", currency: 'SGD',
id: "cl96stky9003fw32goc3zqxwr", id: 'cl96stky9003fw32goc3zqxwr',
value: 0 value: 0,
}, },
bonusId: "cl96stky9003fw32goc3zqxwr", bonusId: 'cl96stky9003fw32goc3zqxwr',
id: "cl96stky9003cw32g5v10izfu", id: 'cl96stky9003cw32g5v10izfu',
level: "Senior", level: 'Senior',
specialization: "Front End", specialization: 'Front End',
stocks: { stocks: {
currency: "SGD", currency: 'SGD',
id: "cl96stky9003hw32g1lbbkqqr", id: 'cl96stky9003hw32g1lbbkqqr',
value: 999999 value: 999999,
}, },
stocksId: "cl96stky9003hw32g1lbbkqqr", stocksId: 'cl96stky9003hw32g1lbbkqqr',
title: "Software Engineer DOG", title: 'Software Engineer DOG',
totalCompensation: { totalCompensation: {
currency: "SGD", currency: 'SGD',
id: "cl96stky9003jw32gzumcoi7v", id: 'cl96stky9003jw32gzumcoi7v',
value: 999999 value: 999999,
}, },
totalCompensationId: "cl96stky9003jw32gzumcoi7v" totalCompensationId: 'cl96stky9003jw32gzumcoi7v',
}, },
OffersIntern: null, OffersIntern: null,
comments: null, comments: null,
company: { company: {
createdAt: new Date("2022-10-12T16:19:05.196Z"), 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.", description:
id: "cl95u79f000007im531ysjg79", '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.',
logoUrl: "https://logo.clearbit.com/meta.com", id: 'cl95u79f000007im531ysjg79',
name: "Meta", logoUrl: 'https://logo.clearbit.com/meta.com',
slug: "meta", name: 'Meta',
updatedAt: new Date("2022-10-12T16:19:05.196Z") slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
}, },
companyId: "cl95u79f000007im531ysjg79", companyId: 'cl95u79f000007im531ysjg79',
id: "cl96stky9003bw32gc3l955vr", id: 'cl96stky9003bw32gc3l955vr',
jobType: "FULLTIME", jobType: 'FULLTIME',
location: "Singapore, Singapore", location: 'Singapore, Singapore',
monthYearReceived: new Date("2022-09-30T07:58:54.000Z"), monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
negotiationStrategy: "LOst out having multiple offers", negotiationStrategy: 'LOst out having multiple offers',
offersFullTimeId: "cl96stky9003cw32g5v10izfu", offersFullTimeId: 'cl96stky9003cw32g5v10izfu',
offersInternId: null, offersInternId: null,
profileId: "cl96stky5002ew32gx2kale2x" profileId: 'cl96stky5002ew32gx2kale2x',
}, },
{ {
OffersFullTime: { OffersFullTime: {
baseSalary: { baseSalary: {
currency: "SGD", currency: 'SGD',
id: "cl976wf28000v7iygmk1b7qaq", id: 'cl976wf28000v7iygmk1b7qaq',
value: 1999999999 value: 1999999999,
}, },
baseSalaryId: "cl976wf28000v7iygmk1b7qaq", baseSalaryId: 'cl976wf28000v7iygmk1b7qaq',
bonus: { bonus: {
currency: "SGD", currency: 'SGD',
id: "cl976wf28000x7iyg63w7kcli", id: 'cl976wf28000x7iyg63w7kcli',
value: 1410065407 value: 1410065407,
}, },
bonusId: "cl976wf28000x7iyg63w7kcli", bonusId: 'cl976wf28000x7iyg63w7kcli',
id: "cl976wf28000u7iyg6euei8e9", id: 'cl976wf28000u7iyg6euei8e9',
level: "EXPERT", level: 'EXPERT',
specialization: "FRONTEND", specialization: 'FRONTEND',
stocks: { stocks: {
currency: "SGD", currency: 'SGD',
id: "cl976wf28000z7iyg9ivun6ap", id: 'cl976wf28000z7iyg9ivun6ap',
value: 111222333 value: 111222333,
}, },
stocksId: "cl976wf28000z7iyg9ivun6ap", stocksId: 'cl976wf28000z7iyg9ivun6ap',
title: "Software Engineer", title: 'Software Engineer',
totalCompensation: { totalCompensation: {
currency: "SGD", currency: 'SGD',
id: "cl976wf2800117iygmzsc0xit", id: 'cl976wf2800117iygmzsc0xit',
value: 55555555 value: 55555555,
}, },
totalCompensationId: "cl976wf2800117iygmzsc0xit" totalCompensationId: 'cl976wf2800117iygmzsc0xit',
}, },
OffersIntern: null, OffersIntern: null,
comments: "this IS SO COOL", comments: 'this IS SO COOL',
company: { company: {
createdAt: new Date("2022-10-12T16:19:05.196Z"), 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.", description:
id: "cl95u79f000007im531ysjg79", '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.',
logoUrl: "https://logo.clearbit.com/meta.com", id: 'cl95u79f000007im531ysjg79',
name: "Meta", logoUrl: 'https://logo.clearbit.com/meta.com',
slug: "meta", name: 'Meta',
updatedAt: new Date("2022-10-12T16:19:05.196Z") slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
}, },
companyId: "cl95u79f000007im531ysjg79", companyId: 'cl95u79f000007im531ysjg79',
id: "cl976wf28000t7iyga4noyz7s", id: 'cl976wf28000t7iyga4noyz7s',
jobType: "FULLTIME", jobType: 'FULLTIME',
location: "Singapore, Singapore", location: 'Singapore, Singapore',
monthYearReceived: new Date("2022-09-30T07:58:54.000Z"), monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
negotiationStrategy: "Charmed the guy with my face", negotiationStrategy: 'Charmed the guy with my face',
offersFullTimeId: "cl976wf28000u7iyg6euei8e9", offersFullTimeId: 'cl976wf28000u7iyg6euei8e9',
offersInternId: null, offersInternId: null,
profileId: "cl96stky5002ew32gx2kale2x" profileId: 'cl96stky5002ew32gx2kale2x',
}, },
{ {
OffersFullTime: { OffersFullTime: {
baseSalary: { baseSalary: {
currency: "SGD", currency: 'SGD',
id: "cl96tbb3o0053w32gz11paaxu", id: 'cl96tbb3o0053w32gz11paaxu',
value: 1999999999 value: 1999999999,
}, },
baseSalaryId: "cl96tbb3o0053w32gz11paaxu", baseSalaryId: 'cl96tbb3o0053w32gz11paaxu',
bonus: { bonus: {
currency: "SGD", currency: 'SGD',
id: "cl96tbb3o0055w32gpyqgz5hx", id: 'cl96tbb3o0055w32gpyqgz5hx',
value: 1410065407 value: 1410065407,
}, },
bonusId: "cl96tbb3o0055w32gpyqgz5hx", bonusId: 'cl96tbb3o0055w32gpyqgz5hx',
id: "cl96tbb3o0052w32guguajzin", id: 'cl96tbb3o0052w32guguajzin',
level: "EXPERT", level: 'EXPERT',
specialization: "FRONTEND", specialization: 'FRONTEND',
stocks: { stocks: {
currency: "SGD", currency: 'SGD',
id: "cl96tbb3o0057w32gu4nyxguf", id: 'cl96tbb3o0057w32gu4nyxguf',
value: 500 value: 500,
}, },
stocksId: "cl96tbb3o0057w32gu4nyxguf", stocksId: 'cl96tbb3o0057w32gu4nyxguf',
title: "Software Engineer", title: 'Software Engineer',
totalCompensation: { totalCompensation: {
currency: "SGD", currency: 'SGD',
id: "cl96tbb3o0059w32gm3iy1zk4", id: 'cl96tbb3o0059w32gm3iy1zk4',
value: 55555555 value: 55555555,
}, },
totalCompensationId: "cl96tbb3o0059w32gm3iy1zk4" totalCompensationId: 'cl96tbb3o0059w32gm3iy1zk4',
}, },
OffersIntern: null, OffersIntern: null,
comments: "this rocks", comments: 'this rocks',
company: { company: {
createdAt: new Date("2022-10-12T16:19:05.196Z"), 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.", description:
id: "cl95u79f000007im531ysjg79", '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.',
logoUrl: "https://logo.clearbit.com/meta.com", id: 'cl95u79f000007im531ysjg79',
name: "Meta", logoUrl: 'https://logo.clearbit.com/meta.com',
slug: "meta", name: 'Meta',
updatedAt: new Date("2022-10-12T16:19:05.196Z") slug: 'meta',
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
}, },
companyId: "cl95u79f000007im531ysjg79", companyId: 'cl95u79f000007im531ysjg79',
id: "cl96tbb3o0051w32gjrpaiiit", id: 'cl96tbb3o0051w32gjrpaiiit',
jobType: "FULLTIME", jobType: 'FULLTIME',
location: "Singapore, Singapore", location: 'Singapore, Singapore',
monthYearReceived: new Date("2022-09-30T07:58:54.000Z"), monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
negotiationStrategy: "Charmed the guy with my face", negotiationStrategy: 'Charmed the guy with my face',
offersFullTimeId: "cl96tbb3o0052w32guguajzin", offersFullTimeId: 'cl96tbb3o0052w32guguajzin',
offersInternId: null, offersInternId: null,
profileId: "cl96stky5002ew32gx2kale2x" profileId: 'cl96stky5002ew32gx2kale2x',
} },
], ],
profileName: "ailing bryann stuart ziqing", profileName: 'ailing bryann stuart ziqing',
token: "afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba", token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba',
userId: null userId: null,
}); });
} };
return ( return (
<> <>

@ -6,12 +6,11 @@ function Test() {
const data = trpc.useQuery([ const data = trpc.useQuery([
'offers.list', 'offers.list',
{ {
companyId: 'cl95u79f000007im531ysjg79', limit: 100,
limit: 20,
location: 'Singapore, Singapore', location: 'Singapore, Singapore',
offset: 0, offset: 0,
sortBy: '-monthYearReceived', sortBy: '-totalYoe',
yoeCategory: 1, yoeCategory: 2,
}, },
]); ]);

@ -0,0 +1,14 @@
import React from 'react';
import { trpc } from '~/utils/trpc';
function profileAnalysis() {
const analysis = trpc.useQuery([
'offers.analysis.generate',
{ profileId: 'cl96stky5002ew32gx2kale2x' },
]);
return <div>{JSON.stringify(analysis.data)}</div>;
}
export default profileAnalysis;

@ -3,6 +3,7 @@ import superjson from 'superjson';
import { companiesRouter } from './companies-router'; import { companiesRouter } from './companies-router';
import { createRouter } from './context'; import { createRouter } from './context';
import { offersRouter } from './offers/offers'; import { offersRouter } from './offers/offers';
import { offersAnalysisRouter } from './offers/offers-analysis-router';
import { offersCommentsRouter } from './offers/offers-comments-router'; import { offersCommentsRouter } from './offers/offers-comments-router';
import { offersProfileRouter } from './offers/offers-profile-router'; import { offersProfileRouter } from './offers/offers-profile-router';
import { protectedExampleRouter } from './protected-example-router'; import { protectedExampleRouter } from './protected-example-router';
@ -38,6 +39,7 @@ export const appRouter = createRouter()
.merge('questions.questions.', questionsQuestionRouter) .merge('questions.questions.', questionsQuestionRouter)
.merge('offers.', offersRouter) .merge('offers.', offersRouter)
.merge('offers.profile.', offersProfileRouter) .merge('offers.profile.', offersProfileRouter)
.merge('offers.analysis.', offersAnalysisRouter)
.merge('offers.comments.', offersCommentsRouter); .merge('offers.comments.', offersCommentsRouter);
// Export type definition of API // Export type definition of API

@ -0,0 +1,264 @@
import { z } from 'zod';
import type {
Company,
OffersBackground,
OffersCurrency,
OffersFullTime,
OffersIntern,
OffersOffer,
OffersProfile,
} from '@prisma/client';
import { TRPCError } from '@trpc/server';
import { createRouter } from '../context';
const binarySearchOfferPercentile = (
offer: OffersOffer & {
OffersFullTime:
| (OffersFullTime & {
baseSalary: OffersCurrency;
bonus: OffersCurrency;
stocks: OffersCurrency;
totalCompensation: OffersCurrency;
})
| null;
OffersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null;
company: Company;
profile: OffersProfile & { background: OffersBackground | null };
},
similarOffers: Array<any> | string,
) => {
let start = 0;
let end = similarOffers.length - 1;
while (start <= end) {
const mid = Math.floor((start + end) / 2);
if (similarOffers[mid].id === offer.id) {
return mid;
}
if (offer.id < similarOffers[mid].id) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return -1;
};
export const offersAnalysisRouter = createRouter().query('generate', {
input: z.object({
profileId: z.string(),
}),
async resolve({ ctx, input }) {
const offers = await ctx.prisma.offersOffer.findMany({
include: {
OffersFullTime: {
include: {
baseSalary: true,
bonus: true,
stocks: true,
totalCompensation: true,
},
},
OffersIntern: {
include: {
monthlySalary: true,
},
},
company: true,
profile: {
include: {
background: true,
},
},
},
orderBy: [
{
OffersFullTime: {
totalCompensation: {
value: 'desc',
},
},
},
{
OffersIntern: {
monthlySalary: {
value: 'desc',
},
},
},
],
where: {
profileId: input.profileId,
},
});
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,
},
{
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,
},
},
],
},
},
},
],
},
});
let similarCompanyOffers = similarOffers.filter(
(offer) => offer.companyId === overallHighestOffer.companyId,
);
// CALCULATE PERCENTILES
const highestOfferAgainstOverallIndex = binarySearchOfferPercentile(
overallHighestOffer,
similarOffers,
);
const highestOfferAgainstOverallPercentile =
highestOfferAgainstOverallIndex / similarOffers.length;
const highestOfferAgainstCompanyIndex = binarySearchOfferPercentile(
overallHighestOffer,
similarCompanyOffers,
);
const highestOfferAgainstCompanyPercentile =
highestOfferAgainstCompanyIndex / similarCompanyOffers.length;
// FIND TOP >=90 PERCENTILE OFFERS
similarOffers = similarOffers.filter(
(offer) => offer.id !== overallHighestOffer.id,
);
similarCompanyOffers = similarCompanyOffers.filter(
(offer) => offer.id !== overallHighestOffer.id,
);
const similarOffersCount = similarOffers.length;
const similarOffers90PercentileIndex =
Math.floor(similarOffersCount * 0.9) - 1;
const topPercentileOffers =
similarOffersCount > 1
? similarOffers.slice(
similarOffers90PercentileIndex,
similarOffers90PercentileIndex + 2,
)
: similarOffers;
const similarCompanyOffersCount = similarCompanyOffers.length;
const similarCompanyOffers90PercentileIndex =
Math.floor(similarCompanyOffersCount * 0.9) - 1;
const topPercentileCompanyOffers =
similarCompanyOffersCount > 1
? similarCompanyOffers.slice(
similarCompanyOffers90PercentileIndex,
similarCompanyOffers90PercentileIndex + 2,
)
: similarCompanyOffers;
return {
company: {
highestOfferAgainstCompanyPercentile,
similarCompanyOffersCount,
topPercentileCompanyOffers,
},
overall: {
highestOfferAgainstOverallPercentile,
similarOffersCount,
topPercentileOffers,
},
overallHighestOffer,
};
},
});

@ -16,8 +16,8 @@ const getYoeRange = (yoeCategory: number) => {
: yoeCategoryMap[yoeCategory] === 'Mid' : yoeCategoryMap[yoeCategory] === 'Mid'
? { maxYoe: 7, minYoe: 4 } ? { maxYoe: 7, minYoe: 4 }
: yoeCategoryMap[yoeCategory] === 'Senior' : yoeCategoryMap[yoeCategory] === 'Senior'
? { maxYoe: null, minYoe: 8 } ? { maxYoe: 100, minYoe: 8 }
: null; : null; // Internship
}; };
const ascOrder = '+'; const ascOrder = '+';
@ -35,7 +35,7 @@ export const offersRouter = createRouter().query('list', {
companyId: z.string().nullish(), companyId: z.string().nullish(),
dateEnd: z.date().nullish(), dateEnd: z.date().nullish(),
dateStart: z.date().nullish(), dateStart: z.date().nullish(),
limit: z.number().nonnegative(), limit: z.number().positive(),
location: z.string(), location: z.string(),
offset: z.number().nonnegative(), offset: z.number().nonnegative(),
salaryMax: z.number().nullish(), salaryMax: z.number().nullish(),
@ -43,9 +43,13 @@ export const offersRouter = createRouter().query('list', {
sortBy: z.string().regex(createSortByValidationRegex()).nullish(), sortBy: z.string().regex(createSortByValidationRegex()).nullish(),
title: z.string().nullish(), title: z.string().nullish(),
yoeCategory: z.number().min(0).max(3), yoeCategory: z.number().min(0).max(3),
yoeMax: z.number().max(100).nullish(),
yoeMin: z.number().min(0).nullish(),
}), }),
async resolve({ ctx, input }) { async resolve({ ctx, input }) {
const yoeRange = getYoeRange(input.yoeCategory); const yoeRange = getYoeRange(input.yoeCategory);
const yoeMin = input.yoeMin ? input.yoeMin : yoeRange?.minYoe;
const yoeMax = input.yoeMax ? input.yoeMax : yoeRange?.maxYoe;
let data = !yoeRange let data = !yoeRange
? await ctx.prisma.offersOffer.findMany({ ? await ctx.prisma.offersOffer.findMany({
@ -89,68 +93,8 @@ export const offersRouter = createRouter().query('list', {
], ],
}, },
}) })
: yoeRange.maxYoe
? await ctx.prisma.offersOffer.findMany({
// Junior, Mid
include: {
OffersFullTime: {
include: {
baseSalary: true,
bonus: true,
stocks: true,
totalCompensation: true,
},
},
OffersIntern: {
include: {
monthlySalary: true,
},
},
company: true,
profile: {
include: {
background: true,
},
},
},
where: {
AND: [
{
location: input.location,
},
{
OffersIntern: {
is: null,
},
},
{
OffersFullTime: {
isNot: null,
},
},
{
profile: {
background: {
totalYoe: {
gte: yoeRange.minYoe,
},
},
},
},
{
profile: {
background: {
totalYoe: {
gte: yoeRange.maxYoe,
},
},
},
},
],
},
})
: await ctx.prisma.offersOffer.findMany({ : await ctx.prisma.offersOffer.findMany({
// Senior // Junior, Mid, Senior
include: { include: {
OffersFullTime: { OffersFullTime: {
include: { include: {
@ -191,7 +135,8 @@ export const offersRouter = createRouter().query('list', {
profile: { profile: {
background: { background: {
totalYoe: { totalYoe: {
gte: yoeRange.minYoe, gte: yoeMin,
lte: yoeMax,
}, },
}, },
}, },

Loading…
Cancel
Save