[offers][feat] tweak offer background submission form

pull/490/head
Yangshun Tay 3 years ago
parent 6682d81d2e
commit 87efcc3932

@ -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>
);
}

@ -264,10 +264,10 @@ export default function OffersSubmissionForm({
}, []);
return (
<div ref={pageRef} className="fixed h-full w-full overflow-y-scroll">
<div className="mb-20 flex justify-center">
<div className="my-5 block w-full max-w-screen-md rounded-lg bg-white py-10 px-10 shadow-lg">
<div className="mb-4 flex justify-end">
<div ref={pageRef} className="w-full overflow-y-scroll">
<div className="flex justify-center">
<div className="block w-full max-w-screen-md rounded-lg bg-white p-6 sm:p-10 sm:shadow-lg md:my-10">
<div className="mb-8 flex justify-end">
<Breadcrumbs
currentStep={step}
setStep={setStep}
@ -300,6 +300,7 @@ export default function OffersSubmissionForm({
{step === 1 && (
<div className="flex items-center justify-between">
<Button
addonPosition="start"
icon={ArrowLeftIcon}
label="Previous"
variant="secondary"
@ -314,6 +315,7 @@ export default function OffersSubmissionForm({
/>
<Button
disabled={isSubmitting || isSubmitSuccessful}
icon={ArrowRightIcon}
isLoading={isSubmitting || isSubmitSuccessful}
label="Submit"
type="submit"

@ -21,6 +21,7 @@ import {
} from '~/utils/offers/currency/CurrencyEnum';
import FormRadioList from '../../forms/FormRadioList';
import FormSection from '../../forms/FormSection';
import FormSelect from '../../forms/FormSelect';
import FormTextInput from '../../forms/FormTextInput';
@ -29,29 +30,26 @@ function YoeSection() {
background: BackgroundPostData;
}>();
const backgroundFields = formState.errors.background;
return (
<>
<h6 className="mb-2 text-left text-xl font-medium text-slate-400">
Years of Experience (YOE)
</h6>
<div className="mb-5 rounded-lg border border-slate-200 px-10 py-5">
<div className="mb-2 grid grid-cols-3 space-x-3">
<FormTextInput
errorMessage={backgroundFields?.totalYoe?.message}
label="Total YOE"
placeholder="0"
required={true}
type="number"
{...register(`background.totalYoe`, {
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
required: FieldError.REQUIRED,
valueAsNumber: true,
})}
/>
</div>
<Collapsible label="Add specific YOEs by domain">
<div className="mb-5 grid grid-cols-2 space-x-3">
return (
<FormSection title="Years of Experience (YOE)">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<FormTextInput
errorMessage={backgroundFields?.totalYoe?.message}
label="Total YOE"
placeholder="0"
required={true}
type="number"
{...register(`background.totalYoe`, {
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
required: FieldError.REQUIRED,
valueAsNumber: true,
})}
/>
</div>
<Collapsible label="Add specific YOEs by domain">
<div className="space-y-4 sm:space-y-6">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<FormTextInput
errorMessage={backgroundFields?.specificYoes?.[0]?.yoe?.message}
label="Specific YOE 1"
@ -63,11 +61,11 @@ function YoeSection() {
/>
<FormTextInput
label="Specific Domain 1"
placeholder="e.g. Frontend"
placeholder="e.g. Front End"
{...register(`background.specificYoes.0.domain`)}
/>
</div>
<div className="mb-5 grid grid-cols-2 space-x-3">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<FormTextInput
errorMessage={backgroundFields?.specificYoes?.[1]?.yoe?.message}
label="Specific YOE 2"
@ -79,13 +77,13 @@ function YoeSection() {
/>
<FormTextInput
label="Specific Domain 2"
placeholder="e.g. Backend"
placeholder="e.g. Back End"
{...register(`background.specificYoes.1.domain`)}
/>
</div>
</Collapsible>
</div>
</>
</div>
</Collapsible>
</FormSection>
);
}
@ -107,38 +105,34 @@ function FullTimeJobFields() {
return (
<>
<div className="mb-5 grid grid-cols-2 space-x-3">
<div>
<JobTitlesTypeahead
value={{
id: watchJobTitle,
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
value: watchJobTitle,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.title', option.value);
}
}}
/>
</div>
<div>
<CompaniesTypeahead
value={{
id: watchCompanyId,
label: watchCompanyName,
value: watchCompanyId,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.companyId', option.value);
setValue('background.experiences.0.companyName', option.label);
}
}}
/>
</div>
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<JobTitlesTypeahead
value={{
id: watchJobTitle,
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
value: watchJobTitle,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.title', option.value);
}
}}
/>
<CompaniesTypeahead
value={{
id: watchCompanyId,
label: watchCompanyName,
value: watchCompanyId,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.companyId', option.value);
setValue('background.experiences.0.companyName', option.label);
}
}}
/>
</div>
<div className="mb-5 grid grid-cols-1 space-x-3">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<FormTextInput
endAddOn={
<FormSelect
@ -166,7 +160,7 @@ function FullTimeJobFields() {
/>
</div>
<Collapsible label="Add more details">
<div className="mb-5 grid grid-cols-2 space-x-3">
<div className="grid grid-cols-1 gap-6 sm:grid-cols-3">
<FormTextInput
label="Level"
placeholder="e.g. L4, Junior"
@ -178,8 +172,6 @@ function FullTimeJobFields() {
options={locationOptions}
{...register(`background.experiences.0.location`)}
/>
</div>
<div className="mb-5 grid grid-cols-2 space-x-3">
<FormTextInput
errorMessage={experiencesField?.durationInMonths?.message}
label="Duration (months)"
@ -213,72 +205,64 @@ function InternshipJobFields() {
return (
<>
<div className="mb-5 grid grid-cols-2 space-x-3">
<div>
<JobTitlesTypeahead
value={{
id: watchJobTitle,
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
value: watchJobTitle,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.title', option.value);
}
}}
/>
</div>
<div>
<CompaniesTypeahead
value={{
id: watchCompanyId,
label: watchCompanyName,
value: watchCompanyId,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.companyId', option.value);
setValue('background.experiences.0.companyName', option.label);
}
}}
/>
</div>
</div>
<div className="mb-5 grid grid-cols-1 space-x-3">
<FormTextInput
endAddOn={
<FormSelect
borderStyle="borderless"
defaultValue={Currency.SGD}
isLabelHidden={true}
label="Currency"
options={CURRENCY_OPTIONS}
{...register(`background.experiences.0.monthlySalary.currency`)}
/>
}
endAddOnType="element"
errorMessage={experiencesField?.monthlySalary?.value?.message}
label="Salary (Monthly)"
placeholder="0.00"
startAddOn="$"
startAddOnType="label"
type="number"
{...register(`background.experiences.0.monthlySalary.value`, {
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
valueAsNumber: true,
})}
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<JobTitlesTypeahead
value={{
id: watchJobTitle,
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
value: watchJobTitle,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.title', option.value);
}
}}
/>
<CompaniesTypeahead
value={{
id: watchCompanyId,
label: watchCompanyName,
value: watchCompanyId,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.companyId', option.value);
setValue('background.experiences.0.companyName', option.label);
}
}}
/>
</div>
<Collapsible label="Add more details">
<div className="mb-5 grid grid-cols-2 space-x-3">
<FormTextInput
endAddOn={
<FormSelect
display="block"
label="Location"
options={locationOptions}
placeholder={emptyOption}
{...register(`background.experiences.0.location`)}
borderStyle="borderless"
defaultValue={Currency.SGD}
isLabelHidden={true}
label="Currency"
options={CURRENCY_OPTIONS}
{...register(`background.experiences.0.monthlySalary.currency`)}
/>
</div>
}
endAddOnType="element"
errorMessage={experiencesField?.monthlySalary?.value?.message}
label="Salary (Monthly)"
placeholder="0.00"
startAddOn="$"
startAddOnType="label"
type="number"
{...register(`background.experiences.0.monthlySalary.value`, {
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
valueAsNumber: true,
})}
/>
<Collapsible label="Add more details">
<FormSelect
display="block"
label="Location"
options={locationOptions}
placeholder={emptyOption}
{...register(`background.experiences.0.location`)}
/>
</Collapsible>
</>
);
@ -291,85 +275,71 @@ function CurrentJobSection() {
});
return (
<>
<h6 className="mb-2 text-left text-xl font-medium text-slate-400">
Current / Previous Job
</h6>
<div className="mb-5 rounded-lg border border-slate-200 px-10 py-5">
<div className="mb-5">
<FormRadioList
defaultValue={watchJobType}
isLabelHidden={true}
label="Job Type"
orientation="horizontal"
{...register('background.experiences.0.jobType')}>
<RadioList.Item
key="Full-time"
label="Full-time"
value={JobType.FULLTIME}
/>
<RadioList.Item
key="Internship"
label="Internship"
value={JobType.INTERN}
/>
</FormRadioList>
</div>
{watchJobType === JobType.FULLTIME ? (
<FullTimeJobFields />
) : (
<InternshipJobFields />
)}
</div>
</>
<FormSection title="Current / Previous Job">
<FormRadioList
defaultValue={watchJobType}
isLabelHidden={true}
label="Job Type"
orientation="horizontal"
{...register('background.experiences.0.jobType')}>
<RadioList.Item
key="Full-time"
label="Full-time"
value={JobType.FULLTIME}
/>
<RadioList.Item
key="Internship"
label="Internship"
value={JobType.INTERN}
/>
</FormRadioList>
{watchJobType === JobType.FULLTIME ? (
<FullTimeJobFields />
) : (
<InternshipJobFields />
)}
</FormSection>
);
}
function EducationSection() {
const { register } = useFormContext();
return (
<>
<h6 className="mb-2 text-left text-xl font-medium text-slate-400">
Education
</h6>
<div className="mb-5 rounded-lg border border-slate-200 px-10 py-5">
<div className="mb-5 grid grid-cols-2 space-x-3">
<FormSelect
display="block"
label="Education Level"
options={educationLevelOptions}
placeholder={emptyOption}
{...register(`background.educations.0.type`)}
/>
<FormSelect
display="block"
label="Field"
options={educationFieldOptions}
placeholder={emptyOption}
{...register(`background.educations.0.field`)}
/>
</div>
<Collapsible label="Add more details">
<div className="mb-5">
<FormTextInput
label="School"
placeholder="e.g. National University of Singapore"
{...register(`background.educations.0.school`)}
/>
</div>
</Collapsible>
<FormSection title="Education">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<FormSelect
display="block"
label="Education Level"
options={educationLevelOptions}
placeholder={emptyOption}
{...register(`background.educations.0.type`)}
/>
<FormSelect
display="block"
label="Field"
options={educationFieldOptions}
placeholder={emptyOption}
{...register(`background.educations.0.field`)}
/>
</div>
</>
<Collapsible label="Add more details">
<FormTextInput
label="School"
placeholder="e.g. National University of Singapore"
{...register(`background.educations.0.school`)}
/>
</Collapsible>
</FormSection>
);
}
export default function BackgroundForm() {
return (
<div>
<h5 className="mb-8 text-center text-4xl font-bold text-slate-900">
<div className="space-y-6">
<h2 className="mb-8 text-2xl font-bold text-slate-900 sm:text-center sm:text-4xl">
Help us better gauge your offers
</h5>
<div>
</h2>
<div className="space-y-8 rounded-lg border border-slate-200 p-6 sm:space-y-16 sm:p-8">
<YoeSection />
<CurrentJobSection />
<EducationSection />

@ -29,6 +29,7 @@ import {
yearOptions,
} from '../../constants';
import FormMonthYearPicker from '../../forms/FormMonthYearPicker';
import FormSection from '../../forms/FormSection';
import FormSelect from '../../forms/FormSelect';
import FormTextArea from '../../forms/FormTextArea';
import FormTextInput from '../../forms/FormTextInput';
@ -45,23 +46,6 @@ type FullTimeOfferDetailsFormProps = Readonly<{
remove: UseFieldArrayRemove;
}>;
function Section({
children,
title,
}: Readonly<{ children: React.ReactNode; title: string }>) {
return (
<div>
<div className="mb-4">
<h3 className="text-lg font-medium leading-6 text-slate-900">
{title}
</h3>
<HorizontalDivider />
</div>
<div className="space-y-4 sm:space-y-6">{children}</div>
</div>
);
}
function FullTimeOfferDetailsForm({
index,
remove,
@ -95,8 +79,8 @@ function FullTimeOfferDetailsForm({
return (
<div className="space-y-8 rounded-lg border border-slate-200 p-6 sm:space-y-16 sm:p-8">
<Section title="Company & Title Information">
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
<FormSection title="Company & Title Information">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<JobTitlesTypeahead
required={true}
value={{
@ -120,7 +104,7 @@ function FullTimeOfferDetailsForm({
})}
/>
</div>
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<CompaniesTypeahead
required={true}
value={{
@ -147,9 +131,9 @@ function FullTimeOfferDetailsForm({
})}
/>
</div>
</Section>
<Section title="Compensation Details">
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
</FormSection>
<FormSection title="Compensation Details">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<FormMonthYearPicker
monthLabel="Date Received"
monthRequired={true}
@ -269,8 +253,8 @@ function FullTimeOfferDetailsForm({
})}
/>
</div>
</Section>
<Section title="Additional Information">
</FormSection>
<FormSection title="Additional Information">
<FormTextArea
label="Negotiation Strategy / Interview Performance"
placeholder="e.g. Did well in the behavioral interview / Used competing offers to negotiate for a higher salary"
@ -296,7 +280,7 @@ function FullTimeOfferDetailsForm({
</div>
</div>
)}
</Section>
</FormSection>
</div>
);
}
@ -327,7 +311,7 @@ function InternshipOfferDetailsForm({
return (
<div className="space-y-8 rounded-lg border border-slate-200 p-6 sm:space-y-16 sm:p-8">
<Section title="Company & Title Information">
<FormSection title="Company & Title Information">
<JobTitlesTypeahead
required={true}
value={{
@ -342,7 +326,7 @@ function InternshipOfferDetailsForm({
}}
/>
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<CompaniesTypeahead
required={true}
value={{
@ -369,7 +353,7 @@ function InternshipOfferDetailsForm({
})}
/>
</div>
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<FormSelect
display="block"
errorMessage={offerFields?.offersIntern?.internshipCycle?.message}
@ -394,9 +378,9 @@ function InternshipOfferDetailsForm({
})}
/>
</div>
</Section>
<Section title="Compensation Details">
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
</FormSection>
<FormSection title="Compensation Details">
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
<FormMonthYearPicker
monthLabel="Date Received"
monthRequired={true}
@ -438,8 +422,8 @@ function InternshipOfferDetailsForm({
})}
/>
</div>
</Section>
<Section title="Additional Information">
</FormSection>
<FormSection title="Additional Information">
<FormTextArea
label="Negotiation Strategy / Interview Performance"
placeholder="e.g. Did well in the behavioral interview. Used competing offers to negotiate for a higher salary."
@ -450,7 +434,7 @@ function InternshipOfferDetailsForm({
placeholder="e.g. Encountered similar questions using the Technical Interview Handbook."
{...register(`offers.${index}.comments`)}
/>
</Section>
</FormSection>
{index > 0 && (
<div className="space-y-4 sm:space-y-6">
<HorizontalDivider />
@ -541,21 +525,19 @@ export default function OfferDetailsForm({
return (
<div className="space-y-6">
<h5 className="mb-8 text-center text-4xl font-bold text-slate-900">
<h2 className="mb-8 text-2xl font-bold text-slate-900 sm:text-center sm:text-4xl">
Fill in your offer details
</h5>
<div>
<JobTypeTabs
value={jobType}
onChange={(newJobType) => {
if (newJobType === jobType) {
return;
}
</h2>
<JobTypeTabs
value={jobType}
onChange={(newJobType) => {
if (newJobType === jobType) {
return;
}
setDialogOpen(true);
}}
/>
</div>
setDialogOpen(true);
}}
/>
<OfferDetailsFormArray
fieldArrayValues={fieldArrayValues}
jobType={jobType}

Loading…
Cancel
Save