mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2026-02-03 02:24:47 +08:00
[offers][feat] Add currency detection in forms (#542)
* [offers][feat] Tweak OEA text * [offers][feat] Add currency detection in forms
This commit is contained in:
@@ -58,9 +58,9 @@ function OfferAnalysisContent({
|
||||
tab={tab}
|
||||
/>
|
||||
<p className="mt-5">
|
||||
{isSubmission
|
||||
? 'Here are some of the top offers relevant to you:'
|
||||
: 'Relevant top offers:'}
|
||||
{tab === OVERALL_TAB
|
||||
? 'Here are some of the highest offers with the same job title and YOE(±1):'
|
||||
: 'Here are some of the highest offers with the same company, job title and YOE(±1):'}
|
||||
</p>
|
||||
{analysis.topPercentileOffers.map((topPercentileOffer) => (
|
||||
<OfferProfileCard
|
||||
|
||||
@@ -18,7 +18,10 @@ import type {
|
||||
} from '~/components/offers/types';
|
||||
import type { Month } from '~/components/shared/MonthYearPicker';
|
||||
|
||||
import { Currency } from '~/utils/offers/currency/CurrencyEnum';
|
||||
import {
|
||||
Currency,
|
||||
getCurrencyForCountry,
|
||||
} from '~/utils/offers/currency/CurrencyEnum';
|
||||
import {
|
||||
cleanObject,
|
||||
removeEmptyObjects,
|
||||
@@ -85,6 +88,7 @@ const defaultOfferProfileValues: OffersProfileFormData = {
|
||||
};
|
||||
|
||||
type Props = Readonly<{
|
||||
country: string | null;
|
||||
initialOfferProfileValues?: OffersProfileFormData;
|
||||
profileId?: string;
|
||||
token?: string;
|
||||
@@ -94,6 +98,7 @@ export default function OffersSubmissionForm({
|
||||
initialOfferProfileValues = defaultOfferProfileValues,
|
||||
profileId: editProfileId = '',
|
||||
token: editToken = '',
|
||||
country,
|
||||
}: Props) {
|
||||
const [step, setStep] = useState(0);
|
||||
const [params, setParams] = useState({
|
||||
@@ -137,7 +142,12 @@ export default function OffersSubmissionForm({
|
||||
},
|
||||
);
|
||||
|
||||
const steps = [<OfferDetailsForm key={0} />, <BackgroundForm key={1} />];
|
||||
const defaultCurrency = getCurrencyForCountry(country).toString();
|
||||
|
||||
const steps = [
|
||||
<OfferDetailsForm key={0} defaultCurrency={defaultCurrency} />,
|
||||
<BackgroundForm key={1} defaultCurrency={defaultCurrency} />,
|
||||
];
|
||||
|
||||
const breadcrumbSteps: Array<BreadcrumbStep> = [
|
||||
{
|
||||
|
||||
@@ -5,10 +5,7 @@ import { Collapsible, RadioList } from '@tih/ui';
|
||||
import { FieldError } from '~/components/offers/constants';
|
||||
import type { BackgroundPostData } from '~/components/offers/types';
|
||||
|
||||
import {
|
||||
Currency,
|
||||
CURRENCY_OPTIONS,
|
||||
} from '~/utils/offers/currency/CurrencyEnum';
|
||||
import { CURRENCY_OPTIONS } from '~/utils/offers/currency/CurrencyEnum';
|
||||
|
||||
import { EducationFieldOptions } from '../../EducationFields';
|
||||
import { EducationLevelOptions } from '../../EducationLevels';
|
||||
@@ -82,7 +79,11 @@ function YoeSection() {
|
||||
);
|
||||
}
|
||||
|
||||
function FullTimeJobFields() {
|
||||
type FullTimeJobFieldsProps = Readonly<{
|
||||
defaultCurrency: string;
|
||||
}>;
|
||||
|
||||
function FullTimeJobFields({ defaultCurrency }: FullTimeJobFieldsProps) {
|
||||
const { register, formState } = useFormContext<{
|
||||
background: BackgroundPostData;
|
||||
}>();
|
||||
@@ -104,7 +105,7 @@ function FullTimeJobFields() {
|
||||
endAddOn={
|
||||
<FormSelect
|
||||
borderStyle="borderless"
|
||||
defaultValue={Currency.SGD}
|
||||
defaultValue={defaultCurrency}
|
||||
isLabelHidden={true}
|
||||
label="Currency"
|
||||
options={CURRENCY_OPTIONS}
|
||||
@@ -154,7 +155,11 @@ function FullTimeJobFields() {
|
||||
);
|
||||
}
|
||||
|
||||
function InternshipJobFields() {
|
||||
type InternshipJobFieldsProps = Readonly<{
|
||||
defaultCurrency: string;
|
||||
}>;
|
||||
|
||||
function InternshipJobFields({ defaultCurrency }: InternshipJobFieldsProps) {
|
||||
const { register, formState } = useFormContext<{
|
||||
background: BackgroundPostData;
|
||||
}>();
|
||||
@@ -175,7 +180,7 @@ function InternshipJobFields() {
|
||||
endAddOn={
|
||||
<FormSelect
|
||||
borderStyle="borderless"
|
||||
defaultValue={Currency.SGD}
|
||||
defaultValue={defaultCurrency}
|
||||
isLabelHidden={true}
|
||||
label="Currency"
|
||||
options={CURRENCY_OPTIONS}
|
||||
@@ -217,7 +222,11 @@ function InternshipJobFields() {
|
||||
);
|
||||
}
|
||||
|
||||
function CurrentJobSection() {
|
||||
type CurrentJobSectionProps = Readonly<{
|
||||
defaultCurrency: string;
|
||||
}>;
|
||||
|
||||
function CurrentJobSection({ defaultCurrency }: CurrentJobSectionProps) {
|
||||
const { register } = useFormContext();
|
||||
const watchJobType = useWatch({
|
||||
name: 'background.experiences.0.jobType',
|
||||
@@ -243,9 +252,9 @@ function CurrentJobSection() {
|
||||
/>
|
||||
</FormRadioList>
|
||||
{watchJobType === JobType.FULLTIME ? (
|
||||
<FullTimeJobFields />
|
||||
<FullTimeJobFields defaultCurrency={defaultCurrency} />
|
||||
) : (
|
||||
<InternshipJobFields />
|
||||
<InternshipJobFields defaultCurrency={defaultCurrency} />
|
||||
)}
|
||||
</FormSection>
|
||||
);
|
||||
@@ -280,7 +289,13 @@ function EducationSection() {
|
||||
);
|
||||
}
|
||||
|
||||
export default function BackgroundForm() {
|
||||
type BackgroundFormProps = Readonly<{
|
||||
defaultCurrency: string;
|
||||
}>;
|
||||
|
||||
export default function BackgroundForm({
|
||||
defaultCurrency,
|
||||
}: BackgroundFormProps) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<h2 className="mb-8 text-2xl font-bold text-slate-900 sm:text-center sm:text-4xl">
|
||||
@@ -288,7 +303,7 @@ export default function BackgroundForm() {
|
||||
</h2>
|
||||
<div className="space-y-8 rounded-lg border border-slate-200 p-6 sm:space-y-16 sm:p-8">
|
||||
<YoeSection />
|
||||
<CurrentJobSection />
|
||||
<CurrentJobSection defaultCurrency={defaultCurrency} />
|
||||
<EducationSection />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,12 +30,10 @@ import { InternshipCycleOptions } from '../../InternshipCycles';
|
||||
import JobTypeTabs from '../../JobTypeTabs';
|
||||
import type { OfferFormData } from '../../types';
|
||||
import { FutureYearsOptions } from '../../Years';
|
||||
import {
|
||||
Currency,
|
||||
CURRENCY_OPTIONS,
|
||||
} from '../../../../utils/offers/currency/CurrencyEnum';
|
||||
import { CURRENCY_OPTIONS } from '../../../../utils/offers/currency/CurrencyEnum';
|
||||
|
||||
type FullTimeOfferDetailsFormProps = Readonly<{
|
||||
defaultCurrency: string;
|
||||
index: number;
|
||||
remove: UseFieldArrayRemove;
|
||||
}>;
|
||||
@@ -43,6 +41,7 @@ type FullTimeOfferDetailsFormProps = Readonly<{
|
||||
function FullTimeOfferDetailsForm({
|
||||
index,
|
||||
remove,
|
||||
defaultCurrency,
|
||||
}: FullTimeOfferDetailsFormProps) {
|
||||
const { register, formState, setValue, control } = useFormContext<{
|
||||
offers: Array<OfferFormData>;
|
||||
@@ -135,7 +134,7 @@ function FullTimeOfferDetailsForm({
|
||||
endAddOn={
|
||||
<FormSelect
|
||||
borderStyle="borderless"
|
||||
defaultValue={Currency.SGD}
|
||||
defaultValue={defaultCurrency}
|
||||
isLabelHidden={true}
|
||||
label="Currency"
|
||||
options={CURRENCY_OPTIONS}
|
||||
@@ -172,7 +171,7 @@ function FullTimeOfferDetailsForm({
|
||||
endAddOn={
|
||||
<FormSelect
|
||||
borderStyle="borderless"
|
||||
defaultValue={Currency.SGD}
|
||||
defaultValue={defaultCurrency}
|
||||
isLabelHidden={true}
|
||||
label="Currency"
|
||||
options={CURRENCY_OPTIONS}
|
||||
@@ -199,7 +198,7 @@ function FullTimeOfferDetailsForm({
|
||||
endAddOn={
|
||||
<FormSelect
|
||||
borderStyle="borderless"
|
||||
defaultValue={Currency.SGD}
|
||||
defaultValue={defaultCurrency}
|
||||
isLabelHidden={true}
|
||||
label="Currency"
|
||||
options={CURRENCY_OPTIONS}
|
||||
@@ -222,7 +221,7 @@ function FullTimeOfferDetailsForm({
|
||||
endAddOn={
|
||||
<FormSelect
|
||||
borderStyle="borderless"
|
||||
defaultValue={Currency.SGD}
|
||||
defaultValue={defaultCurrency}
|
||||
isLabelHidden={true}
|
||||
label="Currency"
|
||||
options={CURRENCY_OPTIONS}
|
||||
@@ -275,6 +274,7 @@ function FullTimeOfferDetailsForm({
|
||||
}
|
||||
|
||||
type InternshipOfferDetailsFormProps = Readonly<{
|
||||
defaultCurrency: string;
|
||||
index: number;
|
||||
remove: UseFieldArrayRemove;
|
||||
}>;
|
||||
@@ -282,6 +282,7 @@ type InternshipOfferDetailsFormProps = Readonly<{
|
||||
function InternshipOfferDetailsForm({
|
||||
index,
|
||||
remove,
|
||||
defaultCurrency,
|
||||
}: InternshipOfferDetailsFormProps) {
|
||||
const { register, formState, control } = useFormContext<{
|
||||
offers: Array<OfferFormData>;
|
||||
@@ -373,7 +374,7 @@ function InternshipOfferDetailsForm({
|
||||
endAddOn={
|
||||
<FormSelect
|
||||
borderStyle="borderless"
|
||||
defaultValue={Currency.SGD}
|
||||
defaultValue={defaultCurrency}
|
||||
isLabelHidden={true}
|
||||
label="Currency"
|
||||
options={CURRENCY_OPTIONS}
|
||||
@@ -435,6 +436,7 @@ function InternshipOfferDetailsForm({
|
||||
}
|
||||
|
||||
type OfferDetailsFormArrayProps = Readonly<{
|
||||
defaultCurrency: string;
|
||||
fieldArrayValues: UseFieldArrayReturn<FieldValues, 'offers', 'id'>;
|
||||
jobType: JobType;
|
||||
}>;
|
||||
@@ -442,6 +444,7 @@ type OfferDetailsFormArrayProps = Readonly<{
|
||||
function OfferDetailsFormArray({
|
||||
fieldArrayValues,
|
||||
jobType,
|
||||
defaultCurrency,
|
||||
}: OfferDetailsFormArrayProps) {
|
||||
const { append, remove, fields } = fieldArrayValues;
|
||||
|
||||
@@ -451,9 +454,17 @@ function OfferDetailsFormArray({
|
||||
return (
|
||||
<div key={item.id}>
|
||||
{jobType === JobType.FULLTIME ? (
|
||||
<FullTimeOfferDetailsForm index={index} remove={remove} />
|
||||
<FullTimeOfferDetailsForm
|
||||
defaultCurrency={defaultCurrency}
|
||||
index={index}
|
||||
remove={remove}
|
||||
/>
|
||||
) : (
|
||||
<InternshipOfferDetailsForm index={index} remove={remove} />
|
||||
<InternshipOfferDetailsForm
|
||||
defaultCurrency={defaultCurrency}
|
||||
index={index}
|
||||
remove={remove}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@@ -476,7 +487,13 @@ function OfferDetailsFormArray({
|
||||
);
|
||||
}
|
||||
|
||||
export default function OfferDetailsForm() {
|
||||
type OfferDetailsFormProps = Readonly<{
|
||||
defaultCurrency: string;
|
||||
}>;
|
||||
|
||||
export default function OfferDetailsForm({
|
||||
defaultCurrency,
|
||||
}: OfferDetailsFormProps) {
|
||||
const watchJobType = useWatch({
|
||||
name: `offers.0.jobType`,
|
||||
});
|
||||
@@ -515,6 +532,7 @@ export default function OfferDetailsForm() {
|
||||
}}
|
||||
/>
|
||||
<OfferDetailsFormArray
|
||||
defaultCurrency={defaultCurrency}
|
||||
fieldArrayValues={fieldArrayValues}
|
||||
jobType={jobType}
|
||||
/>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { GetServerSideProps, InferGetServerSidePropsType } from 'next';
|
||||
import Error from 'next/error';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -14,7 +15,17 @@ import { getProfilePath } from '~/utils/offers/link';
|
||||
import { convertToMonthYear } from '~/utils/offers/time';
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
export default function OffersEditPage() {
|
||||
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
|
||||
return {
|
||||
props: {
|
||||
country: req.cookies.country ?? null,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default function OffersEditPage({
|
||||
country,
|
||||
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
const [initialData, setInitialData] = useState<OffersProfileFormData>();
|
||||
const router = useRouter();
|
||||
const { offerProfileId, token = '' } = router.query;
|
||||
@@ -104,6 +115,7 @@ export default function OffersEditPage() {
|
||||
)}
|
||||
{!getProfileResult.isLoading && initialData && (
|
||||
<OffersSubmissionForm
|
||||
country={country}
|
||||
initialOfferProfileValues={initialData}
|
||||
profileId={profile?.id}
|
||||
token={profile?.editToken || undefined}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import Head from 'next/head';
|
||||
|
||||
import OffersSubmissionForm from '~/components/offers/offersSubmission/OffersSubmissionForm';
|
||||
|
||||
export default function OffersSubmissionPage() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Analyze your offers</title>
|
||||
</Head>
|
||||
<OffersSubmissionForm />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,25 @@
|
||||
import type { GetServerSideProps, InferGetServerSidePropsType } from 'next';
|
||||
import Head from 'next/head';
|
||||
|
||||
import OffersSubmissionForm from '~/components/offers/offersSubmission/OffersSubmissionForm';
|
||||
|
||||
export default function OffersSubmissionPage() {
|
||||
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
|
||||
return {
|
||||
props: {
|
||||
country: req.cookies.country ?? null,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default function OffersSubmissionPage({
|
||||
country,
|
||||
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Analyze your offers</title>
|
||||
</Head>
|
||||
<OffersSubmissionForm />
|
||||
<OffersSubmissionForm country={country} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user