* main: (33 commits) [offers][fix] fix create offer bug [offers][feat] add default filters and more income columns (#495) [portal][ui] allow customization of spacing within MonthYearPicker [resumes][feat] add logo [offers][feat] return base bonus stocks for dashboard [offers][chore] Change location filter from city to country [offers][chore] Make all filters optional (#493) [offers][chore] Change location fields (#491) [ui][typeahead] fix nullable prop (#492) [offers] tweak offer profiles UI [portal][ui] change app shell nav structure [offers][refactor] tweak submit and analysis steps UI [offers][refactor] improve offers table responsiveness [offers][fix] use upsert to remove id in valuation [offers][fix] fix unable to update BBS in offer bug and remove valuation id [offers][feat] tweak offer background submission form (#490) [offers][fix] fix profile page mobile compatible style (#489) [offers][feat] tweak offer details submission form (#488) [offers][fix] tweak submit offer job type selector (#487) [portal][misc] refactor typeahead props ... # Conflicts: # apps/portal/src/components/offers/dashboard/DashboardOfferCard.tsx # apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx # apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx # apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx # apps/portal/src/components/offers/table/OffersTable.tsx # apps/portal/src/pages/offers/index.tsx # apps/portal/src/pages/offers/test/generateAnalysis.tsx # apps/portal/src/pages/offers/test/getAnalysis.tsx # apps/portal/src/pages/offers/test/listOffers.tsx # apps/portal/src/server/router/offers/offers-profile-router.ts # apps/portal/src/server/router/offers/offers.ts # apps/portal/src/utils/offers/analysisGeneration.tspull/501/head^2
commit
6c8d087bce
@ -0,0 +1,21 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `location` on the `OffersExperience` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `location` on the `OffersOffer` table. All the data in the column will be lost.
|
||||
- Added the required column `cityId` to the `OffersOffer` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "OffersExperience" DROP COLUMN "location",
|
||||
ADD COLUMN "cityId" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "OffersOffer" DROP COLUMN "location",
|
||||
ADD COLUMN "cityId" TEXT NOT NULL;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OffersExperience" ADD CONSTRAINT "OffersExperience_cityId_fkey" FOREIGN KEY ("cityId") REFERENCES "City"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OffersOffer" ADD CONSTRAINT "OffersOffer_cityId_fkey" FOREIGN KEY ("cityId") REFERENCES "City"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
After Width: | Height: | Size: 3.5 KiB |
@ -1,45 +1,50 @@
|
||||
export type BreadcrumbStep = {
|
||||
import clsx from 'clsx';
|
||||
import { ChevronRightIcon } from '@heroicons/react/20/solid';
|
||||
|
||||
export type BreadcrumbStep = Readonly<{
|
||||
label: string;
|
||||
step?: number;
|
||||
};
|
||||
}>;
|
||||
|
||||
type BreadcrumbsProps = Readonly<{
|
||||
currentStep: number;
|
||||
setStep: (nextStep: number) => void;
|
||||
steps: Array<BreadcrumbStep>;
|
||||
steps: ReadonlyArray<BreadcrumbStep>;
|
||||
}>;
|
||||
|
||||
function getPrimaryText(text: string) {
|
||||
return <p className="text-primary-700 text-sm">{text}</p>;
|
||||
}
|
||||
|
||||
function getSlateText(text: string) {
|
||||
return <p className="text-sm text-slate-400">{text}</p>;
|
||||
}
|
||||
|
||||
function getTextWithLink(text: string, onClickHandler: () => void) {
|
||||
return (
|
||||
<p
|
||||
className="hover:text-primary-700 cursor-pointer text-sm text-slate-400 hover:underline hover:underline-offset-2"
|
||||
onClick={onClickHandler}>
|
||||
{text}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
export function Breadcrumbs({ steps, currentStep, setStep }: BreadcrumbsProps) {
|
||||
return (
|
||||
<div className="flex space-x-1">
|
||||
<nav aria-label="Submit offer stages" className="inline-flex">
|
||||
<ol className="mx-auto flex w-full space-x-2 sm:space-x-4" role="list">
|
||||
{steps.map(({ label, step }, index) => (
|
||||
<div key={label} className="flex space-x-1">
|
||||
{step === currentStep
|
||||
? getPrimaryText(label)
|
||||
: step !== undefined
|
||||
? getTextWithLink(label, () => setStep(step))
|
||||
: getSlateText(label)}
|
||||
{index !== steps.length - 1 && getSlateText('>')}
|
||||
</div>
|
||||
<li key={step} className="flex items-center">
|
||||
{index > 0 && (
|
||||
<ChevronRightIcon
|
||||
aria-hidden="true"
|
||||
className="h-5 w-5 flex-shrink-0 text-slate-400"
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
aria-current={step === currentStep ? 'page' : undefined}
|
||||
className={clsx(
|
||||
'text-xs font-medium text-slate-600 sm:text-sm',
|
||||
index > 0 && 'ml-4',
|
||||
step != null ? 'hover:text-primary-500' : 'cursor-default',
|
||||
step === currentStep && 'text-primary-500',
|
||||
)}
|
||||
type="button"
|
||||
{...(step != null
|
||||
? {
|
||||
onClick: () => {
|
||||
setStep(step);
|
||||
},
|
||||
}
|
||||
: {})}>
|
||||
{label}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
</ol>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
import clsx from 'clsx';
|
||||
import { JobType } from '@prisma/client';
|
||||
|
||||
import { JobTypeLabel } from './types';
|
||||
|
||||
type Props = Readonly<{
|
||||
onChange: (jobType: JobType) => void;
|
||||
value: JobType;
|
||||
}>;
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
label: JobTypeLabel.FULLTIME,
|
||||
value: JobType.FULLTIME,
|
||||
},
|
||||
{
|
||||
label: JobTypeLabel.INTERN,
|
||||
value: JobType.INTERN,
|
||||
},
|
||||
];
|
||||
|
||||
export default function JobTypeTabs({ value, onChange }: Props) {
|
||||
return (
|
||||
<div className="block">
|
||||
<nav
|
||||
aria-label="Job Types"
|
||||
className="isolate flex divide-x divide-slate-200 rounded-lg border border-slate-200 bg-white">
|
||||
{tabs.map((tab, tabIdx) => (
|
||||
<button
|
||||
key={tab.value}
|
||||
aria-current={tab.value === value ? 'page' : undefined}
|
||||
className={clsx(
|
||||
tab.value === value
|
||||
? 'bg-primary-100 text-primary-700 hover:bg-primary-200'
|
||||
: 'text-slate-500 hover:bg-slate-50 hover:text-slate-700',
|
||||
tabIdx === 0 && 'rounded-l-lg',
|
||||
tabIdx === tabs.length - 1 && 'rounded-r-lg',
|
||||
'focus:ring-primary-500 group relative min-w-0 flex-1 overflow-hidden py-3 px-4 text-center font-medium focus:z-10',
|
||||
)}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onChange(tab.value);
|
||||
}}>
|
||||
<span>{tab.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { HorizontalDivider } from '@tih/ui';
|
||||
|
||||
export default function FormSection({
|
||||
children,
|
||||
title,
|
||||
}: Readonly<{ children: React.ReactNode; title: string }>) {
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-4">
|
||||
<h2 className="text-lg font-medium leading-6 text-slate-900">
|
||||
{title}
|
||||
</h2>
|
||||
<HorizontalDivider />
|
||||
</div>
|
||||
<div className="space-y-4 sm:space-y-6">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
type Props = Readonly<{
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
variant?: 'md' | 'sm' | 'xs';
|
||||
}>;
|
||||
|
||||
export default function Container({
|
||||
children,
|
||||
className,
|
||||
variant = 'md',
|
||||
}: Props) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'mx-auto px-4 sm:px-6 lg:px-8',
|
||||
variant === 'md' && 'max-w-7xl',
|
||||
variant === 'sm' && 'max-w-5xl',
|
||||
variant === 'xs' && 'max-w-3xl',
|
||||
className,
|
||||
)}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
export default function GitHubIcon(props: React.ComponentProps<'svg'>) {
|
||||
return (
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
stroke="currentColor"
|
||||
strokeWidth={0}
|
||||
viewBox="0 0 496 512"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}>
|
||||
<path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
export default function loginPageHref(redirectUrl?: string) {
|
||||
return {
|
||||
pathname: '/login',
|
||||
query: {
|
||||
redirect:
|
||||
typeof window !== 'undefined'
|
||||
? redirectUrl ?? window.location.href
|
||||
: null,
|
||||
},
|
||||
};
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import type {
|
||||
GetServerSideProps,
|
||||
InferGetServerSidePropsType,
|
||||
} from 'next/types';
|
||||
import { getProviders, signIn } from 'next-auth/react';
|
||||
import { Button } from '@tih/ui';
|
||||
|
||||
import GitHubIcon from '~/components/shared/icons/GitHubIcon';
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<{
|
||||
providers: Awaited<ReturnType<typeof getProviders>>;
|
||||
}> = async () => {
|
||||
const providers = await getProviders();
|
||||
return {
|
||||
props: { providers },
|
||||
};
|
||||
};
|
||||
|
||||
export default function LoginPage({
|
||||
providers,
|
||||
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<div className="flex w-full justify-center">
|
||||
<div className="flex min-h-full flex-col justify-center py-12 px-6 lg:px-8">
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<img
|
||||
alt="Tech Interview Handbook"
|
||||
className="mx-auto h-24 w-auto"
|
||||
src="/logo.svg"
|
||||
/>
|
||||
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-slate-900">
|
||||
Tech Interview Handbook Portal
|
||||
</h2>
|
||||
<p className="mt-2 text-center text-slate-600">
|
||||
Get your resumes peer-reviewed, discuss solutions to tech interview
|
||||
questions, get offer data points.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="space-y-4">
|
||||
{providers != null &&
|
||||
Object.values(providers).map((provider) => (
|
||||
<div key={provider.name}>
|
||||
<Button
|
||||
addonPosition="start"
|
||||
display="block"
|
||||
icon={GitHubIcon}
|
||||
label={`Sign in with ${provider.name}`}
|
||||
type="button"
|
||||
variant="primary"
|
||||
onClick={() =>
|
||||
signIn(
|
||||
provider.id,
|
||||
router.query.redirect != null
|
||||
? {
|
||||
callbackUrl: String(router.query.redirect),
|
||||
}
|
||||
: undefined,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,412 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
function Test() {
|
||||
const [createdData, setCreatedData] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const createMutation = trpc.useMutation(['offers.profile.create'], {
|
||||
onError(err) {
|
||||
alert(err);
|
||||
},
|
||||
onSuccess(data) {
|
||||
setCreatedData(JSON.stringify(data));
|
||||
},
|
||||
});
|
||||
|
||||
const addToUserProfileMutation = trpc.useMutation(
|
||||
['offers.user.profile.addToUserProfile'],
|
||||
{
|
||||
onError(err) {
|
||||
alert(err);
|
||||
},
|
||||
onSuccess(data) {
|
||||
setCreatedData(JSON.stringify(data));
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const deleteCommentMutation = trpc.useMutation(['offers.comments.delete'], {
|
||||
onError(err) {
|
||||
alert(err);
|
||||
},
|
||||
onSuccess(data) {
|
||||
setCreatedData(JSON.stringify(data));
|
||||
},
|
||||
});
|
||||
|
||||
const handleDeleteComment = () => {
|
||||
deleteCommentMutation.mutate({
|
||||
id: 'cl97fprun001j7iyg6ev9x983',
|
||||
profileId: 'cl96stky5002ew32gx2kale2x',
|
||||
token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
|
||||
userId: 'cl97dl51k001e7iygd5v5gt58',
|
||||
});
|
||||
};
|
||||
|
||||
const updateCommentMutation = trpc.useMutation(['offers.comments.update'], {
|
||||
onError(err) {
|
||||
alert(err);
|
||||
},
|
||||
onSuccess(data) {
|
||||
setCreatedData(JSON.stringify(data));
|
||||
},
|
||||
});
|
||||
|
||||
const handleUpdateComment = () => {
|
||||
updateCommentMutation.mutate({
|
||||
id: 'cl97fxb0y001l7iyg14sdobt2',
|
||||
message: 'hello hello',
|
||||
profileId: 'cl96stky5002ew32gx2kale2x',
|
||||
token: 'afca11e436d21bde24543718fa957c6c625335439dc504f24ee35eae7b5ef1ba',
|
||||
});
|
||||
};
|
||||
|
||||
const createCommentMutation = trpc.useMutation(['offers.comments.create'], {
|
||||
onError(err) {
|
||||
alert(err);
|
||||
},
|
||||
onSuccess(data) {
|
||||
setCreatedData(JSON.stringify(data));
|
||||
},
|
||||
});
|
||||
|
||||
const handleCreate = () => {
|
||||
createCommentMutation.mutate({
|
||||
message: 'wassup bro',
|
||||
profileId: 'cl9efyn9p004ww3u42mjgl1vn',
|
||||
replyingToId: 'cl9el4xj10001w3w21o3p2iny',
|
||||
userId: 'cl9ehvpng0000w3ec2mpx0bdd',
|
||||
});
|
||||
};
|
||||
|
||||
const handleLink = () => {
|
||||
addToUserProfileMutation.mutate({
|
||||
profileId: 'cl9efyn9p004ww3u42mjgl1vn',
|
||||
token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
|
||||
// UserId: 'cl9ehvpng0000w3ec2mpx0bdd',
|
||||
});
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
createMutation.mutate({
|
||||
background: {
|
||||
educations: [
|
||||
{
|
||||
endDate: new Date('2018-09-30T07:58:54.000Z'),
|
||||
field: 'Computer Science',
|
||||
school: 'National University of Singapore',
|
||||
startDate: new Date('2014-09-30T07:58:54.000Z'),
|
||||
type: 'Bachelors',
|
||||
},
|
||||
],
|
||||
experiences: [
|
||||
{
|
||||
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
|
||||
durationInMonths: 24,
|
||||
jobType: 'FULLTIME',
|
||||
level: 'Junior',
|
||||
title: 'software-engineer',
|
||||
totalCompensation: {
|
||||
currency: 'SGD',
|
||||
value: 104100,
|
||||
},
|
||||
},
|
||||
],
|
||||
specificYoes: [
|
||||
{
|
||||
domain: 'Front End',
|
||||
yoe: 2,
|
||||
},
|
||||
{
|
||||
domain: 'Full Stack',
|
||||
yoe: 2,
|
||||
},
|
||||
],
|
||||
totalYoe: 4,
|
||||
},
|
||||
offers: [
|
||||
{
|
||||
comments: 'I am a Raffles Institution almumni',
|
||||
// Comments: '',
|
||||
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
|
||||
jobType: 'FULLTIME',
|
||||
location: 'Singapore, Singapore',
|
||||
monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
|
||||
negotiationStrategy: 'Leveraged having multiple offers',
|
||||
offersFullTime: {
|
||||
baseSalary: {
|
||||
currency: 'SGD',
|
||||
value: 2222,
|
||||
},
|
||||
bonus: {
|
||||
currency: 'SGD',
|
||||
value: 2222,
|
||||
},
|
||||
level: 'Junior',
|
||||
stocks: {
|
||||
currency: 'SGD',
|
||||
value: 0,
|
||||
},
|
||||
title: 'software-engineer',
|
||||
totalCompensation: {
|
||||
currency: 'SGD',
|
||||
value: 4444,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
comments: '',
|
||||
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
|
||||
jobType: 'FULLTIME',
|
||||
location: 'Singapore, Singapore',
|
||||
monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
|
||||
negotiationStrategy: 'Leveraged having multiple offers',
|
||||
offersFullTime: {
|
||||
baseSalary: {
|
||||
currency: 'SGD',
|
||||
value: 84000,
|
||||
},
|
||||
bonus: {
|
||||
currency: 'SGD',
|
||||
value: 20000,
|
||||
},
|
||||
level: 'Junior',
|
||||
stocks: {
|
||||
currency: 'SGD',
|
||||
value: 100,
|
||||
},
|
||||
title: 'software-engineer',
|
||||
totalCompensation: {
|
||||
currency: 'SGD',
|
||||
value: 104100,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const profileId = 'cl9j50xzk008vutfqg6mta2ey'; // Remember to change this filed after testing deleting
|
||||
const data = trpc.useQuery(
|
||||
[
|
||||
`offers.profile.listOne`,
|
||||
{
|
||||
profileId,
|
||||
token:
|
||||
'24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
|
||||
},
|
||||
],
|
||||
{
|
||||
onError(err) {
|
||||
setError(err.shape?.message || '');
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
trpc.useQuery(
|
||||
[
|
||||
`offers.profile.isValidToken`,
|
||||
{
|
||||
profileId: 'cl9scdzuh0000tt727ipone1k',
|
||||
token:
|
||||
'aa628d0db3ad7a5f84895537d4cca38edd0a9b8b96d869cddeb967fccf068c08',
|
||||
},
|
||||
],
|
||||
{
|
||||
onError(err) {
|
||||
setError(err.shape?.message || '');
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const replies = trpc.useQuery(
|
||||
['offers.comments.getComments', { profileId }],
|
||||
{
|
||||
onError(err) {
|
||||
setError(err.shape?.message || '');
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const deleteMutation = trpc.useMutation(['offers.profile.delete']);
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
deleteMutation.mutate({
|
||||
profileId: id,
|
||||
token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
|
||||
});
|
||||
};
|
||||
|
||||
const updateMutation = trpc.useMutation(['offers.profile.update'], {
|
||||
onError(err) {
|
||||
alert(err);
|
||||
},
|
||||
onSuccess(response) {
|
||||
setCreatedData(JSON.stringify(response));
|
||||
},
|
||||
});
|
||||
|
||||
const handleUpdate = () => {
|
||||
updateMutation.mutate({
|
||||
background: {
|
||||
educations: [
|
||||
{
|
||||
backgroundId: 'cl9i68fv60001tthj23g9tuv4',
|
||||
endDate: new Date('2018-09-30T07:58:54.000Z'),
|
||||
field: 'Computer Science',
|
||||
id: 'cl9i87y7z004otthjmpsd48wo',
|
||||
school: 'National University of Singapore',
|
||||
startDate: new Date('2014-09-30T07:58:54.000Z'),
|
||||
type: 'Bachelors',
|
||||
},
|
||||
],
|
||||
experiences: [
|
||||
{
|
||||
backgroundId: 'cl9i68fv60001tthj23g9tuv4',
|
||||
company: {
|
||||
createdAt: new Date('2022-10-12T16:19:05.196Z'),
|
||||
description:
|
||||
'Meta Platforms, Inc., doing business as Meta and formerly named Facebook, Inc., and TheFacebook, Inc., is an American multinational technology conglomerate based in Menlo Park, California. The company owns Facebook, Instagram, and WhatsApp, among other products and services.',
|
||||
id: 'cl9j4yawz0003utlp1uaa1t8o',
|
||||
logoUrl: 'https://logo.clearbit.com/meta.com',
|
||||
name: 'Meta',
|
||||
slug: 'meta',
|
||||
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
|
||||
},
|
||||
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
|
||||
durationInMonths: 24,
|
||||
// Id: 'cl9j4yawz0003utlp1uaa1t8o',
|
||||
jobType: 'FULLTIME',
|
||||
level: 'Junior',
|
||||
monthlySalary: null,
|
||||
monthlySalaryId: null,
|
||||
title: 'software-engineer',
|
||||
totalCompensation: {
|
||||
currency: 'SGD',
|
||||
id: 'cl9i68fvc0005tthj7r1rhvb1',
|
||||
value: 100,
|
||||
},
|
||||
totalCompensationId: 'cl9i68fvc0005tthj7r1rhvb1',
|
||||
},
|
||||
],
|
||||
id: 'cl9i68fv60001tthj23g9tuv4',
|
||||
offersProfileId: 'cl9i68fv60000tthj8t3zkox0',
|
||||
specificYoes: [
|
||||
{
|
||||
backgroundId: 'cl9i68fv60001tthj23g9tuv4',
|
||||
domain: 'Backend',
|
||||
id: 'cl9i68fvc0008tthjlxslzfo4',
|
||||
yoe: 5,
|
||||
},
|
||||
{
|
||||
backgroundId: 'cl9i68fv60001tthj23g9tuv4',
|
||||
domain: 'Backend',
|
||||
id: 'cl9i68fvc0009tthjwol3285l',
|
||||
yoe: 4,
|
||||
},
|
||||
],
|
||||
totalYoe: 1,
|
||||
},
|
||||
createdAt: '2022-10-13T08:28:13.518Z',
|
||||
// Discussion: [],
|
||||
id: 'cl9i68fv60000tthj8t3zkox0',
|
||||
isEditable: true,
|
||||
offers: [
|
||||
{
|
||||
comments: 'this IS SO IEUHDAEUIGDI',
|
||||
company: {
|
||||
createdAt: new Date('2022-10-12T16:19:05.196Z'),
|
||||
description:
|
||||
'Meta Platforms, Inc., doing business as Meta and formerly named Facebook, Inc., and TheFacebook, Inc., is an American multinational technology conglomerate based in Menlo Park, California. The company owns Facebook, Instagram, and WhatsApp, among other products and services.',
|
||||
id: 'cl9j4yawz0003utlp1uaa1t8o',
|
||||
logoUrl: 'https://logo.clearbit.com/meta.com',
|
||||
name: 'Meta',
|
||||
slug: 'meta',
|
||||
updatedAt: new Date('2022-10-12T16:19:05.196Z'),
|
||||
},
|
||||
companyId: 'cl9j4yawz0003utlp1uaa1t8o',
|
||||
id: 'cl9i68fve000ntthj5h9yvqnh',
|
||||
jobType: 'FULLTIME',
|
||||
location: 'Singapore, Singapore',
|
||||
monthYearReceived: new Date('2022-09-30T07:58:54.000Z'),
|
||||
negotiationStrategy: 'Charmed the guy with my face',
|
||||
offersFullTime: {
|
||||
baseSalary: {
|
||||
currency: 'SGD',
|
||||
id: 'cl9i68fve000ptthjn55hpoe4',
|
||||
value: 1999999999,
|
||||
},
|
||||
baseSalaryId: 'cl9i68fve000ptthjn55hpoe4',
|
||||
bonus: {
|
||||
currency: 'SGD',
|
||||
id: 'cl9i68fve000rtthjqo2ktljt',
|
||||
value: 1410065407,
|
||||
},
|
||||
bonusId: 'cl9i68fve000rtthjqo2ktljt',
|
||||
id: 'cl9i68fve000otthjqk0g01k0',
|
||||
level: 'EXPERT',
|
||||
stocks: {
|
||||
currency: 'SGD',
|
||||
id: 'cl9i68fvf000ttthjt2ode0cc',
|
||||
value: -558038585,
|
||||
},
|
||||
stocksId: 'cl9i68fvf000ttthjt2ode0cc',
|
||||
title: 'software-engineer',
|
||||
totalCompensation: {
|
||||
currency: 'SGD',
|
||||
id: 'cl9i68fvf000vtthjg90s48nj',
|
||||
value: 55555555,
|
||||
},
|
||||
totalCompensationId: 'cl9i68fvf000vtthjg90s48nj',
|
||||
},
|
||||
offersFullTimeId: 'cl9i68fve000otthjqk0g01k0',
|
||||
offersIntern: null,
|
||||
offersInternId: null,
|
||||
profileId: 'cl9i68fv60000tthj8t3zkox0',
|
||||
},
|
||||
],
|
||||
|
||||
token: '24bafa6fef803f447d7f2e229b14cb8ee43f0c22dffbe41ee1c1e5e6e870f117',
|
||||
userId: null,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>{createdData}</div>
|
||||
<div>{JSON.stringify(replies.data?.data)}</div>
|
||||
<button type="button" onClick={handleClick}>
|
||||
Click Me!
|
||||
</button>
|
||||
<button type="button" onClick={handleUpdate}>
|
||||
UPDATE!
|
||||
</button>
|
||||
<button type="button" onClick={handleLink}>
|
||||
LINKKKK!
|
||||
</button>
|
||||
<button type="button" onClick={handleCreate}>
|
||||
CREATE COMMENT!
|
||||
</button>
|
||||
<button type="button" onClick={handleDeleteComment}>
|
||||
DELETE COMMENT!
|
||||
</button>
|
||||
<button type="button" onClick={handleUpdateComment}>
|
||||
UPDATE COMMENT!
|
||||
</button>
|
||||
<button
|
||||
className="text-danger-600"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
handleDelete(profileId);
|
||||
}}>
|
||||
DELETE THIS PROFILE
|
||||
</button>
|
||||
<div>{JSON.stringify(data.data)}</div>
|
||||
<div>{JSON.stringify(error)}</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Test;
|
@ -1,17 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
function GenerateAnalysis() {
|
||||
const analysisMutation = trpc.useMutation(['offers.analysis.generate']);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{JSON.stringify(
|
||||
analysisMutation.mutate({ profileId: 'cl9lwe9m902k5utskjs52wc0j' }),
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default GenerateAnalysis;
|
@ -1,14 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
function GetAnalysis() {
|
||||
const analysis = trpc.useQuery([
|
||||
'offers.analysis.get',
|
||||
{ profileId: 'cl9lwe9m902k5utskjs52wc0j' },
|
||||
]);
|
||||
|
||||
return <div>{JSON.stringify(analysis.data)}</div>;
|
||||
}
|
||||
|
||||
export default GetAnalysis;
|
@ -1,53 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
function Test() {
|
||||
const data = trpc.useQuery([
|
||||
'offers.list',
|
||||
{
|
||||
currency: 'SGD',
|
||||
limit: 100,
|
||||
location: 'Singapore, Singapore',
|
||||
offset: 0,
|
||||
sortBy: '-totalCompensation',
|
||||
yoeCategory: 1,
|
||||
},
|
||||
]);
|
||||
|
||||
const deleteMutation = trpc.useMutation(['offers.profile.delete']);
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
deleteMutation.mutate({ profileId: id, token: ' dadaadad' });
|
||||
};
|
||||
|
||||
return (
|
||||
<ul>
|
||||
<li>
|
||||
<b>{JSON.stringify(data.data?.paging)}</b>
|
||||
</li>
|
||||
<li>
|
||||
<ul>
|
||||
{data.data?.data.map((offer) => {
|
||||
return (
|
||||
<li key={offer.id}>
|
||||
<button
|
||||
className="text-danger-600"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
handleDelete(offer.profileId);
|
||||
}}>
|
||||
DELETE THIS PROFILE AND ALL ITS OFFERS
|
||||
</button>
|
||||
<div>{JSON.stringify(offer)}</div>
|
||||
<br />
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default Test;
|
@ -0,0 +1,18 @@
|
||||
import type {
|
||||
FilterChoice,
|
||||
FilterOption,
|
||||
} from '~/components/questions/filter/FilterSection';
|
||||
|
||||
export function companyOptionToSlug(option: FilterChoice): string {
|
||||
return `${option.id}_${option.label}`;
|
||||
}
|
||||
|
||||
export function slugToCompanyOption(slug: string): FilterOption {
|
||||
const [id, label] = slug.split('_');
|
||||
return {
|
||||
checked: true,
|
||||
id,
|
||||
label,
|
||||
value: id,
|
||||
};
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import type { TypeaheadOption } from '@tih/ui';
|
||||
|
||||
import type { Location } from '~/types/questions';
|
||||
|
||||
export function locationOptionToSlug(
|
||||
value: Location & TypeaheadOption,
|
||||
): string {
|
||||
return [
|
||||
value.countryId,
|
||||
value.stateId,
|
||||
value.cityId,
|
||||
value.id,
|
||||
value.label,
|
||||
value.value,
|
||||
].join('-');
|
||||
}
|
Loading…
Reference in new issue