From ca057b84b8b6b93d368394c4c47e7857f8d0c81a Mon Sep 17 00:00:00 2001 From: jomarmontuya Date: Thu, 15 Feb 2024 12:20:07 +0800 Subject: [PATCH 01/20] date field initial commit --- .../src/app/components/Editor/Field/Field.tsx | 79 +++++++++++++++---- src/shell/components/FieldTypeDate/index.tsx | 17 ++-- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx index 35e4aee580..c923b6e1ab 100644 --- a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx +++ b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx @@ -67,6 +67,8 @@ import { import { ResolvedOption } from "./ResolvedOption"; import { LinkOption } from "./LinkOption"; import { FieldTypeMedia } from "../../FieldTypeMedia"; +import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers-pro"; +import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; const AIFieldShell = withAI(FieldShell); @@ -259,6 +261,22 @@ export const Field = ({ return Object.values(errors)?.some((error) => !!error); }; + /** + * @description This function remove items that are only saved in memory. + * This means that we only shows in the options all items that are saved, published or scheduled. + * + */ + const filterValidItems = (items: any) => { + // remove items that are only saved in memory + const filteredValidItems = Object.entries(items).filter( + ([, value]) => value.web.version + ); + // Reshape the array back into an object + let options = Object.fromEntries(filteredValidItems); + + return options; + }; + switch (datatype) { case "text": return ( @@ -678,6 +696,8 @@ export const Field = ({ }, [allLanguages.length, relatedModelZUID, langID]); let oneToOneOptions: OneToManyOptions[] = useMemo(() => { + const options = filterValidItems(allItems); + return [ { inputLabel: "- None -", @@ -686,7 +706,7 @@ export const Field = ({ }, ...resolveRelatedOptions( allFields, - allItems, + options, relatedFieldZUID, relatedModelZUID, langID, @@ -751,9 +771,12 @@ export const Field = ({ case "one_to_many": const oneToManyOptions: OneToManyOptions[] = useMemo(() => { + console.log(allItems); + const options = filterValidItems(allItems); + return resolveRelatedOptions( allFields, - allItems, + options, relatedFieldZUID, relatedModelZUID, langID, @@ -876,6 +899,7 @@ export const Field = ({ */ const onDateChange = useCallback( (value, name, datatype) => { + console.log(value, name, datatype); /** * Flatpickr emits a utc timestamp, offset from users local time. * Legacy behavior did not send utc but sent the value as is selected by the user @@ -886,22 +910,45 @@ export const Field = ({ [onChange] ); + // return ( + // + // + // onDateChange(date, name, datatype)} + // error={errors && Object.values(errors)?.some((error) => !!error)} + // /> + // + // + // ); + return ( - - onDateChange(date, name, datatype)} - error={errors && Object.values(errors)?.some((error) => !!error)} - /> + + + onDateChange(date, name, datatype)} + slotProps={{ + inputAdornment: { + position: "start", + }, + }} + /> + ); diff --git a/src/shell/components/FieldTypeDate/index.tsx b/src/shell/components/FieldTypeDate/index.tsx index 1171b71b2c..f206cc647b 100644 --- a/src/shell/components/FieldTypeDate/index.tsx +++ b/src/shell/components/FieldTypeDate/index.tsx @@ -1,7 +1,10 @@ -import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; -import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; -import { DesktopDatePicker, DesktopDatePickerProps } from "@mui/x-date-pickers"; +import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; +import { LocalizationProvider } from "@mui/x-date-pickers"; import { TextField } from "@mui/material"; +import { + DesktopDatePicker, + DesktopDatePickerProps, +} from "@mui/x-date-pickers/DesktopDatePicker"; export interface FieldTypeDateProps extends Omit, "renderInput"> { @@ -18,10 +21,12 @@ export const FieldTypeDate = ({ return ( ( - - )} + renderInput={(params) => { + params.inputProps.placeholder = "Mon DD YYYY"; + return ; + }} // Spread props at the end to allow prop overrides {...props} /> From edd65bad64a33554b178c7db6596166d0e1590a6 Mon Sep 17 00:00:00 2001 From: jomarmontuya Date: Wed, 21 Feb 2024 06:59:11 +0800 Subject: [PATCH 02/20] updates --- .../src/app/components/Editor/Field/Field.tsx | 31 ++++----- src/shell/components/FieldTypeDate/index.tsx | 69 ++++++++++++++----- 2 files changed, 66 insertions(+), 34 deletions(-) diff --git a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx index c923b6e1ab..9ea1a06464 100644 --- a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx +++ b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx @@ -67,8 +67,6 @@ import { import { ResolvedOption } from "./ResolvedOption"; import { LinkOption } from "./LinkOption"; import { FieldTypeMedia } from "../../FieldTypeMedia"; -import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers-pro"; -import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; const AIFieldShell = withAI(FieldShell); @@ -933,22 +931,19 @@ export const Field = ({ return ( - - onDateChange(date, name, datatype)} - slotProps={{ - inputAdornment: { - position: "start", - }, - }} - /> - + onDateChange(date, name, datatype)} + error={errors && Object.values(errors)?.some((error) => !!error)} + /> ); diff --git a/src/shell/components/FieldTypeDate/index.tsx b/src/shell/components/FieldTypeDate/index.tsx index f206cc647b..727728fc4a 100644 --- a/src/shell/components/FieldTypeDate/index.tsx +++ b/src/shell/components/FieldTypeDate/index.tsx @@ -1,13 +1,39 @@ -import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; -import { LocalizationProvider } from "@mui/x-date-pickers"; -import { TextField } from "@mui/material"; import { - DesktopDatePicker, - DesktopDatePickerProps, -} from "@mui/x-date-pickers/DesktopDatePicker"; + DatePicker, + LocalizationProvider, + DatePickerProps, +} from "@mui/x-date-pickers-pro"; +import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; + +// export interface FieldTypeDateProps +// extends Omit, "renderInput"> { +// name: string; +// required?: boolean; +// error?: boolean; +// } -export interface FieldTypeDateProps - extends Omit, "renderInput"> { +// export const FieldTypeDate = ({ +// required, +// error, +// ...props +// }: FieldTypeDateProps) => { +// return ( +// +// { +// params.inputProps.placeholder = "Mon DD YYYY"; +// return ; +// }} +// // Spread props at the end to allow prop overrides +// {...props} +// /> +// +// ); +// }; + +export interface FieldTypeDateProps extends DatePickerProps { name: string; required?: boolean; error?: boolean; @@ -20,15 +46,26 @@ export const FieldTypeDate = ({ }: FieldTypeDateProps) => { return ( - { - params.inputProps.placeholder = "Mon DD YYYY"; - return ; - }} - // Spread props at the end to allow prop overrides + ); From a3c053d2fd314b4f3016e506115e3b6c6d09474f Mon Sep 17 00:00:00 2001 From: jomarmontuya Date: Wed, 21 Feb 2024 16:21:48 +0800 Subject: [PATCH 03/20] Date field Revamp initial commit --- .../src/app/components/Editor/Field/Field.tsx | 28 ++--- src/shell/components/FieldTypeDate/index.tsx | 114 ++++++++++++------ 2 files changed, 89 insertions(+), 53 deletions(-) diff --git a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx index 9ea1a06464..ee4fb57101 100644 --- a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx +++ b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx @@ -930,21 +930,19 @@ export const Field = ({ return ( - - onDateChange(date, name, datatype)} - error={errors && Object.values(errors)?.some((error) => !!error)} - /> - + onDateChange(date, name, datatype)} + error={errors && Object.values(errors)?.some((error) => !!error)} + /> ); diff --git a/src/shell/components/FieldTypeDate/index.tsx b/src/shell/components/FieldTypeDate/index.tsx index 727728fc4a..f32af663cb 100644 --- a/src/shell/components/FieldTypeDate/index.tsx +++ b/src/shell/components/FieldTypeDate/index.tsx @@ -4,6 +4,82 @@ import { DatePickerProps, } from "@mui/x-date-pickers-pro"; import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; +import { useEffect, useState } from "react"; +import Button from "@mui/material/Button"; +import { Typography, Stack, Box } from "@mui/material"; + +export interface FieldTypeDateProps extends DatePickerProps { + name: string; + required?: boolean; + error?: boolean; +} + +export const FieldTypeDate = ({ + required, + error, + value, + ...props +}: FieldTypeDateProps) => { + const [dateValue, setValue] = useState(null); + + useEffect(() => { + setValue(value); + }, [value]); + + return ( + + + + + + + + + + ); +}; // export interface FieldTypeDateProps // extends Omit, "renderInput"> { @@ -32,41 +108,3 @@ import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; // // ); // }; - -export interface FieldTypeDateProps extends DatePickerProps { - name: string; - required?: boolean; - error?: boolean; -} - -export const FieldTypeDate = ({ - required, - error, - ...props -}: FieldTypeDateProps) => { - return ( - - - - ); -}; From 058536f5aca0c6400994e1433e9e4747619cfed5 Mon Sep 17 00:00:00 2001 From: jomarmontuya Date: Thu, 22 Feb 2024 15:35:35 +0800 Subject: [PATCH 04/20] update component to enforce Mon placeholder and keep the component uncontrolled --- .../src/app/components/Editor/Field/Field.tsx | 29 +------ src/shell/components/FieldTypeDate/index.tsx | 84 ++++++++----------- 2 files changed, 38 insertions(+), 75 deletions(-) diff --git a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx index 002ba71beb..b83753d9dd 100644 --- a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx +++ b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx @@ -900,48 +900,23 @@ export const Field = ({ */ const onDateChange = useCallback( (value, name, datatype) => { - console.log(value, name, datatype); /** * Flatpickr emits a utc timestamp, offset from users local time. * Legacy behavior did not send utc but sent the value as is selected by the user * this ensures that behavior is maintained. */ - onChange(moment(value).format("YYYY-MM-DD HH:mm:ss"), name, datatype); + onChange(value, name, datatype); }, [onChange] ); - // return ( - // - // - // onDateChange(date, name, datatype)} - // error={errors && Object.values(errors)?.some((error) => !!error)} - // /> - // - // - // ); - return ( onDateChange(date, name, datatype)} error={errors && Object.values(errors)?.some((error) => !!error)} diff --git a/src/shell/components/FieldTypeDate/index.tsx b/src/shell/components/FieldTypeDate/index.tsx index f32af663cb..e6975f29a9 100644 --- a/src/shell/components/FieldTypeDate/index.tsx +++ b/src/shell/components/FieldTypeDate/index.tsx @@ -4,7 +4,7 @@ import { DatePickerProps, } from "@mui/x-date-pickers-pro"; import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; -import { useEffect, useState } from "react"; +import { useRef } from "react"; import Button from "@mui/material/Button"; import { Typography, Stack, Box } from "@mui/material"; @@ -17,37 +17,55 @@ export interface FieldTypeDateProps extends DatePickerProps { export const FieldTypeDate = ({ required, error, - value, ...props }: FieldTypeDateProps) => { - const [dateValue, setValue] = useState(null); + const inputRef = useRef(null); - useEffect(() => { - setValue(value); - }, [value]); + const handleClear = () => { + /** + * Clear the input value + */ + if (props.onChange) props.onChange(null, null); + }; return ( - + { + /** + * Enforce the placeholder to be "Mon" instead of "MMM" + */ + return "Mon"; + }, + }} + dateAdapter={AdapterDateFns} + > { - setValue(null); - }} + onClick={handleClear} > ); }; - -// export interface FieldTypeDateProps -// extends Omit, "renderInput"> { -// name: string; -// required?: boolean; -// error?: boolean; -// } - -// export const FieldTypeDate = ({ -// required, -// error, -// ...props -// }: FieldTypeDateProps) => { -// return ( -// -// { -// params.inputProps.placeholder = "Mon DD YYYY"; -// return ; -// }} -// // Spread props at the end to allow prop overrides -// {...props} -// /> -// -// ); -// }; From 52f56386a314578e3df6fe35fe81862e0cfad569 Mon Sep 17 00:00:00 2001 From: jomarmontuya Date: Thu, 22 Feb 2024 15:39:58 +0800 Subject: [PATCH 05/20] update popper margin --- src/shell/components/FieldTypeDate/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shell/components/FieldTypeDate/index.tsx b/src/shell/components/FieldTypeDate/index.tsx index e6975f29a9..9f7bde42d7 100644 --- a/src/shell/components/FieldTypeDate/index.tsx +++ b/src/shell/components/FieldTypeDate/index.tsx @@ -47,6 +47,11 @@ export const FieldTypeDate = ({ {...props} disableHighlightToday={!!props.value} slotProps={{ + desktopPaper: { + sx: { + mt: 1, + }, + }, day: { /* * Override the default today's background color to match with the theme From 772033037903278000b663540f7df9a16eff911d Mon Sep 17 00:00:00 2001 From: jomarmontuya Date: Fri, 1 Mar 2024 02:08:32 +0800 Subject: [PATCH 06/20] open picker on textfield click --- src/shell/components/FieldTypeDate/index.tsx | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/shell/components/FieldTypeDate/index.tsx b/src/shell/components/FieldTypeDate/index.tsx index 9f7bde42d7..728008fafe 100644 --- a/src/shell/components/FieldTypeDate/index.tsx +++ b/src/shell/components/FieldTypeDate/index.tsx @@ -4,7 +4,7 @@ import { DatePickerProps, } from "@mui/x-date-pickers-pro"; import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; -import { useRef } from "react"; +import { Ref, useRef, useState } from "react"; import Button from "@mui/material/Button"; import { Typography, Stack, Box } from "@mui/material"; @@ -19,7 +19,9 @@ export const FieldTypeDate = ({ error, ...props }: FieldTypeDateProps) => { - const inputRef = useRef(null); + const triggerPickerRef = useRef(null); + const textFieldRef = useRef(null); + const [open, setOpen] = useState(false); const handleClear = () => { /** @@ -43,7 +45,8 @@ export const FieldTypeDate = ({ setOpen(false)} {...props} disableHighlightToday={!!props.value} slotProps={{ @@ -65,12 +68,17 @@ export const FieldTypeDate = ({ }, }, textField: { + ref: textFieldRef, + onClick: () => { + triggerPickerRef.current?.click(); + textFieldRef.current?.focus(); + }, placeholder: "Mon DD YYYY", }, + openPickerButton: { + ref: triggerPickerRef, + }, inputAdornment: { - sx: { - margin: "0px", - }, position: "start", }, }} From f1a238a7a9e3ba26b289be202d7b825a6984badc Mon Sep 17 00:00:00 2001 From: jomarmontuya Date: Mon, 4 Mar 2024 21:55:29 +0800 Subject: [PATCH 07/20] open the picker when textfield is click and refocus to the textfield --- .../src/app/components/Editor/Field/Field.tsx | 1 - src/shell/components/FieldTypeDate/index.tsx | 190 ++++++++++-------- 2 files changed, 107 insertions(+), 84 deletions(-) diff --git a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx index b83753d9dd..f9b80cb182 100644 --- a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx +++ b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx @@ -915,7 +915,6 @@ export const Field = ({ onDateChange(date, name, datatype)} diff --git a/src/shell/components/FieldTypeDate/index.tsx b/src/shell/components/FieldTypeDate/index.tsx index 728008fafe..171fc7cea1 100644 --- a/src/shell/components/FieldTypeDate/index.tsx +++ b/src/shell/components/FieldTypeDate/index.tsx @@ -4,9 +4,10 @@ import { DatePickerProps, } from "@mui/x-date-pickers-pro"; import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; -import { Ref, useRef, useState } from "react"; +import { Ref, memo, useCallback, useRef, useState } from "react"; import Button from "@mui/material/Button"; import { Typography, Stack, Box } from "@mui/material"; +import { parse } from "date-fns"; export interface FieldTypeDateProps extends DatePickerProps { name: string; @@ -14,98 +15,121 @@ export interface FieldTypeDateProps extends DatePickerProps { error?: boolean; } -export const FieldTypeDate = ({ - required, - error, - ...props -}: FieldTypeDateProps) => { - const triggerPickerRef = useRef(null); - const textFieldRef = useRef(null); - const [open, setOpen] = useState(false); +export const FieldTypeDate = memo( + ({ required, error, ...props }: FieldTypeDateProps) => { + const triggerPickerRef = useRef(null); + const textFieldRef = useRef(null); + + const handleClear = () => { + /** + * Clear the input value + */ + if (props.onChange) props.onChange(null, null); + }; - const handleClear = () => { /** - * Clear the input value + * This function is used to open the date picker when the input field is clicked + * and refocus the input field when the date picker is opened */ - if (props.onChange) props.onChange(null, null); - }; + const handleOpen = useCallback(() => { + /** + * Step 1: Open the date picker + */ + + if (triggerPickerRef.current) triggerPickerRef.current?.click(); + /** + * Step 2: Refocus the input field + */ + + if (textFieldRef.current) { + /** + * Add delay to ensure the picker is rendered before refocusing the input field + */ + setTimeout(() => { + textFieldRef.current.focus(); + }, 0); + } + }, [triggerPickerRef, textFieldRef]); + + console.log("rerender"); - return ( - { + return ( + - - - setOpen(false)} - {...props} - disableHighlightToday={!!props.value} - slotProps={{ - desktopPaper: { - sx: { - mt: 1, + fieldMonthPlaceholder: () => { + return "Mon"; + }, + fieldDayPlaceholder: () => { + return "DD"; + }, + fieldYearPlaceholder: () => { + return "YYYY"; + }, + }} + dateAdapter={AdapterDateFns} + > + + + { - triggerPickerRef.current?.click(); - textFieldRef.current?.focus(); + textField: { + onClick: handleOpen, }, - placeholder: "Mon DD YYYY", - }, - openPickerButton: { - ref: triggerPickerRef, - }, - inputAdornment: { - position: "start", + openPickerButton: { + ref: triggerPickerRef, + }, + inputAdornment: { + position: "start", + }, + }} + /> + + + - - - ); -}; + + Clear + + + + + ); + } +); From c9c465729facf5dd3b12b05baecaf3ef152363da Mon Sep 17 00:00:00 2001 From: jomarmontuya Date: Mon, 4 Mar 2024 23:53:01 +0800 Subject: [PATCH 08/20] clear logs --- src/shell/components/FieldTypeDate/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shell/components/FieldTypeDate/index.tsx b/src/shell/components/FieldTypeDate/index.tsx index 171fc7cea1..748dee7148 100644 --- a/src/shell/components/FieldTypeDate/index.tsx +++ b/src/shell/components/FieldTypeDate/index.tsx @@ -51,8 +51,6 @@ export const FieldTypeDate = memo( } }, [triggerPickerRef, textFieldRef]); - console.log("rerender"); - return ( Date: Tue, 5 Mar 2024 23:31:09 +0800 Subject: [PATCH 09/20] keep button default styling --- src/shell/components/FieldTypeDate/index.tsx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/shell/components/FieldTypeDate/index.tsx b/src/shell/components/FieldTypeDate/index.tsx index 748dee7148..6d8ad6cc37 100644 --- a/src/shell/components/FieldTypeDate/index.tsx +++ b/src/shell/components/FieldTypeDate/index.tsx @@ -4,10 +4,9 @@ import { DatePickerProps, } from "@mui/x-date-pickers-pro"; import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; -import { Ref, memo, useCallback, useRef, useState } from "react"; +import { memo, useCallback, useRef } from "react"; import Button from "@mui/material/Button"; import { Typography, Stack, Box } from "@mui/material"; -import { parse } from "date-fns"; export interface FieldTypeDateProps extends DatePickerProps { name: string; @@ -69,7 +68,7 @@ export const FieldTypeDate = memo( }} dateAdapter={AdapterDateFns} > - +