diff --git a/apps/portal/src/components/offers/forms/BackgroundForm.tsx b/apps/portal/src/components/offers/forms/BackgroundForm.tsx index 0acbbe69..02d64af7 100644 --- a/apps/portal/src/components/offers/forms/BackgroundForm.tsx +++ b/apps/portal/src/components/offers/forms/BackgroundForm.tsx @@ -1,9 +1,9 @@ import { useFormContext, useWatch } from 'react-hook-form'; import { Collapsible, RadioList } from '@tih/ui'; -import FormRadioList from './FormRadioList'; -import FormSelect from './FormSelect'; -import FormTextInput from './FormTextInput'; +import FormRadioList from './components/FormRadioList'; +import FormSelect from './components/FormSelect'; +import FormTextInput from './components/FormTextInput'; import { companyOptions, educationFieldOptions, diff --git a/apps/portal/src/components/offers/forms/OfferAnalysis.tsx b/apps/portal/src/components/offers/forms/OfferAnalysis.tsx index 3147bdc2..b0b7133c 100644 --- a/apps/portal/src/components/offers/forms/OfferAnalysis.tsx +++ b/apps/portal/src/components/offers/forms/OfferAnalysis.tsx @@ -86,8 +86,7 @@ export default function OfferAnalysis() {
Result
- -
+
; + offers: Array; }>(); return ( @@ -81,10 +82,7 @@ function FullTimeOfferDetailsForm({ required={true} {...register(`offers.${index}.location`, { required: true })} /> -
@@ -121,7 +119,9 @@ function FullTimeOfferDetailsForm({ isLabelHidden={true} label="Currency" options={CURRENCY_OPTIONS} - {...register(`offers.${index}.job.base.currency`)} + {...register(`offers.${index}.job.base.currency`, { + required: true, + })} /> } endAddOnType="element" @@ -131,7 +131,7 @@ function FullTimeOfferDetailsForm({ startAddOn="$" startAddOnType="label" type="number" - {...register(`offers.${index}.job.base.value`)} + {...register(`offers.${index}.job.base.value`, { required: true })} /> } endAddOnType="element" @@ -150,7 +152,7 @@ function FullTimeOfferDetailsForm({ startAddOn="$" startAddOnType="label" type="number" - {...register(`offers.${index}.job.bonus.value`)} + {...register(`offers.${index}.job.bonus.value`, { required: true })} />
@@ -161,7 +163,9 @@ function FullTimeOfferDetailsForm({ isLabelHidden={true} label="Currency" options={CURRENCY_OPTIONS} - {...register(`offers.${index}.job.stocks.currency`)} + {...register(`offers.${index}.job.stocks.currency`, { + required: true, + })} /> } endAddOnType="element" @@ -171,7 +175,7 @@ function FullTimeOfferDetailsForm({ startAddOn="$" startAddOnType="label" type="number" - {...register(`offers.${index}.job.stocks.value`)} + {...register(`offers.${index}.job.stocks.value`, { required: true })} />
@@ -251,7 +255,7 @@ function InternshipOfferDetailsForm({ remove, }: InternshipOfferDetailsFormProps) { const { register } = useFormContext<{ - offers: Array; + offers: Array; }>(); return ( @@ -262,13 +266,19 @@ function InternshipOfferDetailsForm({ label="Title" options={titleOptions} required={true} - {...register(`offers.${index}.job.title`)} + {...register(`offers.${index}.job.title`, { + minLength: 1, + required: true, + })} />
@@ -289,13 +299,7 @@ function InternshipOfferDetailsForm({ {...register(`offers.${index}.location`)} />
-
- +
+
+

Date received:

+ +
; + +type FormMonthYearPickerProps = Omit< + MonthYearPickerProps, + 'onChange' | 'value' +> & { + name: string; +}; + +function FormMonthYearPickerWithRef({ + name, + ...rest +}: FormMonthYearPickerProps) { + const { setValue } = useFormContext(); + + const value = useWatch({ + defaultValue: { month: getCurrentMonth(), year: getCurrentYear() }, + name, + }); + + return ( + { + setValue(name, val); + }} + /> + ); +} + +const FormMonthYearPicker = forwardRef(FormMonthYearPickerWithRef); + +export default FormMonthYearPicker; diff --git a/apps/portal/src/components/offers/forms/FormRadioList.tsx b/apps/portal/src/components/offers/forms/components/FormRadioList.tsx similarity index 100% rename from apps/portal/src/components/offers/forms/FormRadioList.tsx rename to apps/portal/src/components/offers/forms/components/FormRadioList.tsx diff --git a/apps/portal/src/components/offers/forms/FormSelect.tsx b/apps/portal/src/components/offers/forms/components/FormSelect.tsx similarity index 100% rename from apps/portal/src/components/offers/forms/FormSelect.tsx rename to apps/portal/src/components/offers/forms/components/FormSelect.tsx diff --git a/apps/portal/src/components/offers/forms/FormTextArea.tsx b/apps/portal/src/components/offers/forms/components/FormTextArea.tsx similarity index 100% rename from apps/portal/src/components/offers/forms/FormTextArea.tsx rename to apps/portal/src/components/offers/forms/components/FormTextArea.tsx diff --git a/apps/portal/src/components/offers/forms/FormTextInput.tsx b/apps/portal/src/components/offers/forms/components/FormTextInput.tsx similarity index 100% rename from apps/portal/src/components/offers/forms/FormTextInput.tsx rename to apps/portal/src/components/offers/forms/components/FormTextInput.tsx diff --git a/apps/portal/src/components/offers/types.ts b/apps/portal/src/components/offers/types.ts index 17bda427..b514744e 100644 --- a/apps/portal/src/components/offers/types.ts +++ b/apps/portal/src/components/offers/types.ts @@ -3,6 +3,8 @@ * Offer Profile */ +import type { MonthYear } from '../shared/MonthYearPicker'; + export enum JobType { FullTime = 'FULLTIME', Internship = 'INTERNSHIP', @@ -33,16 +35,6 @@ type FullTimeJobData = { totalCompensation: Money; }; -export type FullTimeOfferFormData = { - comments: string; - companyId: string; - job: FullTimeJobData; - jobType: string; - location: string; - monthYearReceived: string; - negotiationStrategy: string; -}; - type InternshipJobData = { internshipCycle: string; monthlySalary: Money; @@ -51,18 +43,16 @@ type InternshipJobData = { title: string; }; -export type InternshipOfferFormData = { +export type OfferDetailsFormData = { comments: string; companyId: string; - job: InternshipJobData; + job: FullTimeJobData | InternshipJobData; jobType: string; location: string; - monthYearReceived: string; + monthYearReceived: MonthYear; negotiationStrategy: string; }; -type OfferDetailsFormData = FullTimeOfferFormData | InternshipOfferFormData; - type SpecificYoe = { domain: string; yoe: number; diff --git a/apps/portal/src/components/offers/util/time/index.tsx b/apps/portal/src/components/offers/util/time/index.tsx index 86f21ab9..c13a6efe 100644 --- a/apps/portal/src/components/offers/util/time/index.tsx +++ b/apps/portal/src/components/offers/util/time/index.tsx @@ -1,3 +1,7 @@ +import { getMonth, getYear } from 'date-fns'; + +import type { MonthYear } from '~/components/shared/MonthYearPicker'; + export function formatDate(value: Date | number | string) { const date = new Date(value); // Const day = date.toLocaleString('default', { day: '2-digit' }); @@ -5,3 +9,17 @@ export function formatDate(value: Date | number | string) { const year = date.toLocaleString('default', { year: 'numeric' }); return `${month} ${year}`; } + +export function formatMonthYear({ month, year }: MonthYear) { + const monthString = month < 10 ? month.toString() : `0${month}`; + const yearString = year.toString(); + return `${monthString}/${yearString}`; +} + +export function getCurrentMonth() { + return getMonth(Date.now()); +} + +export function getCurrentYear() { + return getYear(Date.now()); +} diff --git a/apps/portal/src/pages/offers/index.tsx b/apps/portal/src/pages/offers/index.tsx index 27166716..c4dfe8b5 100644 --- a/apps/portal/src/pages/offers/index.tsx +++ b/apps/portal/src/pages/offers/index.tsx @@ -3,9 +3,11 @@ import { Select } from '@tih/ui'; import OffersTable from '~/components/offers/OffersTable'; 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 [companyFilter, setCompanyFilter] = useState('All companies'); return ( @@ -13,7 +15,7 @@ export default function OffersHomePage() {
-
+
Viewing offers for
setCompanyFilter(value)} />
diff --git a/apps/portal/src/pages/offers/submit.tsx b/apps/portal/src/pages/offers/submit.tsx index b85e098c..05b25555 100644 --- a/apps/portal/src/pages/offers/submit.tsx +++ b/apps/portal/src/pages/offers/submit.tsx @@ -9,6 +9,8 @@ import OfferAnalysis from '~/components/offers/forms/OfferAnalysis'; import OfferDetailsForm from '~/components/offers/forms/OfferDetailsForm'; import OfferProfileSave from '~/components/offers/forms/OfferProfileSave'; import type { SubmitOfferFormData } from '~/components/offers/types'; +import { getCurrentMonth, getCurrentYear } from '~/components/offers/util/time'; +import type { Month } from '~/components/shared/MonthYearPicker'; function Breadcrumbs() { return ( @@ -23,53 +25,69 @@ const defaultOfferValues = { { comments: '', companyId: '', - job: { - base: { - currency: 'USD', - value: 0, - }, - bonus: { - currency: 'USD', - value: 0, - }, - level: '', - specialization: '', - stocks: { - currency: 'USD', - value: 0, - }, - title: '', - totalCompensation: { - currency: 'USD', - value: 0, - }, - }, + job: {}, jobType: 'FULLTIME', location: '', - monthYearReceived: '', + monthYearReceived: { + month: getCurrentMonth() as Month, + year: getCurrentYear(), + }, negotiationStrategy: '', }, ], }; +type FormStep = { + component: JSX.Element; + hasNext: boolean; + hasPrevious: boolean; +}; + export default function OffersSubmissionPage() { const [formStep, setFormStep] = useState(0); const formMethods = useForm({ defaultValues: defaultOfferValues, + mode: 'all', }); + const { handleSubmit, trigger } = formMethods; - const nextStep = () => setFormStep(formStep + 1); - const previousStep = () => setFormStep(formStep - 1); - - const formComponents = [ - , - , - , - , + const formSteps: Array = [ + { + component: , + hasNext: true, + hasPrevious: false, + }, + { + component: , + hasNext: false, + hasPrevious: true, + }, + { component: , hasNext: true, hasPrevious: false }, + { + component: , + hasNext: false, + hasPrevious: false, + }, ]; + const nextStep = async (currStep: number) => { + if (currStep === 0) { + const result = await trigger('offers'); + if (!result) { + return; + } + } + setFormStep(formStep + 1); + }; + + const previousStep = () => setFormStep(formStep - 1); + const onSubmit: SubmitHandler = async () => { - nextStep(); + const result = await trigger(); + if (!result) { + return; + } + setFormStep(formStep + 1); }; return ( @@ -78,16 +96,17 @@ export default function OffersSubmissionPage() {
-
- {formComponents[formStep]} + + {formSteps[formStep].component} {/*
{JSON.stringify(formMethods.watch(), null, 2)}
*/} - {(formStep === 0 || formStep === 2) && ( + {formSteps[formStep].hasNext && (
)}