diff --git a/apps/portal/src/components/offers/profile/OfferCard.tsx b/apps/portal/src/components/offers/profile/OfferCard.tsx index 58eb888f..8b3c9566 100644 --- a/apps/portal/src/components/offers/profile/OfferCard.tsx +++ b/apps/portal/src/components/offers/profile/OfferCard.tsx @@ -14,16 +14,16 @@ type Props = Readonly<{ export default function OfferCard({ offer: { - companyName = 'Meta', - jobTitle = 'Senior Engineer', - jobLevel, - location = 'Singapore', - receivedMonth = 'Jun 2021', - totalCompensation = '350.1k', - base = '0k', - stocks = '0k', - bonus = '0k', + base, + bonus, + companyName, duration, + jobTitle, + jobLevel, + location, + receivedMonth, + totalCompensation, + stocks, monthlySalary, negotiationStrategy, otherComment, diff --git a/apps/portal/src/components/offers/table/OffersTable.tsx b/apps/portal/src/components/offers/table/OffersTable.tsx index bfc74285..848098d7 100644 --- a/apps/portal/src/components/offers/table/OffersTable.tsx +++ b/apps/portal/src/components/offers/table/OffersTable.tsx @@ -19,7 +19,10 @@ export type OffersTableProps = Readonly<{ companyFilter: string; jobTitleFilter: string; }>; -export default function OffersTable({ jobTitleFilter }: OffersTableProps) { +export default function OffersTable({ + companyFilter, + jobTitleFilter, +}: OffersTableProps) { const [currency, setCurrency] = useState('SGD'); // TODO: Detect location const [selectedTab, setSelectedTab] = useState(YOE_CATEGORY.ENTRY); const [pagination, setPagination] = useState<PaginationType>({ @@ -42,10 +45,9 @@ export default function OffersTable({ jobTitleFilter }: OffersTableProps) { [ 'offers.list', { - // Company: companyFilter, // TODO + companyId: companyFilter, limit: NUMBER_OF_OFFERS_IN_PAGE, - - location: 'Singapore, Singapore', + location: 'Singapore, Singapore', // TODO: Geolocation offset: pagination.currentPage - 1, sortBy: '-monthYearReceived', title: jobTitleFilter, diff --git a/apps/portal/src/components/offers/types.ts b/apps/portal/src/components/offers/types.ts index 3ddf56b4..1841a3a5 100644 --- a/apps/portal/src/components/offers/types.ts +++ b/apps/portal/src/components/offers/types.ts @@ -137,11 +137,11 @@ type EducationDisplay = { export type OfferEntity = { base?: string; bonus?: string; - companyName: string; + companyName?: string; duration?: string; id?: string; jobLevel?: string; - jobTitle: string; + jobTitle?: string; location?: string; monthlySalary?: string; negotiationStrategy?: string; diff --git a/apps/portal/src/pages/offers/index.tsx b/apps/portal/src/pages/offers/index.tsx index f690fa27..eee97296 100644 --- a/apps/portal/src/pages/offers/index.tsx +++ b/apps/portal/src/pages/offers/index.tsx @@ -7,7 +7,7 @@ import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead'; export default function OffersHomePage() { const [jobTitleFilter, setjobTitleFilter] = useState('Software Engineer'); - const [companyFilter, setCompanyFilter] = useState('All companies'); + const [companyFilter, setCompanyFilter] = useState(''); return ( <main className="flex-1 overflow-y-auto"> diff --git a/apps/portal/src/pages/offers/profile/[offerProfileId].tsx b/apps/portal/src/pages/offers/profile/[offerProfileId].tsx index 31857c64..b59921cc 100644 --- a/apps/portal/src/pages/offers/profile/[offerProfileId].tsx +++ b/apps/portal/src/pages/offers/profile/[offerProfileId].tsx @@ -8,6 +8,7 @@ import ProfileHeader from '~/components/offers/profile/ProfileHeader'; import type { OfferEntity } from '~/components/offers/types'; import type { BackgroundCard } from '~/components/offers/types'; +import { convertCurrencyToString } from '~/utils/offers/currency'; import { formatDate } from '~/utils/offers/time'; import { trpc } from '~/utils/trpc'; export default function OfferProfile() { @@ -33,58 +34,57 @@ export default function OfferProfile() { if (!data) { router.push('/offers'); } + // If the profile is not editable with a wrong token, redirect to the profile page if (!data?.isEditable && token !== '') { router.push(`/offers/profile/${offerProfileId}`); } setIsEditable(data?.isEditable ?? false); - const filteredOffers: Array<OfferEntity> = data - ? data?.offers.map((res) => { - if (res.OffersFullTime) { + if (data?.offers) { + const filteredOffers: Array<OfferEntity> = data + ? data?.offers.map((res) => { + if (res.OffersFullTime) { + const filteredOffer: OfferEntity = { + base: convertCurrencyToString( + res.OffersFullTime.baseSalary.value, + ), + bonus: convertCurrencyToString( + res.OffersFullTime.bonus.value, + ), + companyName: res.company.name, + id: res.OffersFullTime.id, + jobLevel: res.OffersFullTime.level, + jobTitle: res.OffersFullTime.title, + location: res.location, + negotiationStrategy: res.negotiationStrategy || '', + otherComment: res.comments || '', + receivedMonth: formatDate(res.monthYearReceived), + stocks: convertCurrencyToString(res.OffersFullTime.stocks), + totalCompensation: convertCurrencyToString( + res.OffersFullTime.totalCompensation, + ), + }; + + return filteredOffer; + } const filteredOffer: OfferEntity = { - base: res.OffersFullTime.baseSalary.value - ? `${res.OffersFullTime.baseSalary.value} ${res.OffersFullTime.baseSalary.currency}` - : '', - bonus: res.OffersFullTime.bonus.value - ? `${res.OffersFullTime.bonus.value} ${res.OffersFullTime.bonus.currency}` - : '', companyName: res.company.name, - id: res.OffersFullTime.id, - jobLevel: res.OffersFullTime.level, - jobTitle: res.OffersFullTime.title, + id: res.OffersIntern!.id, + jobTitle: res.OffersIntern!.title, location: res.location, + monthlySalary: convertCurrencyToString( + res.OffersIntern!.monthlySalary, + ), negotiationStrategy: res.negotiationStrategy || '', otherComment: res.comments || '', receivedMonth: formatDate(res.monthYearReceived), - stocks: res.OffersFullTime.stocks.value - ? `${res.OffersFullTime.stocks.value} ${res.OffersFullTime.stocks.currency}` - : '', - totalCompensation: res.OffersFullTime.totalCompensation.value - ? `${res.OffersFullTime.totalCompensation.value} ${res.OffersFullTime.totalCompensation.currency}` - : '', }; - return filteredOffer; - } - const filteredOffer: OfferEntity = { - companyName: res.company.name, - id: res.OffersIntern!.id, - jobTitle: res.OffersIntern!.title, - location: res.location, - monthlySalary: res.OffersIntern!.monthlySalary.value - ? `${res.OffersIntern!.monthlySalary.value} ${ - res.OffersIntern!.monthlySalary.currency - }` - : '', - negotiationStrategy: res.negotiationStrategy || '', - otherComment: res.comments || '', - receivedMonth: formatDate(res.monthYearReceived), - }; - return filteredOffer; - }) - : []; - setOffers(filteredOffers); + }) + : []; + setOffers(filteredOffers); + } if (data?.background) { const transformedBackground = { @@ -102,23 +102,29 @@ export default function OfferProfile() { }, ], experiences: [ - { - companyName: - data.background.experiences[0].company?.name ?? '-', - duration: - String(data.background.experiences[0].durationInMonths) ?? - '-', - jobLevel: data.background.experiences[0].level ?? '', - jobTitle: data.background.experiences[0].title ?? '-', - monthlySalary: data.background.experiences[0].monthlySalary - ?.value - ? `${data.background.experiences[0].monthlySalary?.value} ${data.background.experiences[0].monthlySalary?.currency}` - : `-`, - totalCompensation: data.background.experiences[0] - .totalCompensation?.value - ? `${data.background.experiences[0].totalCompensation?.value} ${data.background.experiences[0].totalCompensation?.currency}` - : ``, - }, + data.background.experiences && + data.background.experiences.length > 0 + ? { + companyName: + data.background.experiences[0].company?.name ?? '-', + duration: + String(data.background.experiences[0].durationInMonths) ?? + '-', + jobLevel: data.background.experiences[0].level ?? '', + jobTitle: data.background.experiences[0].title ?? '-', + monthlySalary: data.background.experiences[0].monthlySalary + ? convertCurrencyToString( + data.background.experiences[0].monthlySalary, + ) + : '-', + totalCompensation: data.background.experiences[0] + .totalCompensation + ? convertCurrencyToString( + data.background.experiences[0].totalCompensation, + ) + : '-', + } + : {}, ], profileName: data.profileName, specificYoes: data.background.specificYoes ?? [], @@ -131,16 +137,22 @@ export default function OfferProfile() { ); const trpcContext = trpc.useContext(); - const deleteMutation = trpc.useMutation(['offers.profile.delete']); + const deleteMutation = trpc.useMutation(['offers.profile.delete'], { + onError: () => { + alert('Error deleting profile'); // TODO: replace with toast + }, + onSuccess: () => { + trpcContext.invalidateQueries(['offers.profile.listOne']); + router.push('/offers'); + }, + }); function handleDelete() { if (isEditable) { deleteMutation.mutate({ profileId: offerProfileId as string, - token: 'CHANGE THIS PART TO URL PARAM @ ZIQING', // TODO: token: token as string, + token: token as string, }); - trpcContext.invalidateQueries(['offers.profile.listOne']); - router.push('/offers'); } } diff --git a/apps/portal/src/utils/offers/currency/index.tsx b/apps/portal/src/utils/offers/currency/index.tsx new file mode 100644 index 00000000..c2cfcb05 --- /dev/null +++ b/apps/portal/src/utils/offers/currency/index.tsx @@ -0,0 +1,14 @@ +import type { Money } from '~/components/offers/types'; + +export function convertCurrencyToString({ currency, value }: Money) { + if (!value) { + return '-'; + } + const formatter = new Intl.NumberFormat('en-US', { + currency, + maximumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1) + minimumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501) + style: 'currency', + }); + return `${formatter.format(10000)}`; /* $2,500.00 */ +}