UpdateModal.tsx133 lines · main
1import { zodResolver } from '@hookform/resolvers/zod'
2import { useParams } from 'common'
3import { useEffect } from 'react'
4import { SubmitHandler, useForm } from 'react-hook-form'
5import { toast } from 'sonner'
6import { Button, Form, FormControl, FormField, Input, Modal, Textarea } from 'ui'
7import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
8import * as z from 'zod'
9
10import { Content } from '@/data/content/content-query'
11import { useContentUpsertMutation } from '@/data/content/content-upsert-mutation'
12
13const formSchema = z.object({
14 name: z.string().min(1, 'Required'),
15 description: z.string().optional(),
16})
17
18type CustomReport = z.infer<typeof formSchema>
19
20export interface UpdateCustomReportProps {
21 selectedReport?: Content
22 initialValues: CustomReport
23 onCancel: () => void
24}
25
26export const UpdateCustomReportModal = ({
27 selectedReport,
28 initialValues,
29 onCancel,
30}: UpdateCustomReportProps) => {
31 const { ref } = useParams()
32 const { mutate: updateReport, isPending: isUpdating } = useContentUpsertMutation({
33 onSuccess: () => {
34 toast.success('Successfully updated report')
35 onCancel()
36 },
37 onError: (error) => {
38 toast.error(`Failed to update report: ${error.message}`)
39 },
40 })
41
42 const onConfirmUpdateReport: SubmitHandler<CustomReport> = (newVals) => {
43 if (!ref) return console.error('Project ref is required')
44 if (!selectedReport) return
45 if (!selectedReport.id) return
46 if (!selectedReport.project_id) return
47
48 updateReport({
49 projectRef: ref,
50 payload: {
51 ...selectedReport,
52 owner_id: selectedReport.owner_id!,
53 project_id: selectedReport.project_id,
54 id: selectedReport.id,
55 name: newVals.name,
56 description: newVals.description || '',
57 },
58 })
59 }
60
61 const handleCancel = () => {
62 onCancel()
63 form.reset()
64 }
65
66 const form = useForm<CustomReport>({
67 resolver: zodResolver(formSchema as any),
68 defaultValues: initialValues,
69 })
70 const { formState, reset } = form
71 const { isDirty } = formState
72
73 useEffect(() => {
74 if (isDirty) return
75 reset(initialValues)
76 }, [initialValues, isDirty, reset])
77
78 return (
79 <Modal
80 visible={selectedReport !== undefined}
81 onCancel={handleCancel}
82 hideFooter
83 header="Update custom report"
84 size="small"
85 >
86 <Form {...form}>
87 <form onSubmit={form.handleSubmit(onConfirmUpdateReport)} noValidate>
88 <Modal.Content>
89 <FormField
90 control={form.control}
91 name="name"
92 render={({ field }) => (
93 <FormItemLayout name="name" layout="vertical" label="Name">
94 <FormControl>
95 <Input {...field} id="name" />
96 </FormControl>
97 </FormItemLayout>
98 )}
99 />
100 </Modal.Content>
101 <Modal.Content>
102 <FormField
103 control={form.control}
104 name="description"
105 render={({ field }) => (
106 <FormItemLayout name="description" layout="vertical" label="Description">
107 <FormControl>
108 <Textarea
109 {...field}
110 id="description"
111 rows={4}
112 placeholder="Describe your custom report"
113 className="resize-none"
114 />
115 </FormControl>
116 </FormItemLayout>
117 )}
118 />
119 </Modal.Content>
120 <Modal.Separator />
121 <Modal.Content className="flex items-center justify-end gap-2">
122 <Button htmlType="reset" type="default" onClick={handleCancel} disabled={isUpdating}>
123 Cancel
124 </Button>
125 <Button htmlType="submit" loading={isUpdating} disabled={isUpdating || !isDirty}>
126 Save custom report
127 </Button>
128 </Modal.Content>
129 </form>
130 </Form>
131 </Modal>
132 )
133}