mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-28 20:52:00 +08:00
[offers][feat] integrate profile API and offer API (#360)
This commit is contained in:
@ -1,16 +1,22 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { HorizontalDivider, Pagination, Select, Tabs } from '@tih/ui';
|
||||
|
||||
import CurrencySelector from '~/utils/offers/currency/CurrencySelector';
|
||||
import { formatDate } from '~/utils/offers/time';
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
type TableRow = {
|
||||
type OfferTableRow = {
|
||||
company: string;
|
||||
date: string;
|
||||
salary: string;
|
||||
id: string;
|
||||
profileId: string;
|
||||
salary: number | undefined;
|
||||
title: string;
|
||||
yoe: string;
|
||||
yoe: number;
|
||||
};
|
||||
|
||||
// To be changed to backend enum
|
||||
// eslint-disable-next-line no-shadow
|
||||
enum YOE_CATEGORY {
|
||||
INTERN = 0,
|
||||
@ -19,10 +25,81 @@ enum YOE_CATEGORY {
|
||||
SENIOR = 3,
|
||||
}
|
||||
|
||||
export default function OffersTable() {
|
||||
const [currency, setCurrency] = useState('SGD');
|
||||
type OffersTableProps = {
|
||||
companyFilter: string;
|
||||
jobTitleFilter: string;
|
||||
};
|
||||
|
||||
type Pagination = {
|
||||
currentPage: number;
|
||||
numOfItems: number;
|
||||
numOfPages: number;
|
||||
totalItems: number;
|
||||
};
|
||||
|
||||
const NUMBER_OF_OFFERS_IN_PAGE = 10;
|
||||
|
||||
export default function OffersTable({ jobTitleFilter }: OffersTableProps) {
|
||||
const router = useRouter();
|
||||
const [currency, setCurrency] = useState('SGD'); // TODO
|
||||
const [selectedTab, setSelectedTab] = useState(YOE_CATEGORY.ENTRY);
|
||||
const [selectedPage, setSelectedPage] = useState(1);
|
||||
const [pagination, setPagination] = useState<Pagination>({
|
||||
currentPage: 1,
|
||||
numOfItems: 1,
|
||||
numOfPages: 0,
|
||||
totalItems: 0,
|
||||
});
|
||||
const [offers, setOffers] = useState<Array<OfferTableRow>>([]);
|
||||
|
||||
useEffect(() => {
|
||||
setPagination({
|
||||
currentPage: 1,
|
||||
numOfItems: 1,
|
||||
numOfPages: 0,
|
||||
totalItems: 0,
|
||||
});
|
||||
}, [selectedTab]);
|
||||
trpc.useQuery(
|
||||
[
|
||||
'offers.list',
|
||||
{
|
||||
// Company: companyFilter, // TODO
|
||||
limit: NUMBER_OF_OFFERS_IN_PAGE,
|
||||
|
||||
location: 'Singapore, Singapore',
|
||||
offset: pagination.currentPage - 1,
|
||||
sortBy: '-monthYearReceived',
|
||||
title: jobTitleFilter,
|
||||
yoeCategory: selectedTab,
|
||||
},
|
||||
],
|
||||
{
|
||||
onSuccess: (response) => {
|
||||
const filteredData = response.data.map((res) => {
|
||||
return {
|
||||
company: res.company.name,
|
||||
date: formatDate(res.monthYearReceived),
|
||||
id: res.OffersFullTime
|
||||
? res.OffersFullTime!.id
|
||||
: res.OffersIntern!.id,
|
||||
profileId: res.profileId,
|
||||
salary: res.OffersFullTime
|
||||
? res.OffersFullTime?.totalCompensation.value
|
||||
: res.OffersIntern?.monthlySalary.value,
|
||||
title: res.OffersFullTime ? res.OffersFullTime?.level : '',
|
||||
yoe: 100,
|
||||
};
|
||||
});
|
||||
setOffers(filteredData);
|
||||
setPagination({
|
||||
currentPage: (response.paging.currPage as number) + 1,
|
||||
numOfItems: response.paging.numOfItemsInPage,
|
||||
numOfPages: response.paging.numOfPages,
|
||||
totalItems: response.paging.totalNumberOfOffers,
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
function renderTabs() {
|
||||
return (
|
||||
@ -103,9 +180,27 @@ export default function OffersTable() {
|
||||
);
|
||||
}
|
||||
|
||||
function renderRow({ company, title, yoe, salary, date }: TableRow) {
|
||||
const handleClickViewProfile = (profileId: string) => {
|
||||
router.push(`/offers/profile/${profileId}`);
|
||||
};
|
||||
|
||||
const handlePageChange = (currPage: number) => {
|
||||
setPagination({ ...pagination, currentPage: currPage });
|
||||
};
|
||||
|
||||
function renderRow({
|
||||
company,
|
||||
title,
|
||||
yoe,
|
||||
salary,
|
||||
date,
|
||||
profileId,
|
||||
id,
|
||||
}: OfferTableRow) {
|
||||
return (
|
||||
<tr className="border-b bg-white hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-600">
|
||||
<tr
|
||||
key={id}
|
||||
className="border-b bg-white hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-600">
|
||||
<th
|
||||
className="whitespace-nowrap py-4 px-6 font-medium text-gray-900 dark:text-white"
|
||||
scope="row">
|
||||
@ -118,14 +213,14 @@ export default function OffersTable() {
|
||||
<td className="space-x-4 py-4 px-6">
|
||||
<a
|
||||
className="font-medium text-indigo-600 hover:underline dark:text-indigo-500"
|
||||
href="#">
|
||||
onClick={() => handleClickViewProfile(profileId)}>
|
||||
View Profile
|
||||
</a>
|
||||
<a
|
||||
{/* <a
|
||||
className="font-medium text-indigo-600 hover:underline dark:text-indigo-500"
|
||||
href="#">
|
||||
Comment
|
||||
</a>
|
||||
</a> */}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
@ -137,22 +232,30 @@ export default function OffersTable() {
|
||||
aria-label="Table navigation"
|
||||
className="flex items-center justify-between p-4">
|
||||
<span className="text-sm font-normal text-gray-500 dark:text-gray-400">
|
||||
Showing{' '}
|
||||
Showing
|
||||
<span className="font-semibold text-gray-900 dark:text-white">
|
||||
1-10
|
||||
</span>{' '}
|
||||
of{' '}
|
||||
{` ${
|
||||
(pagination.currentPage - 1) * NUMBER_OF_OFFERS_IN_PAGE + 1
|
||||
} - ${
|
||||
(pagination.currentPage - 1) * NUMBER_OF_OFFERS_IN_PAGE +
|
||||
offers.length
|
||||
} `}
|
||||
</span>
|
||||
{`of `}
|
||||
<span className="font-semibold text-gray-900 dark:text-white">
|
||||
1000
|
||||
{pagination.totalItems}
|
||||
{/* {pagination.numOfPages * NUMBER_OF_OFFERS_IN_PAGE} */}
|
||||
</span>
|
||||
</span>
|
||||
<Pagination
|
||||
current={selectedPage}
|
||||
end={10}
|
||||
current={pagination.currentPage}
|
||||
end={pagination.numOfPages}
|
||||
label="Pagination"
|
||||
pagePadding={1}
|
||||
start={1}
|
||||
onSelect={(page) => setSelectedPage(page)}
|
||||
onSelect={(currPage) => {
|
||||
handlePageChange(currPage);
|
||||
}}
|
||||
/>
|
||||
</nav>
|
||||
);
|
||||
@ -167,20 +270,7 @@ export default function OffersTable() {
|
||||
<table className="w-full text-left text-sm text-gray-500 dark:text-gray-400">
|
||||
{renderHeader()}
|
||||
<tbody>
|
||||
{renderRow({
|
||||
company: 'Shopee',
|
||||
date: 'May 2022',
|
||||
salary: 'TC/yr',
|
||||
title: 'SWE',
|
||||
yoe: '5',
|
||||
})}
|
||||
{renderRow({
|
||||
company: 'Shopee',
|
||||
date: 'May 2022',
|
||||
salary: 'TC/yr',
|
||||
title: 'SWE',
|
||||
yoe: '5',
|
||||
})}
|
||||
{offers.map((offer: OfferTableRow) => renderRow(offer))}
|
||||
</tbody>
|
||||
</table>
|
||||
{renderPagination()}
|
||||
|
@ -3,14 +3,14 @@ import {
|
||||
LightBulbIcon,
|
||||
} from '@heroicons/react/24/outline';
|
||||
|
||||
import type { EducationBackgroundType } from '../types';
|
||||
import type { EducationBackgroundType } from '~/components/offers/types';
|
||||
|
||||
type EducationEntity = {
|
||||
backgroundType?: EducationBackgroundType;
|
||||
endDate?: string;
|
||||
field?: string;
|
||||
fromMonth?: string;
|
||||
school?: string;
|
||||
toMonth?: string;
|
||||
startDate?: string;
|
||||
type?: EducationBackgroundType;
|
||||
};
|
||||
|
||||
type Props = Readonly<{
|
||||
@ -18,7 +18,7 @@ type Props = Readonly<{
|
||||
}>;
|
||||
|
||||
export default function EducationCard({
|
||||
education: { backgroundType, field, fromMonth, school, toMonth },
|
||||
education: { type, field, startDate, endDate, school },
|
||||
}: Props) {
|
||||
return (
|
||||
<div className="mx-8 my-4 block rounded-lg bg-white py-4 shadow-md">
|
||||
@ -27,9 +27,7 @@ export default function EducationCard({
|
||||
<div className="flex flex-row">
|
||||
<LightBulbIcon className="mr-1 h-5" />
|
||||
<span className="ml-1 font-bold">
|
||||
{field
|
||||
? `${backgroundType ?? 'N/A'}, ${field}`
|
||||
: backgroundType ?? `N/A`}
|
||||
{field ? `${type ?? 'N/A'}, ${field}` : type ?? `N/A`}
|
||||
</span>
|
||||
</div>
|
||||
{school && (
|
||||
@ -39,9 +37,11 @@ export default function EducationCard({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{(fromMonth || toMonth) && (
|
||||
{(startDate || endDate) && (
|
||||
<div className="font-light text-gray-400">
|
||||
<p>{`${fromMonth ?? 'N/A'} - ${toMonth ?? 'N/A'}`}</p>
|
||||
<p>{`${startDate ? startDate : 'N/A'} - ${
|
||||
endDate ? endDate : 'N/A'
|
||||
}`}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -6,18 +6,19 @@ import {
|
||||
} from '@heroicons/react/24/outline';
|
||||
import { HorizontalDivider } from '@tih/ui';
|
||||
|
||||
type OfferEntity = {
|
||||
export type OfferEntity = {
|
||||
base?: string;
|
||||
bonus?: string;
|
||||
companyName: string;
|
||||
duration?: string; // For background
|
||||
duration?: string;
|
||||
id?: string;
|
||||
jobLevel?: string;
|
||||
jobTitle: string;
|
||||
location: string;
|
||||
location?: string;
|
||||
monthlySalary?: string;
|
||||
negotiationStrategy?: string;
|
||||
otherComment?: string;
|
||||
receivedMonth: string;
|
||||
receivedMonth?: string;
|
||||
stocks?: string;
|
||||
totalCompensation?: string;
|
||||
};
|
||||
@ -57,14 +58,14 @@ export default function OfferCard({
|
||||
<p>{jobLevel ? `${jobTitle}, ${jobLevel}` : jobTitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
{receivedMonth && (
|
||||
{!duration && receivedMonth && (
|
||||
<div className="font-light text-gray-400">
|
||||
<p>{receivedMonth}</p>
|
||||
</div>
|
||||
)}
|
||||
{duration && (
|
||||
<div className="font-light text-gray-400">
|
||||
<p>{duration}</p>
|
||||
<p>{`${duration} months`}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-shadow */
|
||||
import type { MonthYear } from '../shared/MonthYearPicker';
|
||||
import type { OfferEntity } from '~/components/offers/profile/OfferCard';
|
||||
import type { MonthYear } from '~/components/shared/MonthYearPicker';
|
||||
|
||||
/*
|
||||
* Offer Profile
|
||||
@ -82,7 +83,7 @@ type GeneralExperience = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
type Experience =
|
||||
export type Experience =
|
||||
| (FullTimeExperience & GeneralExperience)
|
||||
| (GeneralExperience & InternshipExperience);
|
||||
|
||||
@ -110,3 +111,19 @@ export type OfferPostData = {
|
||||
background: BackgroundFormData;
|
||||
offers: Array<OfferDetailsPostData>;
|
||||
};
|
||||
|
||||
type EducationDisplay = {
|
||||
endDate?: string;
|
||||
field: string;
|
||||
school: string;
|
||||
startDate?: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type BackgroundCard = {
|
||||
educations: Array<EducationDisplay>;
|
||||
experiences: Array<OfferEntity>;
|
||||
profileName: string;
|
||||
specificYoes: Array<SpecificYoe>;
|
||||
totalYoe: string;
|
||||
};
|
||||
|
@ -6,8 +6,7 @@ import OffersTitle from '~/components/offers/OffersTitle';
|
||||
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
|
||||
|
||||
export default function OffersHomePage() {
|
||||
const [jobTitleFilter, setjobTitleFilter] = useState('Software engineers');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [jobTitleFilter, setjobTitleFilter] = useState('Software Engineer');
|
||||
const [companyFilter, setCompanyFilter] = useState('All companies');
|
||||
|
||||
return (
|
||||
@ -23,20 +22,20 @@ export default function OffersHomePage() {
|
||||
label="Select a job title"
|
||||
options={[
|
||||
{
|
||||
label: 'Software engineers',
|
||||
value: 'Software engineers',
|
||||
label: 'Software Engineer',
|
||||
value: 'Software Engineer',
|
||||
},
|
||||
{
|
||||
label: 'Frontend engineers',
|
||||
value: 'Frontend engineers',
|
||||
label: 'Frontend Engineer',
|
||||
value: 'Frontend Engineer',
|
||||
},
|
||||
{
|
||||
label: 'Backend engineers',
|
||||
value: 'Backend engineers',
|
||||
label: 'Backend Engineer',
|
||||
value: 'Backend Engineer',
|
||||
},
|
||||
{
|
||||
label: 'Full-stack engineers',
|
||||
value: 'Full-stack engineers',
|
||||
label: 'Full-stack Engineer',
|
||||
value: 'Full-stack Engineer',
|
||||
},
|
||||
]}
|
||||
value={jobTitleFilter}
|
||||
@ -53,7 +52,10 @@ export default function OffersHomePage() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-center bg-white pb-20 pt-10">
|
||||
<OffersTable />
|
||||
<OffersTable
|
||||
companyFilter={companyFilter}
|
||||
jobTitleFilter={jobTitleFilter}
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
@ -1,3 +1,5 @@
|
||||
import Error from 'next/error';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
AcademicCapIcon,
|
||||
@ -13,13 +15,129 @@ import {
|
||||
import { Button, Dialog, Tabs } from '@tih/ui';
|
||||
|
||||
import EducationCard from '~/components/offers/profile/EducationCard';
|
||||
import type { OfferEntity } from '~/components/offers/profile/OfferCard';
|
||||
import OfferCard from '~/components/offers/profile/OfferCard';
|
||||
import ProfilePhotoHolder from '~/components/offers/profile/ProfilePhotoHolder';
|
||||
import type { BackgroundCard } from '~/components/offers/types';
|
||||
import { EducationBackgroundType } from '~/components/offers/types';
|
||||
|
||||
import { formatDate } from '~/utils/offers/time';
|
||||
import { trpc } from '~/utils/trpc';
|
||||
export default function OfferProfile() {
|
||||
const ErrorPage = (
|
||||
<Error statusCode={404} title="Requested profile does not exist." />
|
||||
);
|
||||
const router = useRouter();
|
||||
const { offerProfileId, token = '' } = router.query;
|
||||
const [isEditable, setIsEditable] = useState(false);
|
||||
const [background, setBackground] = useState<BackgroundCard>();
|
||||
const [offers, setOffers] = useState<Array<OfferEntity>>([]);
|
||||
const [selectedTab, setSelectedTab] = useState('offers');
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||
|
||||
const detailsQuery = trpc.useQuery(
|
||||
[
|
||||
'offers.profile.listOne',
|
||||
{ profileId: offerProfileId as string, token: token as string },
|
||||
],
|
||||
{
|
||||
enabled: typeof offerProfileId === 'string',
|
||||
onSuccess: (data) => {
|
||||
const filteredOffers: Array<OfferEntity> = data!.offers.map((res) => {
|
||||
if (res.OffersFullTime) {
|
||||
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,
|
||||
location: res.location,
|
||||
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 ?? []);
|
||||
|
||||
if (data?.background) {
|
||||
const filteredBackground: BackgroundCard = {
|
||||
educations: [
|
||||
{
|
||||
endDate: data?.background.educations[0].endDate
|
||||
? formatDate(data.background.educations[0].endDate)
|
||||
: '-',
|
||||
field: data.background.educations[0].field || '-',
|
||||
school: data.background.educations[0].school || '-',
|
||||
startDate: data.background.educations[0].startDate
|
||||
? formatDate(data.background.educations[0].startDate)
|
||||
: '-',
|
||||
type: data.background.educations[0].type || '-',
|
||||
},
|
||||
],
|
||||
|
||||
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}`
|
||||
: ``,
|
||||
},
|
||||
],
|
||||
profileName: data.profileName,
|
||||
specificYoes: data.background.specificYoes ?? [],
|
||||
|
||||
totalYoe: String(data.background.totalYoe) || '-',
|
||||
};
|
||||
|
||||
setBackground(filteredBackground);
|
||||
}
|
||||
|
||||
setIsEditable(data?.isEditable ?? false);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
function renderActionList() {
|
||||
return (
|
||||
<div className="space-x-2">
|
||||
@ -67,8 +185,8 @@ export default function OfferProfile() {
|
||||
title="Are you sure you want to delete this offer profile?"
|
||||
onClose={() => setIsDialogOpen(false)}>
|
||||
<div>
|
||||
All comments will gone. You will not be able to access or recover
|
||||
it.
|
||||
All comments will be gone. You will not be able to access or
|
||||
recover it.
|
||||
</div>
|
||||
</Dialog>
|
||||
)}
|
||||
@ -84,20 +202,36 @@ export default function OfferProfile() {
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<div className="justify-left flex ">
|
||||
<h2 className="flex w-4/5 text-2xl font-bold">anonymised-name</h2>
|
||||
<div className="flex h-8 w-1/5 justify-end">
|
||||
{renderActionList()}
|
||||
</div>
|
||||
<h2 className="flex w-4/5 text-2xl font-bold">
|
||||
{background?.profileName ?? 'anonymous'}
|
||||
</h2>
|
||||
{isEditable && (
|
||||
<div className="flex h-8 w-1/5 justify-end">
|
||||
{isEditable && renderActionList()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row">
|
||||
<BuildingOffice2Icon className="mr-2.5 h-5" />
|
||||
<span className="mr-2 font-bold">Current:</span>
|
||||
<span>Level 4 Google</span>
|
||||
<span>{`${background?.experiences[0].companyName ?? '-'} ${
|
||||
background?.experiences[0].jobLevel
|
||||
} ${background?.experiences[0].jobTitle}`}</span>
|
||||
</div>
|
||||
<div className="flex flex-row">
|
||||
<CalendarDaysIcon className="mr-2.5 h-5" />
|
||||
<span className="mr-2 font-bold">YOE:</span>
|
||||
<span>4</span>
|
||||
<span className="mr-4">{background?.totalYoe}</span>
|
||||
{background?.specificYoes &&
|
||||
background?.specificYoes.length > 0 &&
|
||||
background?.specificYoes.map(({ domain, yoe }) => (
|
||||
<>
|
||||
<span
|
||||
key={domain}
|
||||
className="mr-2">{`${domain} : ${yoe}`}</span>
|
||||
<span>{background?.totalYoe}</span>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -131,41 +265,7 @@ export default function OfferProfile() {
|
||||
if (selectedTab === 'offers') {
|
||||
return (
|
||||
<>
|
||||
{[
|
||||
{
|
||||
base: undefined,
|
||||
bonus: undefined,
|
||||
companyName: 'Meta',
|
||||
id: 1,
|
||||
jobLevel: 'G5',
|
||||
jobTitle: 'Software Engineer',
|
||||
location: 'Singapore',
|
||||
monthlySalary: undefined,
|
||||
negotiationStrategy:
|
||||
'Nostrud nulla aliqua deserunt commodo id aute.',
|
||||
otherComment:
|
||||
'Pariatur ut est voluptate incididunt consequat do veniam quis irure adipisicing. Deserunt laborum dolor quis voluptate enim.',
|
||||
receivedMonth: 'Jun 2022',
|
||||
stocks: undefined,
|
||||
totalCompensation: undefined,
|
||||
},
|
||||
{
|
||||
companyName: 'Meta',
|
||||
id: 2,
|
||||
jobLevel: 'G5',
|
||||
jobTitle: 'Software Engineer',
|
||||
location: 'Singapore',
|
||||
receivedMonth: 'Jun 2022',
|
||||
},
|
||||
{
|
||||
companyName: 'Meta',
|
||||
id: 3,
|
||||
jobLevel: 'G5',
|
||||
jobTitle: 'Software Engineer',
|
||||
location: 'Singapore',
|
||||
receivedMonth: 'Jun 2022',
|
||||
},
|
||||
].map((offer) => (
|
||||
{[...offers].map((offer) => (
|
||||
<OfferCard key={offer.id} offer={offer} />
|
||||
))}
|
||||
</>
|
||||
@ -174,37 +274,32 @@ export default function OfferProfile() {
|
||||
if (selectedTab === 'background') {
|
||||
return (
|
||||
<>
|
||||
<div className="mx-8 my-4 flex flex-row">
|
||||
<BriefcaseIcon className="mr-1 h-5" />
|
||||
<span className="font-bold">Work Experience</span>
|
||||
</div>
|
||||
<OfferCard
|
||||
offer={{
|
||||
base: undefined,
|
||||
bonus: undefined,
|
||||
companyName: 'Prefer not to say',
|
||||
jobLevel: 'G4',
|
||||
jobTitle: 'N/A',
|
||||
location: '',
|
||||
monthlySalary: '1,400k',
|
||||
receivedMonth: '',
|
||||
stocks: undefined,
|
||||
totalCompensation: undefined,
|
||||
}}
|
||||
/>
|
||||
<div className="mx-8 my-4 flex flex-row">
|
||||
<AcademicCapIcon className="mr-1 h-5" />
|
||||
<span className="font-bold">Education</span>
|
||||
</div>
|
||||
<EducationCard
|
||||
education={{
|
||||
backgroundType: EducationBackgroundType.Bachelor,
|
||||
field: 'CS',
|
||||
fromMonth: 'Aug 2019',
|
||||
school: 'NUS',
|
||||
toMonth: 'May 2021',
|
||||
}}
|
||||
/>
|
||||
{background?.experiences && background?.experiences.length > 0 && (
|
||||
<>
|
||||
<div className="mx-8 my-4 flex flex-row">
|
||||
<BriefcaseIcon className="mr-1 h-5" />
|
||||
<span className="font-bold">Work Experience</span>
|
||||
</div>
|
||||
<OfferCard offer={background?.experiences[0]} />
|
||||
</>
|
||||
)}
|
||||
{background?.educations && background?.educations.length > 0 && (
|
||||
<>
|
||||
<div className="mx-8 my-4 flex flex-row">
|
||||
<AcademicCapIcon className="mr-1 h-5" />
|
||||
<span className="font-bold">Education</span>
|
||||
</div>
|
||||
<EducationCard
|
||||
education={{
|
||||
endDate: background.educations[0].endDate,
|
||||
field: background.educations[0].field,
|
||||
school: background.educations[0].school,
|
||||
startDate: background.educations[0].startDate,
|
||||
type: EducationBackgroundType.Bachelor,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -215,14 +310,22 @@ export default function OfferProfile() {
|
||||
return (
|
||||
<div className="m-4">
|
||||
<div className="flex-end flex justify-end space-x-4">
|
||||
<Button
|
||||
addonPosition="start"
|
||||
icon={ClipboardDocumentIcon}
|
||||
isLabelHidden={false}
|
||||
label="Copy profile edit link"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
/>
|
||||
{isEditable && (
|
||||
<Button
|
||||
addonPosition="start"
|
||||
icon={ClipboardDocumentIcon}
|
||||
isLabelHidden={false}
|
||||
label="Copy profile edit link"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
// TODO: Add notification
|
||||
navigator.clipboard.writeText(
|
||||
`${router.pathname}/${offerProfileId}?token=${token}`,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
addonPosition="start"
|
||||
icon={ShareIcon}
|
||||
@ -230,6 +333,12 @@ export default function OfferProfile() {
|
||||
label="Copy public link"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
// TODO: Add notification
|
||||
navigator.clipboard.writeText(
|
||||
`${window.location.origin}/offers/profile/${offerProfileId}`,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<h2 className="mt-2 text-2xl font-bold">
|
||||
@ -241,16 +350,19 @@ export default function OfferProfile() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mb-4 flex flex h-screen w-screen items-center justify-center divide-x">
|
||||
<div className="h-full w-2/3 divide-y">
|
||||
<ProfileHeader />
|
||||
<div className="h-4/5 w-full overflow-y-scroll pb-32">
|
||||
<ProfileDetails />
|
||||
<>
|
||||
{detailsQuery.isError && ErrorPage}
|
||||
<div className="mb-4 flex flex h-screen w-screen items-center justify-center divide-x">
|
||||
<div className="h-full w-2/3 divide-y">
|
||||
<ProfileHeader />
|
||||
<div className="h-4/5 w-full overflow-y-scroll pb-32">
|
||||
<ProfileDetails />
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-full w-1/3 bg-white">
|
||||
<ProfileComments />
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-full w-1/3 bg-white">
|
||||
<ProfileComments />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user