Skip to content

Commit

Permalink
Support default values in the new <FormGridSection> component
Browse files Browse the repository at this point in the history
  • Loading branch information
beverloo committed Jun 21, 2024
1 parent 8234a41 commit a716848
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 12 deletions.
28 changes: 18 additions & 10 deletions app/admin/components/FormGridSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

'use client';

import { useState, useTransition } from 'react';
import { useEffect, useState, useTransition } from 'react';

import { FormProvider, useForm } from '@proxy/react-hook-form-mui';
import { useRouter } from 'next/navigation';
Expand All @@ -28,7 +28,11 @@ interface FormGridSectionOwnProps {
*/
action: ServerAction;

// TODO: defaultValues
/**
* Default values that should be provided to the form. Can be updated while the form is visible,
* in which case all non-dirty fields will have their values updated.
*/
defaultValues?: Record<string, any>;
}

/**
Expand All @@ -48,26 +52,30 @@ export type FormGridSectionProps =
* https://github.com/dohomi/react-hook-form-mui/blob/master/packages/rhf-mui/src/FormContainer.tsx
*/
export function FormGridSection(props: React.PropsWithChildren<FormGridSectionProps>) {
const { action, children, ...sectionHeaderProps } = props;
const { action, children, defaultValues, ...sectionHeaderProps } = props;

const [ isPending, startTransition ] = useTransition();
const [ state, setState ] = useState<ServerActionResult | undefined>();

// TODO: Provide `defaultValues` to the form.

// TODO: Update the form with new `defaultValues` when they have changed, e.g. because the
// router has been refreshed by another update.

// TODO: Convert DayJS values to something that can be read as a ZonedDateTime on the server.

const form = useForm();
const form = useForm({ defaultValues });
const router = useRouter();

useEffect(() => {
form.reset(defaultValues, {
keepDirtyValues: true,
});
}, [ defaultValues, form ]);

const handleSubmit = form.handleSubmit(async (data: unknown) => {
await startTransition(async () => {
const result = await action(data);
if (!!result.success) {
form.reset({ /* fields */ }, { keepValues: true });
form.reset({ /* fields */ }, {
keepDirtyValues: true,
keepValues: true,
});

if (!!result.redirect)
router.push(result.redirect);
Expand Down
11 changes: 11 additions & 0 deletions app/admin/system/debug/DebugOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

'use client';

import { useRouter } from 'next/navigation';

import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';

Expand All @@ -13,6 +15,8 @@ import { Section } from '@app/admin/components/Section';
* JavaScript code and event handlers.
*/
export function DebugOptions() {
const router = useRouter();

const triggerJavaScriptError = () => {
/// @ts-ignore
callFunctionThatDoesNotExist();
Expand All @@ -22,6 +26,10 @@ export function DebugOptions() {
throw new Error('Name of the exception');
};

const refresh = () => {
router.refresh();
};

return (
<Section title="Debugging options">
<Stack direction="row" spacing={2}>
Expand All @@ -31,6 +39,9 @@ export function DebugOptions() {
<Button onClick={triggerJavaScriptException} variant="contained">
JavaScript exception
</Button>
<Button onClick={refresh} variant="contained">
Refresh
</Button>
</Stack>
</Section>
);
Expand Down
13 changes: 11 additions & 2 deletions app/admin/system/debug/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ const kDebugActionScheme = z.object({
notes: z.string().optional(),
});

/**
* Refresh counter showing how often the <DebugPage> component has ran.
*/
let globalRefreshCounter = 0;

/**
* Server action that will be invoked when the form section demo has been submitted. Reflects the
* submitted data back to the client after a slight delay.
Expand All @@ -44,7 +49,7 @@ async function debugAction(formData: unknown) {
'use server';
return executeServerAction(formData, kDebugActionScheme, async (data, props) => {
await new Promise(resolve => setTimeout(resolve, 1500));
return { success: false, error: `Not yet implemented (${props.user?.name})` };
return { success: true, refresh: true };
});
}

Expand All @@ -62,10 +67,14 @@ export default async function DebugPage() {
debugValues['Cookies'] = [ ...cookies() ];
debugValues['Headers'] = [ ...headers() ];

const values = {
notes: `Example notes (count: ${++globalRefreshCounter})`,
};

return (
<>
<DebugOptions />
<FormGridSection action={debugAction} title="Form section demo">
<FormGridSection action={debugAction} defaultValues={values} title="Form section demo">
<Grid xs={12} md={6}>
<TextFieldElement name="username" label="Username" size="small" fullWidth
required />
Expand Down

0 comments on commit a716848

Please sign in to comment.