From 4330fb54481638342d39ed3279d16bac4133854b Mon Sep 17 00:00:00 2001 From: Ai Ling <50992674+ailing35@users.noreply.github.com> Date: Tue, 11 Oct 2022 15:08:44 +0800 Subject: [PATCH] [offers][feat] Integrate offers create API and fix form UI (#358) --- .../src/components/offers/OffersTable.tsx | 2 +- .../portal/src/components/offers/constants.ts | 24 ++-- .../offers/forms/BackgroundForm.tsx | 64 +++++---- .../components/offers/forms/OfferAnalysis.tsx | 3 +- .../offers/forms/OfferDetailsForm.tsx | 101 +++++++++----- .../forms/components/FormMonthYearPicker.tsx | 37 ++++++ .../forms/{ => components}/FormRadioList.tsx | 7 +- .../forms/{ => components}/FormSelect.tsx | 0 .../forms/{ => components}/FormTextArea.tsx | 0 .../forms/{ => components}/FormTextInput.tsx | 0 apps/portal/src/components/offers/types.ts | 36 ++--- .../src/components/offers/util/time/index.tsx | 7 - apps/portal/src/pages/offers/index.tsx | 25 +--- apps/portal/src/pages/offers/submit.tsx | 124 ++++++++++++------ .../offers}/currency/CurrencyEnum.tsx | 0 .../offers}/currency/CurrencySelector.tsx | 2 +- apps/portal/src/utils/offers/form.tsx | 56 ++++++++ apps/portal/src/utils/offers/time.tsx | 25 ++++ 18 files changed, 348 insertions(+), 165 deletions(-) create mode 100644 apps/portal/src/components/offers/forms/components/FormMonthYearPicker.tsx rename apps/portal/src/components/offers/forms/{ => components}/FormRadioList.tsx (69%) rename apps/portal/src/components/offers/forms/{ => components}/FormSelect.tsx (100%) rename apps/portal/src/components/offers/forms/{ => components}/FormTextArea.tsx (100%) rename apps/portal/src/components/offers/forms/{ => components}/FormTextInput.tsx (100%) delete mode 100644 apps/portal/src/components/offers/util/time/index.tsx rename apps/portal/src/{components/offers/util => utils/offers}/currency/CurrencyEnum.tsx (100%) rename apps/portal/src/{components/offers/util => utils/offers}/currency/CurrencySelector.tsx (89%) create mode 100644 apps/portal/src/utils/offers/form.tsx create mode 100644 apps/portal/src/utils/offers/time.tsx diff --git a/apps/portal/src/components/offers/OffersTable.tsx b/apps/portal/src/components/offers/OffersTable.tsx index ded79547..5ef39748 100644 --- a/apps/portal/src/components/offers/OffersTable.tsx +++ b/apps/portal/src/components/offers/OffersTable.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { HorizontalDivider, Pagination, Select, Tabs } from '@tih/ui'; -import CurrencySelector from '~/components/offers/util/currency/CurrencySelector'; +import CurrencySelector from '~/utils/offers/currency/CurrencySelector'; type TableRow = { company: string; diff --git a/apps/portal/src/components/offers/constants.ts b/apps/portal/src/components/offers/constants.ts index 2a09e9b5..a5dc2706 100644 --- a/apps/portal/src/components/offers/constants.ts +++ b/apps/portal/src/components/offers/constants.ts @@ -29,24 +29,24 @@ export const titleOptions = [ export const companyOptions = [ emptyOption, { - label: 'Bytedance', - value: 'id-abc123', + label: 'Amazon', + value: 'cl93patjt0000txewdi601mub', + }, + { + label: 'Microsoft', + value: 'cl93patjt0001txewkglfjsro', + }, + { + label: 'Apple', + value: 'cl93patjt0002txewf3ug54m8', }, { label: 'Google', - value: 'id-abc567', + value: 'cl93patjt0003txewyiaky7xx', }, { label: 'Meta', - value: 'id-abc456', - }, - { - label: 'Shopee', - value: 'id-abc345', - }, - { - label: 'Tik Tok', - value: 'id-abc678', + value: 'cl93patjt0004txew88wkcqpu', }, ]; diff --git a/apps/portal/src/components/offers/forms/BackgroundForm.tsx b/apps/portal/src/components/offers/forms/BackgroundForm.tsx index 0acbbe69..171823f1 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, @@ -12,7 +12,7 @@ import { titleOptions, } from '../constants'; import { JobType } from '../types'; -import { CURRENCY_OPTIONS } from '../util/currency/CurrencyEnum'; +import { CURRENCY_OPTIONS } from '../../../utils/offers/currency/CurrencyEnum'; function YoeSection() { const { register } = useFormContext(); @@ -28,7 +28,9 @@ function YoeSection() { label="Total YOE" placeholder="0" type="number" - {...register(`background.totalYoe`)} + {...register(`background.totalYoe`, { + valueAsNumber: true, + })} />
@@ -37,7 +39,9 @@ function YoeSection() {
@@ -90,7 +96,9 @@ function FullTimeJobFields() { isLabelHidden={true} label="Currency" options={CURRENCY_OPTIONS} - {...register(`background.experience.totalCompensation.currency`)} + {...register( + `background.experiences.0.totalCompensation.currency`, + )} /> } endAddOnType="element" @@ -99,7 +107,9 @@ function FullTimeJobFields() { startAddOn="$" startAddOnType="label" type="number" - {...register(`background.experience.totalCompensation.value`)} + {...register(`background.experiences.0.totalCompensation.value`, { + valueAsNumber: true, + })} />
@@ -107,12 +117,12 @@ function FullTimeJobFields() {
@@ -120,12 +130,14 @@ function FullTimeJobFields() { display="block" label="Location" options={locationOptions} - {...register(`background.experience.location`)} + {...register(`background.experiences.0.location`)} />
@@ -142,13 +154,13 @@ function InternshipJobFields() { display="block" label="Title" options={titleOptions} - {...register(`background.experience.title`)} + {...register(`background.experiences.0.title`)} />
@@ -159,7 +171,7 @@ function InternshipJobFields() { isLabelHidden={true} label="Currency" options={CURRENCY_OPTIONS} - {...register(`background.experience.monthlySalary.currency`)} + {...register(`background.experiences.0.monthlySalary.currency`)} /> } endAddOnType="element" @@ -168,7 +180,7 @@ function InternshipJobFields() { startAddOn="$" startAddOnType="label" type="number" - {...register(`background.experience.monthlySalary.value`)} + {...register(`background.experiences.0.monthlySalary.value`)} />
@@ -176,13 +188,13 @@ function InternshipJobFields() { @@ -194,7 +206,7 @@ function CurrentJobSection() { const { register } = useFormContext(); const watchJobType = useWatch({ defaultValue: JobType.FullTime, - name: 'background.experience.jobType', + name: 'background.experiences.0.jobType', }); return ( @@ -209,7 +221,7 @@ function CurrentJobSection() { isLabelHidden={true} label="Job Type" orientation="horizontal" - {...register('background.experience.jobType')}> + {...register('background.experiences.0.jobType')}> @@ -259,7 +271,7 @@ function EducationSection() { 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 })} /> -
@@ -110,6 +108,7 @@ function FullTimeOfferDetailsForm({ type="number" {...register(`offers.${index}.job.totalCompensation.value`, { required: true, + valueAsNumber: true, })} />
@@ -121,7 +120,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 +132,10 @@ function FullTimeOfferDetailsForm({ startAddOn="$" startAddOnType="label" type="number" - {...register(`offers.${index}.job.base.value`)} + {...register(`offers.${index}.job.base.value`, { + required: true, + valueAsNumber: true, + })} /> } endAddOnType="element" @@ -150,7 +156,10 @@ function FullTimeOfferDetailsForm({ startAddOn="$" startAddOnType="label" type="number" - {...register(`offers.${index}.job.bonus.value`)} + {...register(`offers.${index}.job.bonus.value`, { + required: true, + valueAsNumber: true, + })} />
@@ -161,7 +170,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 +182,10 @@ function FullTimeOfferDetailsForm({ startAddOn="$" startAddOnType="label" type="number" - {...register(`offers.${index}.job.stocks.value`)} + {...register(`offers.${index}.job.stocks.value`, { + required: true, + valueAsNumber: true, + })} />
@@ -251,7 +265,7 @@ function InternshipOfferDetailsForm({ remove, }: InternshipOfferDetailsFormProps) { const { register } = useFormContext<{ - offers: Array; + offers: Array; }>(); return ( @@ -262,13 +276,19 @@ function InternshipOfferDetailsForm({ label="Title" options={titleOptions} required={true} - {...register(`offers.${index}.job.title`)} + {...register(`offers.${index}.job.title`, { + minLength: 1, + required: true, + })} />
@@ -277,40 +297,44 @@ function InternshipOfferDetailsForm({ label="Company" options={companyOptions} required={true} - value="Shopee" - {...register(`offers.${index}.companyId`)} + {...register(`offers.${index}.companyId`, { + required: true, + })} />
-
- +
+
+
+

Date received:

+
@@ -321,7 +345,9 @@ function InternshipOfferDetailsForm({ isLabelHidden={true} label="Currency" options={CURRENCY_OPTIONS} - {...register(`offers.${index}.job.monthlySalary.currency`)} + {...register(`offers.${index}.job.monthlySalary.currency`, { + required: true, + })} /> } endAddOnType="element" @@ -331,7 +357,10 @@ function InternshipOfferDetailsForm({ startAddOn="$" startAddOnType="label" type="number" - {...register(`offers.${index}.job.monthlySalary.value`)} + {...register(`offers.${index}.job.monthlySalary.value`, { + required: true, + valueAsNumber: true, + })} />
diff --git a/apps/portal/src/components/offers/forms/components/FormMonthYearPicker.tsx b/apps/portal/src/components/offers/forms/components/FormMonthYearPicker.tsx new file mode 100644 index 00000000..62967117 --- /dev/null +++ b/apps/portal/src/components/offers/forms/components/FormMonthYearPicker.tsx @@ -0,0 +1,37 @@ +import type { ComponentProps } from 'react'; +import { useFormContext, useWatch } from 'react-hook-form'; + +import MonthYearPicker from '~/components/shared/MonthYearPicker'; + +import { getCurrentMonth, getCurrentYear } from '../../../../utils/offers/time'; + +type MonthYearPickerProps = ComponentProps; + +type FormMonthYearPickerProps = Omit< + MonthYearPickerProps, + 'onChange' | 'value' +> & { + name: string; +}; + +export default function FormMonthYearPicker({ + name, + ...rest +}: FormMonthYearPickerProps) { + const { setValue } = useFormContext(); + + const value = useWatch({ + defaultValue: { month: getCurrentMonth(), year: getCurrentYear() }, + name, + }); + + return ( + { + setValue(name, val); + }} + /> + ); +} diff --git a/apps/portal/src/components/offers/forms/FormRadioList.tsx b/apps/portal/src/components/offers/forms/components/FormRadioList.tsx similarity index 69% rename from apps/portal/src/components/offers/forms/FormRadioList.tsx rename to apps/portal/src/components/offers/forms/components/FormRadioList.tsx index 9ce3065d..5fbbd53d 100644 --- a/apps/portal/src/components/offers/forms/FormRadioList.tsx +++ b/apps/portal/src/components/offers/forms/components/FormRadioList.tsx @@ -1,5 +1,4 @@ import type { ComponentProps } from 'react'; -import { forwardRef } from 'react'; import { useFormContext } from 'react-hook-form'; import { RadioList } from '@tih/ui'; @@ -7,7 +6,7 @@ type RadioListProps = ComponentProps; type FormRadioListProps = Omit; -function FormRadioListWithRef({ name, ...rest }: FormRadioListProps) { +export default function FormRadioList({ name, ...rest }: FormRadioListProps) { const { setValue } = useFormContext(); return ( ); } - -const FormRadioList = forwardRef(FormRadioListWithRef); - -export default FormRadioList; 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..82ee7140 100644 --- a/apps/portal/src/components/offers/types.ts +++ b/apps/portal/src/components/offers/types.ts @@ -1,4 +1,6 @@ /* eslint-disable no-shadow */ +import type { MonthYear } from '../shared/MonthYearPicker'; + /* * Offer Profile */ @@ -18,7 +20,7 @@ export enum EducationBackgroundType { SelfTaught = 'Self-taught', } -type Money = { +export type Money = { currency: string; value: number; }; @@ -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,17 +43,22 @@ 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; +export type OfferDetailsPostData = Omit< + OfferDetailsFormData, + 'monthYearReceived' +> & { + monthYearReceived: Date; +}; type SpecificYoe = { domain: string; @@ -98,8 +95,8 @@ type Education = { }; type BackgroundFormData = { - education: Education; - experience: Experience; + educations: Array; + experiences: Array; specificYoes: Array; totalYoe: number; }; @@ -108,3 +105,8 @@ export type SubmitOfferFormData = { background: BackgroundFormData; offers: Array; }; + +export type OfferPostData = { + background: BackgroundFormData; + offers: Array; +}; diff --git a/apps/portal/src/components/offers/util/time/index.tsx b/apps/portal/src/components/offers/util/time/index.tsx deleted file mode 100644 index 86f21ab9..00000000 --- a/apps/portal/src/components/offers/util/time/index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export function formatDate(value: Date | number | string) { - const date = new Date(value); - // Const day = date.toLocaleString('default', { day: '2-digit' }); - const month = date.toLocaleString('default', { month: 'short' }); - const year = date.toLocaleString('default', { year: 'numeric' }); - return `${month} ${year}`; -} 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..c4949bb2 100644 --- a/apps/portal/src/pages/offers/submit.tsx +++ b/apps/portal/src/pages/offers/submit.tsx @@ -8,7 +8,15 @@ import BackgroundForm from '~/components/offers/forms/BackgroundForm'; 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 type { + OfferDetailsFormData, + SubmitOfferFormData, +} from '~/components/offers/types'; +import type { Month } from '~/components/shared/MonthYearPicker'; + +import { cleanObject, removeInvalidMoneyData } from '~/utils/offers/form'; +import { getCurrentMonth, getCurrentYear } from '~/utils/offers/time'; +import { trpc } from '~/utils/trpc'; function Breadcrumbs() { return ( @@ -23,53 +31,94 @@ 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 onSubmit: SubmitHandler = async () => { - nextStep(); + 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 createMutation = trpc.useMutation(['offers.profile.create'], { + onError(error) { + console.error(error.message); + }, + onSuccess() { + alert('offer profile submit success!'); + setFormStep(formStep + 1); + }, + }); + + const onSubmit: SubmitHandler = async (data) => { + const result = await trigger(); + if (!result) { + return; + } + data = removeInvalidMoneyData(data); + const background = cleanObject(data.background); + const offers = data.offers.map((offer: OfferDetailsFormData) => ({ + ...offer, + monthYearReceived: new Date( + offer.monthYearReceived.year, + offer.monthYearReceived.month, + ), + })); + const postData = { background, offers }; + + postData.background.specificYoes = data.background.specificYoes.filter( + (specificYoe) => specificYoe.domain && specificYoe.yoe > 0, + ); + + createMutation.mutate(postData); }; return ( @@ -78,16 +127,17 @@ export default function OffersSubmissionPage() {
-
- {formComponents[formStep]} + + {formSteps[formStep].component} {/*
{JSON.stringify(formMethods.watch(), null, 2)}
*/} - {(formStep === 0 || formStep === 2) && ( + {formSteps[formStep].hasNext && (
)} diff --git a/apps/portal/src/components/offers/util/currency/CurrencyEnum.tsx b/apps/portal/src/utils/offers/currency/CurrencyEnum.tsx similarity index 100% rename from apps/portal/src/components/offers/util/currency/CurrencyEnum.tsx rename to apps/portal/src/utils/offers/currency/CurrencyEnum.tsx diff --git a/apps/portal/src/components/offers/util/currency/CurrencySelector.tsx b/apps/portal/src/utils/offers/currency/CurrencySelector.tsx similarity index 89% rename from apps/portal/src/components/offers/util/currency/CurrencySelector.tsx rename to apps/portal/src/utils/offers/currency/CurrencySelector.tsx index 2ebe5bd5..2ba883b4 100644 --- a/apps/portal/src/components/offers/util/currency/CurrencySelector.tsx +++ b/apps/portal/src/utils/offers/currency/CurrencySelector.tsx @@ -1,6 +1,6 @@ import { Select } from '@tih/ui'; -import { Currency } from '~/components/offers/util/currency/CurrencyEnum'; +import { Currency } from '~/utils/offers/currency/CurrencyEnum'; const currencyOptions = Object.entries(Currency).map(([key, value]) => ({ label: key, diff --git a/apps/portal/src/utils/offers/form.tsx b/apps/portal/src/utils/offers/form.tsx new file mode 100644 index 00000000..16def65d --- /dev/null +++ b/apps/portal/src/utils/offers/form.tsx @@ -0,0 +1,56 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +/** + * Removes empty objects, empty strings, `null`, `undefined`, and `NaN` values from an object. + * Does not remove empty arrays. + * @param object + * @returns object without empty values or objects. + */ +export function cleanObject(object: any) { + Object.entries(object).forEach(([k, v]) => { + if ((v && typeof v === 'object') || Array.isArray(v)) { + cleanObject(v); + } + if ( + (v && + typeof v === 'object' && + !Object.keys(v).length && + !Array.isArray(v)) || + v === null || + v === undefined || + v === '' || + v !== v + ) { + if (Array.isArray(object)) { + const index = object.indexOf(v); + object.splice(index, 1); + } else if (!(v instanceof Date)) { + delete object[k]; + } + } + }); + return object; +} + +/** + * Removes invalid money data from an object. + * If currency is present but value is not present, money object is removed. + * @param object + * @returns object without invalid money data. + */ +export function removeInvalidMoneyData(object: any) { + Object.entries(object).forEach(([k, v]) => { + if ((v && typeof v === 'object') || Array.isArray(v)) { + removeInvalidMoneyData(v); + } + if (k === 'currency') { + if (object.value === undefined) { + delete object[k]; + } else if (object.value === null || object.value !== object.value) { + delete object[k]; + delete object.value; + } + } + }); + return object; +} diff --git a/apps/portal/src/utils/offers/time.tsx b/apps/portal/src/utils/offers/time.tsx new file mode 100644 index 00000000..c13a6efe --- /dev/null +++ b/apps/portal/src/utils/offers/time.tsx @@ -0,0 +1,25 @@ +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' }); + const month = date.toLocaleString('default', { month: 'short' }); + 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()); +}