From d598801bc6e5e097c52a4cd5f83e2f5837e580b1 Mon Sep 17 00:00:00 2001 From: troff8 Date: Fri, 16 Jun 2023 19:41:46 +0400 Subject: [PATCH] feat(EstimateComboBox): added the ability to select the annual quarter --- .../migrations/20230615101320_/migration.sql | 3 + prisma/schema.prisma | 4 +- src/components/EstimateComboBox.tsx | 105 +++++++++++++----- src/schema/goal.ts | 8 +- src/utils/dateTime.ts | 3 + src/utils/estimateToString.ts | 7 +- 6 files changed, 94 insertions(+), 36 deletions(-) create mode 100644 prisma/migrations/20230615101320_/migration.sql diff --git a/prisma/migrations/20230615101320_/migration.sql b/prisma/migrations/20230615101320_/migration.sql new file mode 100644 index 000000000..d1cfde34d --- /dev/null +++ b/prisma/migrations/20230615101320_/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "Estimate" ALTER COLUMN "q" DROP NOT NULL, +ALTER COLUMN "date" DROP NOT NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index dd8d413ca..8587c9fb6 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -149,9 +149,9 @@ model Project { model Estimate { id Int @id @default(autoincrement()) - q String + q String? y String - date String + date String? goal EstimateToGoal[] goalId String activity Activity @relation(fields: [activityId], references: [id]) diff --git a/src/components/EstimateComboBox.tsx b/src/components/EstimateComboBox.tsx index dd7b578f8..cdf34ad06 100644 --- a/src/components/EstimateComboBox.tsx +++ b/src/components/EstimateComboBox.tsx @@ -34,7 +34,7 @@ interface EstimateComboBoxProps { placeholder?: string; error?: React.ComponentProps['error']; - onChange?: (estimate?: { date: string; q: string; y: string }) => void; + onChange?: (estimate?: { date?: string; q?: string; y: string }) => void; } const StyledInput = styled(Input)` @@ -49,6 +49,10 @@ const StyledButtonsContainer = styled.div` grid-gap: 6px; margin: 6px 2px; `; +const StyledItemsYearContainer = styled.div` + display: flex; + margin: 0px 2px; +`; const StyledCleanButton = styled.div` display: none; @@ -109,9 +113,10 @@ export const EstimateComboBox = React.forwardRef { const quarterInfo: Record = { @@ -138,54 +143,77 @@ export const EstimateComboBox = React.forwardRef) => { + e.preventDefault(); + }, []); + const onQButtonClick = useCallback( - (nextQ: string) => () => { + (nextQ: string | undefined) => () => { setSelectedQ(nextQ); - setChanged(true); + if (nextQ === undefined) { + setButtonText(currentYear); + } else { + setChanged(true); + } }, - [], + [currentYear], ); - const onInputChange = useCallback((e: React.ChangeEvent) => { - setChanged(true); - setInputState(e.target.value); + const onInputYearChange = useCallback((e: React.ChangeEvent) => { + setCurrentYear(e.target.value); }, []); - useEffect(() => { - if (Object.keys(quarterInfo).length) { - setInputState(createLocaleDate(parseLocaleDate(quarterInfo[selectedQ].date, { locale }), { locale })); - } - }, [selectedQ, locale, quarterInfo]); + const onInputChange = useCallback( + (e: React.ChangeEvent) => { + setChanged(true); + setInputState(e.target.value); + if (isValidDate(e.target.value)) { + setSelectedQ(quarterFromDate(parseLocaleDate(inputState, { locale }))); + } + }, + [inputState, locale], + ); useEffect(() => { - if (isValidDate(inputState)) { - setSelectedQ(quarterFromDate(parseLocaleDate(inputState, { locale }))); + if (selectedQ !== undefined) { + setInputState( + createLocaleDate( + parseLocaleDate(quarterInfo[selectedQ].date, { + locale, + }), + { locale }, + ), + ); } - }, [inputState, locale]); + }, [selectedQ, locale, quarterInfo, currentYear]); useEffect(() => { - if (changed && isValidDate(inputState)) { + if (changed && isValidDate(inputState) && selectedQ !== undefined) { const v = createValue(inputState, locale); setButtonText(formatEstimate(v, locale)); - onChange?.(v); } - }, [changed, selectedQ, inputState, locale, onChange]); + if (selectedQ === undefined) { + onChange?.({ q: undefined, y: currentYear, date: undefined }); + } + }, [changed, selectedQ, inputState, locale, onChange, currentYear]); useEffect(() => { if (value) { setButtonText( - formatEstimate( - { - q: quarterInfo[value.q].q, - y: quarterInfo[value.q].y || value.y, - date: quarterInfo[value.q].date, - }, - locale, - ), + selectedQ === undefined + ? currentYear + : formatEstimate( + { + q: quarterInfo[selectedQ].q, + y: quarterInfo[selectedQ].y || value.y, + date: quarterInfo[selectedQ].date, + }, + locale, + ), ); } - }, [value, locale, quarterInfo]); + }, [value, locale, quarterInfo, selectedQ, currentYear]); const onCleanClick = useCallback(() => { setButtonText(text); @@ -243,7 +271,26 @@ export const EstimateComboBox = React.forwardRef )} renderItems={(children) => ( - {children as React.ReactNode} + <> + {children as React.ReactNode} + + + + + )} /> ); diff --git a/src/schema/goal.ts b/src/schema/goal.ts index e67871029..91ba66a7e 100644 --- a/src/schema/goal.ts +++ b/src/schema/goal.ts @@ -66,8 +66,8 @@ export const goalCommonSchema = z.object({ priority: z.string().nullable().optional(), estimate: z .object({ - date: z.string(), - q: z.string(), + date: z.string().optional().nullable(), + q: z.string().optional().nullable(), y: z.string(), id: z.number().nullish(), }) @@ -132,8 +132,8 @@ export const goalUpdateSchema = z.object({ priority: z.string().nullable(), estimate: z .object({ - date: z.string(), - q: z.string(), + date: z.string().optional().nullable(), + q: z.string().optional().nullable(), y: z.string(), id: z.number().nullish(), }) diff --git a/src/utils/dateTime.ts b/src/utils/dateTime.ts index f4a6c5895..b4747a98a 100644 --- a/src/utils/dateTime.ts +++ b/src/utils/dateTime.ts @@ -130,6 +130,9 @@ const createValue = (date: string | Date, locale: TLocale) => { }; export const formatEstimate = (estimate: ReturnType, locale: TLocale) => { + if (!estimate.q && !estimate.date) { + return estimate.y; + } const { date, q, y } = createValue(estimate.date, locale); return date === createLocaleDate(endOfQuarter(q), { locale }) ? `${q}/${y}` : date; diff --git a/src/utils/estimateToString.ts b/src/utils/estimateToString.ts index 5a32d1b3b..3e9e3eb9f 100644 --- a/src/utils/estimateToString.ts +++ b/src/utils/estimateToString.ts @@ -1,3 +1,8 @@ import { Estimate } from '@prisma/client'; -export const estimateToString = (estimate: { q: Estimate['q']; y: Estimate['y'] }) => `${estimate.q}/${estimate.y}`; +export const estimateToString = (estimate: { q: Estimate['q']; y: Estimate['y'] }) => { + if (!estimate.q) { + return estimate.y; + } + return `${estimate.q}/${estimate.y}`; +};