[offers][feat] Use city typeahead for location field

pull/491/head
Ai Ling 3 years ago committed by Bryann Yeap Kok Keong
parent 303b9b1670
commit 6f2e8e7a2d

@ -2,21 +2,6 @@ import { EducationBackgroundType } from './types';
export const emptyOption = '----'; export const emptyOption = '----';
export const locationOptions = [
{
label: 'Singapore, Singapore',
value: 'Singapore, Singapore',
},
{
label: 'New York, US',
value: 'New York, US',
},
{
label: 'San Francisco, US',
value: 'San Francisco, US',
},
];
export const internshipCycleOptions = [ export const internshipCycleOptions = [
{ {
label: 'Summer', label: 'Summer',

@ -51,7 +51,7 @@ export default function DashboardProfileCard({
aria-hidden="true" aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400" className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400"
/> />
{location} {location.cityName}
</div> </div>
)} )}
{level && ( {level && (

@ -26,11 +26,11 @@ import { getCurrentMonth, getCurrentYear } from '~/utils/offers/time';
import { trpc } from '~/utils/trpc'; import { trpc } from '~/utils/trpc';
const defaultOfferValues = { const defaultOfferValues = {
cityId: '',
comments: '', comments: '',
companyId: '', companyId: '',
jobTitle: '', jobTitle: '',
jobType: JobType.FULLTIME, jobType: JobType.FULLTIME,
location: '',
monthYearReceived: { monthYearReceived: {
month: getCurrentMonth() as Month, month: getCurrentMonth() as Month,
year: getCurrentYear(), year: getCurrentYear(),

@ -7,9 +7,9 @@ import {
educationLevelOptions, educationLevelOptions,
emptyOption, emptyOption,
FieldError, FieldError,
locationOptions,
} from '~/components/offers/constants'; } from '~/components/offers/constants';
import type { BackgroundPostData } from '~/components/offers/types'; import type { BackgroundPostData } from '~/components/offers/types';
import CitiesTypeahead from '~/components/shared/CitiesTypeahead';
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead'; import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
import type { JobTitleType } from '~/components/shared/JobTitles'; import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles'; import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
@ -102,6 +102,12 @@ function FullTimeJobFields() {
const watchCompanyName = useWatch({ const watchCompanyName = useWatch({
name: 'background.experiences.0.companyName', name: 'background.experiences.0.companyName',
}); });
const watchCityId = useWatch({
name: 'background.experiences.0.cityId',
});
const watchCityName = useWatch({
name: 'background.experiences.0.cityName',
});
return ( return (
<> <>
@ -166,11 +172,22 @@ function FullTimeJobFields() {
placeholder="e.g. L4, Junior" placeholder="e.g. L4, Junior"
{...register(`background.experiences.0.level`)} {...register(`background.experiences.0.level`)}
/> />
<FormSelect <CitiesTypeahead
display="block"
label="Location" label="Location"
options={locationOptions} value={{
{...register(`background.experiences.0.location`)} id: watchCityId,
label: watchCityName,
value: watchCityId,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.cityId', option.value);
setValue('background.experiences.0.cityName', option.label);
} else {
setValue('background.experiences.0.cityId', '');
setValue('background.experiences.0.cityName', '');
}
}}
/> />
<FormTextInput <FormTextInput
errorMessage={experiencesField?.durationInMonths?.message} errorMessage={experiencesField?.durationInMonths?.message}
@ -202,6 +219,12 @@ function InternshipJobFields() {
const watchCompanyName = useWatch({ const watchCompanyName = useWatch({
name: 'background.experiences.0.companyName', name: 'background.experiences.0.companyName',
}); });
const watchCityId = useWatch({
name: 'background.experiences.0.cityId',
});
const watchCityName = useWatch({
name: 'background.experiences.0.cityName',
});
return ( return (
<> <>
@ -256,12 +279,22 @@ function InternshipJobFields() {
})} })}
/> />
<Collapsible label="Add more details"> <Collapsible label="Add more details">
<FormSelect <CitiesTypeahead
display="block"
label="Location" label="Location"
options={locationOptions} value={{
placeholder={emptyOption} id: watchCityId,
{...register(`background.experiences.0.location`)} label: watchCityName,
value: watchCityId,
}}
onSelect={(option) => {
if (option) {
setValue('background.experiences.0.cityId', option.value);
setValue('background.experiences.0.cityName', option.label);
} else {
setValue('background.experiences.0.cityId', '');
setValue('background.experiences.0.cityName', '');
}
}}
/> />
</Collapsible> </Collapsible>
</> </>

@ -12,6 +12,7 @@ import { TrashIcon } from '@heroicons/react/24/outline';
import { JobType } from '@prisma/client'; import { JobType } from '@prisma/client';
import { Button, Dialog, HorizontalDivider } from '@tih/ui'; import { Button, Dialog, HorizontalDivider } from '@tih/ui';
import CitiesTypeahead from '~/components/shared/CitiesTypeahead';
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead'; import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
import type { JobTitleType } from '~/components/shared/JobTitles'; import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles'; import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
@ -25,7 +26,6 @@ import {
emptyOption, emptyOption,
FieldError, FieldError,
internshipCycleOptions, internshipCycleOptions,
locationOptions,
yearOptions, yearOptions,
} from '../../constants'; } from '../../constants';
import FormMonthYearPicker from '../../forms/FormMonthYearPicker'; import FormMonthYearPicker from '../../forms/FormMonthYearPicker';
@ -64,6 +64,12 @@ function FullTimeOfferDetailsForm({
const watchCompanyName = useWatch({ const watchCompanyName = useWatch({
name: `offers.${index}.companyName`, name: `offers.${index}.companyName`,
}); });
const watchCityId = useWatch({
name: `offers.${index}.cityId`,
});
const watchCityName = useWatch({
name: `offers.${index}.cityName`,
});
const watchCurrency = useWatch({ const watchCurrency = useWatch({
name: `offers.${index}.offersFullTime.totalCompensation.currency`, name: `offers.${index}.offersFullTime.totalCompensation.currency`,
}); });
@ -119,16 +125,23 @@ function FullTimeOfferDetailsForm({
} }
}} }}
/> />
<FormSelect <CitiesTypeahead
display="block"
errorMessage={offerFields?.location?.message}
label="Location" label="Location"
options={locationOptions}
placeholder={emptyOption}
required={true} required={true}
{...register(`offers.${index}.location`, { value={{
required: FieldError.REQUIRED, id: watchCityId,
})} label: watchCityName,
value: watchCityId,
}}
onSelect={(option) => {
if (option) {
setValue(`offers.${index}.cityId`, option.value);
setValue(`offers.${index}.cityName`, option.label);
} else {
setValue(`offers.${index}.cityId`, '');
setValue(`offers.${index}.cityName`, '');
}
}}
/> />
</div> </div>
</FormSection> </FormSection>
@ -308,6 +321,12 @@ function InternshipOfferDetailsForm({
const watchCompanyName = useWatch({ const watchCompanyName = useWatch({
name: `offers.${index}.companyName`, name: `offers.${index}.companyName`,
}); });
const watchCityId = useWatch({
name: `offers.${index}.cityId`,
});
const watchCityName = useWatch({
name: `offers.${index}.cityName`,
});
return ( return (
<div className="space-y-8 rounded-lg border border-slate-200 p-6 sm:space-y-16 sm:p-8"> <div className="space-y-8 rounded-lg border border-slate-200 p-6 sm:space-y-16 sm:p-8">
@ -341,16 +360,23 @@ function InternshipOfferDetailsForm({
} }
}} }}
/> />
<FormSelect <CitiesTypeahead
display="block"
errorMessage={offerFields?.location?.message}
label="Location" label="Location"
options={locationOptions}
placeholder={emptyOption}
required={true} required={true}
{...register(`offers.${index}.location`, { value={{
required: FieldError.REQUIRED, id: watchCityId,
})} label: watchCityName,
value: watchCityId,
}}
onSelect={(option) => {
if (option) {
setValue(`offers.${index}.cityId`, option.value);
setValue(`offers.${index}.cityName`, option.label);
} else {
setValue(`offers.${index}.cityId`, '');
setValue(`offers.${index}.cityName`, '');
}
}}
/> />
</div> </div>
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6"> <div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">

@ -100,7 +100,7 @@ export default function OffersTable({
<div className="divide-x-slate-200 col-span-3 flex items-center justify-end space-x-4 divide-x"> <div className="divide-x-slate-200 col-span-3 flex items-center justify-end space-x-4 divide-x">
<div className="justify-left flex items-center space-x-2"> <div className="justify-left flex items-center space-x-2">
<span className="sr-only sm:not-sr-only sm:inline"> <span className="sr-only sm:not-sr-only sm:inline">
View all offers in Display offers in
</span> </span>
<CurrencySelector <CurrencySelector
handleCurrencyChange={(value: string) => setCurrency(value)} handleCurrencyChange={(value: string) => setCurrency(value)}

@ -46,13 +46,14 @@ export type BackgroundPostData = {
}; };
type ExperiencePostData = { type ExperiencePostData = {
cityId?: string | null;
cityName?: string | null;
companyId?: string | null; companyId?: string | null;
companyName?: string | null; companyName?: string | null;
durationInMonths?: number | null; durationInMonths?: number | null;
id?: string; id?: string;
jobType?: string | null; jobType?: string | null;
level?: string | null; level?: string | null;
location?: Location | null;
monthlySalary?: Money | null; monthlySalary?: Money | null;
title?: string | null; title?: string | null;
totalCompensation?: Money | null; totalCompensation?: Money | null;
@ -77,12 +78,13 @@ type SpecificYoePostData = {
type SpecificYoe = SpecificYoePostData; type SpecificYoe = SpecificYoePostData;
export type OfferPostData = { export type OfferPostData = {
cityId: string;
cityName?: string;
comments: string; comments: string;
companyId: string; companyId: string;
companyName?: string; companyName?: string;
id?: string; id?: string;
jobType: JobType; jobType: JobType;
location: string;
monthYearReceived: Date; monthYearReceived: Date;
negotiationStrategy: string; negotiationStrategy: string;
offersFullTime?: OfferFullTimePostData | null; offersFullTime?: OfferFullTimePostData | null;

@ -36,13 +36,14 @@ export default function OffersEditPage() {
experiences.length === 0 experiences.length === 0
? [{ jobType: JobType.FULLTIME }] ? [{ jobType: JobType.FULLTIME }]
: experiences.map((exp) => ({ : experiences.map((exp) => ({
cityId: exp.location?.cityId,
cityName: exp.location?.cityName,
companyId: exp.company?.id, companyId: exp.company?.id,
companyName: exp.company?.name, companyName: exp.company?.name,
durationInMonths: exp.durationInMonths, durationInMonths: exp.durationInMonths,
id: exp.id, id: exp.id,
jobType: exp.jobType, jobType: exp.jobType,
level: exp.level, level: exp.level,
location: exp.location,
monthlySalary: exp.monthlySalary, monthlySalary: exp.monthlySalary,
title: exp.title, title: exp.title,
totalCompensation: exp.totalCompensation, totalCompensation: exp.totalCompensation,
@ -53,12 +54,13 @@ export default function OffersEditPage() {
}, },
id: data.id, id: data.id,
offers: data.offers.map((offer) => ({ offers: data.offers.map((offer) => ({
cityId: offer.location.cityId,
cityName: offer.location.cityName,
comments: offer.comments, comments: offer.comments,
companyId: offer.company.id, companyId: offer.company.id,
companyName: offer.company.name, companyName: offer.company.name,
id: offer.id, id: offer.id,
jobType: offer.jobType, jobType: offer.jobType,
location: offer.location,
monthYearReceived: convertToMonthYear(offer.monthYearReceived), monthYearReceived: convertToMonthYear(offer.monthYearReceived),
negotiationStrategy: offer.negotiationStrategy, negotiationStrategy: offer.negotiationStrategy,
offersFullTime: offer.offersFullTime, offersFullTime: offer.offersFullTime,

Loading…
Cancel
Save