55 *
66 * Copyright Oxide Computer Company
77 */
8- import { useEffect , type ReactNode } from 'react'
8+ import { useEffect , useId , type ReactNode } from 'react'
99import type { FieldValues , UseFormReturn } from 'react-hook-form'
1010import { useNavigationType } from 'react-router-dom'
1111
@@ -14,8 +14,19 @@ import type { ApiError } from '@oxide/api'
1414import { Button } from '~/ui/lib/Button'
1515import { SideModal } from '~/ui/lib/SideModal'
1616
17+ type CreateFormProps = {
18+ formType : 'create'
19+ /** Only needed if you need to override the default button text (`Create ${resourceName}`) */
20+ submitLabel ?: string
21+ }
22+
23+ type EditFormProps = {
24+ formType : 'edit'
25+ /** Not permitted, as all edit form buttons should read `Update ${resourceName}` */
26+ submitLabel ?: never
27+ }
28+
1729type SideModalFormProps < TFieldValues extends FieldValues > = {
18- id : string
1930 form : UseFormReturn < TFieldValues >
2031 /**
2132 * A function that returns the fields.
@@ -27,16 +38,17 @@ type SideModalFormProps<TFieldValues extends FieldValues> = {
2738 */
2839 children : ReactNode
2940 onDismiss : ( ) => void
41+ resourceName : string
3042 /** Must be provided with a reason describing why it's disabled */
3143 submitDisabled ?: string
3244 /** Error from the API call */
3345 submitError : ApiError | null
3446 loading ?: boolean
35- title : string
47+ /** Only needed if you need to override the default title (Create/Edit ${resourceName}) */
48+ title ?: string
3649 subtitle ?: ReactNode
3750 onSubmit ?: ( values : TFieldValues ) => void
38- submitLabel ?: string
39- }
51+ } & ( CreateFormProps | EditFormProps )
4052
4153/**
4254 * Only animate the modal in when we're navigating by a client-side click.
@@ -49,10 +61,11 @@ export function useShouldAnimateModal() {
4961}
5062
5163export function SideModalForm < TFieldValues extends FieldValues > ( {
52- id,
5364 form,
65+ formType,
5466 children,
5567 onDismiss,
68+ resourceName,
5669 submitDisabled,
5770 submitError,
5871 title,
@@ -61,6 +74,7 @@ export function SideModalForm<TFieldValues extends FieldValues>({
6174 loading,
6275 subtitle,
6376} : SideModalFormProps < TFieldValues > ) {
77+ const id = useId ( )
6478 const { isSubmitting } = form . formState
6579
6680 useEffect ( ( ) => {
@@ -70,11 +84,16 @@ export function SideModalForm<TFieldValues extends FieldValues>({
7084 }
7185 } , [ submitError , form ] )
7286
87+ const label =
88+ formType === 'edit'
89+ ? `Update ${ resourceName } `
90+ : submitLabel || title || `Create ${ resourceName } `
91+
7392 return (
7493 < SideModal
7594 onDismiss = { onDismiss }
7695 isOpen
77- title = { title }
96+ title = { title || ` ${ formType === 'edit' ? 'Edit' : 'Create' } ${ resourceName } ` }
7897 animate = { useShouldAnimateModal ( ) }
7998 subtitle = { subtitle }
8099 errors = { submitError ? [ submitError . message ] : [ ] }
@@ -111,7 +130,7 @@ export function SideModalForm<TFieldValues extends FieldValues>({
111130 loading = { loading || isSubmitting }
112131 form = { id }
113132 >
114- { submitLabel || title }
133+ { label }
115134 </ Button >
116135 ) }
117136 </ SideModal . Footer >
0 commit comments