From bf88df7294ff3b7fc9e5deaa7c1fdcd6e0b88911 Mon Sep 17 00:00:00 2001 From: viet nguyen Date: Sat, 11 Nov 2023 21:35:23 -0800 Subject: [PATCH] test loading skeleton & new form --- src/app/area/[...slug]/SingleEntryForm.tsx | 4 ++-- src/app/area/[...slug]/page.tsx | 2 +- src/app/editArea/[slug]/Skeleton.tsx | 10 ++++++++ src/app/editArea/[slug]/attributes/page.tsx | 4 ++-- src/app/editArea/[slug]/layout.tsx | 3 ++- src/app/editArea/[slug]/page.tsx | 24 +++++++++++++------ src/components/editor/MarkdownEditor.tsx | 10 +------- .../plugins/ReactHookFormFieldPlugin.tsx | 16 ++++++------- src/components/ui/form/MDTextArea.tsx | 5 ++-- 9 files changed, 45 insertions(+), 33 deletions(-) create mode 100644 src/app/editArea/[slug]/Skeleton.tsx diff --git a/src/app/area/[...slug]/SingleEntryForm.tsx b/src/app/area/[...slug]/SingleEntryForm.tsx index 28f055ae6..024dcbb0f 100644 --- a/src/app/area/[...slug]/SingleEntryForm.tsx +++ b/src/app/area/[...slug]/SingleEntryForm.tsx @@ -6,7 +6,7 @@ export interface SingleEntryFormProps { children: ReactNode initialValues: DefaultValues validationMode?: keyof ValidationMode - submitHandler: (formData: T) => Promise + submitHandler: (formData: T) => Promise | void } export function SingleEntryForm ({ children, initialValues, submitHandler, validationMode = 'onBlur' }: SingleEntryFormProps): ReactNode { @@ -22,7 +22,7 @@ export function SingleEntryForm ({ children, initialValue {/* eslint-disable-next-line */}
{ await submitHandler(data) - reset() // clear isDirty flag + reset({ ...data }, { keepValues: true }) // clear isDirty flag } )} > diff --git a/src/app/area/[...slug]/page.tsx b/src/app/area/[...slug]/page.tsx index 7c2581779..3ea77c8bb 100644 --- a/src/app/area/[...slug]/page.tsx +++ b/src/app/area/[...slug]/page.tsx @@ -83,7 +83,7 @@ export default async function Page ({ params }: PageWithCatchAllUuidProps): Prom /** * Extract and validate uuid as the first param in a catch-all route */ -export const parseUuidAsFirstParam = ({ params }: PageWithCatchAllUuidProps): string => { +const parseUuidAsFirstParam = ({ params }: PageWithCatchAllUuidProps): string => { if (params.slug.length === 0) { notFound() } diff --git a/src/app/editArea/[slug]/Skeleton.tsx b/src/app/editArea/[slug]/Skeleton.tsx new file mode 100644 index 000000000..dd981d87a --- /dev/null +++ b/src/app/editArea/[slug]/Skeleton.tsx @@ -0,0 +1,10 @@ +import { PageContainer } from './page' + +export default function Loading (): JSX.Element { + return ( + <> +
+
+ + ) +} diff --git a/src/app/editArea/[slug]/attributes/page.tsx b/src/app/editArea/[slug]/attributes/page.tsx index d321b8301..40df21977 100644 --- a/src/app/editArea/[slug]/attributes/page.tsx +++ b/src/app/editArea/[slug]/attributes/page.tsx @@ -1,6 +1,6 @@ -import { EditPageProps, getPageDataForEdit } from '../page' +import { DashboardPageProps, getPageDataForEdit } from '../page' -export default async function AreaEditPage ({ params }: EditPageProps): Promise { +export default async function AreaEditPage ({ params }: DashboardPageProps): Promise { const { area } = await getPageDataForEdit(params.slug) return (
Attributes {JSON.stringify(area, null, 2)}
) } diff --git a/src/app/editArea/[slug]/layout.tsx b/src/app/editArea/[slug]/layout.tsx index eaae1f0e5..316b57d6b 100644 --- a/src/app/editArea/[slug]/layout.tsx +++ b/src/app/editArea/[slug]/layout.tsx @@ -3,7 +3,8 @@ import { SidebarNav } from './SidebarNav' export default function RootLayout ({ children, params }: { - children: React.ReactNode, params: { slug: string } + children: React.ReactNode + params: { slug: string } }): any { return (
diff --git a/src/app/editArea/[slug]/page.tsx b/src/app/editArea/[slug]/page.tsx index d07139f04..8ad707510 100644 --- a/src/app/editArea/[slug]/page.tsx +++ b/src/app/editArea/[slug]/page.tsx @@ -1,35 +1,45 @@ import { notFound } from 'next/navigation' import { validate } from 'uuid' +import { Suspense, ReactNode } from 'react' import { AreaPageDataProps, getArea } from '@/js/graphql/getArea' import { AreaNameForm } from './general/AreaNameForm' import { AreaDescriptionForm } from './general/AreaDescriptionForm' import { AreaLatLngForm } from './general/AreaLatLngForm' +import Loading from './Skeleton' // Opt out of caching for all data requests in the route segment export const dynamic = 'force-dynamic' -interface Props { +export interface DashboardPageProps { params: { slug: string } } -export default async function AreaEditPage ({ params }: Props): Promise { +export default async function AreaEditPage ({ params }: DashboardPageProps): Promise { const areaUuid = params.slug if (!validate(areaUuid)) { notFound() } const { area: { areaName, uuid, content: { description }, metadata: { lat, lng } } } = await getPageDataForEdit(areaUuid) return ( -
- - - -
+ + }> + + + + + ) } +export const PageContainer: React.FC<{ children: ReactNode } > = ({ children }) => ( +
+ {children} +
+) + export const getPageDataForEdit = async (uuid: string): Promise => { if (uuid == null) notFound() diff --git a/src/components/editor/MarkdownEditor.tsx b/src/components/editor/MarkdownEditor.tsx index e44203f9e..ef91f8c40 100644 --- a/src/components/editor/MarkdownEditor.tsx +++ b/src/components/editor/MarkdownEditor.tsx @@ -7,11 +7,9 @@ import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin' import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary' import { ListPlugin } from '@lexical/react/LexicalListPlugin' import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin' -import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin' import { mdeditorConfig } from './editorConfig' import { MarkdownPreviewPlugin } from './plugins/MarkdownPreviewPlugin' -import { PlainTextResetPlugin } from './plugins/PlainTextResetPlugin' import { ReactHookFormFieldPlugin } from './plugins/ReactHookFormFieldPlugin' import { RulesType } from '../../js/types' @@ -27,7 +25,7 @@ export interface MarkdownEditorProps { /** * Multiline inplace editor with react-hook-form support. */ -export const MarkdownEditor: React.FC = ({ fieldName, initialValue = '', preview = false, reset, placeholder = 'Enter some text', rules }) => { +export const MarkdownEditor: React.FC = ({ fieldName, initialValue = '', preview = false, placeholder = 'Enter some text', rules }) => { // const { field, fieldState: { error } } = useController({ name: fieldName, rules }) // const onChangeHandler = (arg0: EditorState, arg1: LexicalEditor): void => { @@ -51,17 +49,11 @@ export const MarkdownEditor: React.FC = ({ fieldName, initi ) : ( <> - } placeholder={} ErrorBoundary={LexicalErrorBoundary} /> - )} diff --git a/src/components/editor/plugins/ReactHookFormFieldPlugin.tsx b/src/components/editor/plugins/ReactHookFormFieldPlugin.tsx index d6b5bdaeb..59d35892c 100644 --- a/src/components/editor/plugins/ReactHookFormFieldPlugin.tsx +++ b/src/components/editor/plugins/ReactHookFormFieldPlugin.tsx @@ -1,7 +1,9 @@ -import { useEffect } from 'react' -import { $getRoot } from 'lexical' +import { useCallback } from 'react' +import { $getRoot, EditorState } from 'lexical' import { useController } from 'react-hook-form' +import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' + import { RulesType } from '@/js/types' /** @@ -10,14 +12,12 @@ import { RulesType } from '@/js/types' export const ReactHookFormFieldPlugin: React.FC<{ fieldName: string, rules?: RulesType }> = ({ fieldName, rules }) => { const { field } = useController({ name: fieldName, rules }) const [editor] = useLexicalComposerContext() - - useEffect(() => { - console.log('#RHF field plugin') - editor.getEditorState().read(() => { + const onChange = useCallback((editorState: EditorState): void => { + editorState.read(() => { const str = $getRoot().getTextContent() console.log('#updating form') field.onChange(str) }) - }) - return null + }, [editor]) + return } diff --git a/src/components/ui/form/MDTextArea.tsx b/src/components/ui/form/MDTextArea.tsx index 0dfb2a130..cf5b4e461 100644 --- a/src/components/ui/form/MDTextArea.tsx +++ b/src/components/ui/form/MDTextArea.tsx @@ -1,6 +1,6 @@ 'use client' import { useState } from 'react' -import { useController, useFormContext } from 'react-hook-form' +import { useController } from 'react-hook-form' import clx from 'classnames' import dynamic from 'next/dynamic' @@ -25,7 +25,6 @@ interface EditorProps { export const MDTextArea: React.FC = ({ initialValue = '', name, placeholder = 'Enter some text', label, description, helper, rules }) => { const { fieldState: { error }, formState: { isValid, isDirty, isSubmitting } } = useController({ name, rules }) const [preview, setPreview] = useState(false) - console.log('#Formstate', isValid, isDirty) return (
@@ -62,5 +61,5 @@ export const MDTextArea: React.FC = ({ initialValue = '', name, pla } export const MarkdownEditor = dynamic(async () => await import('@/components/editor/MarkdownEditor').then( - module => module.MarkdownEditor), { ssr: false } + module => module.MarkdownEditor), { ssr: true } )