mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
chore: migrate docs feedback modal to react-hook-form (#44739)
## Problem The Docs feedback modal still uses the old `Form` component with `formik` ## Solution Migrate it to `react-hook-form` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Enhanced feedback form with schema-driven validation requiring title and comment before submission. * Submission buttons disable while submitting; cancel now also resets the form state. * **Chores** * Added form handling and validation libraries to support the improved feedback experience. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
b8a246f2d7
commit
a9fdb09c66
3 files changed
+120
-80
No files matched your search
@@ -1,10 +1,24 @@
|
||||
import { Button, Form, Input, Modal } from 'ui'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { SubmitHandler, useForm } from 'react-hook-form'
|
||||
import {
|
||||
Button,
|
||||
Form_Shadcn_,
|
||||
FormControl_Shadcn_,
|
||||
FormField_Shadcn_,
|
||||
Input_Shadcn_,
|
||||
Modal,
|
||||
Textarea,
|
||||
} from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import * as z from 'zod'
|
||||
|
||||
export type FeedbackFields = {
|
||||
page: string
|
||||
title: string
|
||||
comment: string
|
||||
}
|
||||
const formSchema = z.object({
|
||||
page: z.string(),
|
||||
title: z.string().min(1, 'Required'),
|
||||
comment: z.string().min(1, 'Required'),
|
||||
})
|
||||
|
||||
export type FeedbackFields = z.infer<typeof formSchema>
|
||||
|
||||
type FeedbackModalProps = {
|
||||
visible: boolean
|
||||
@@ -14,78 +28,92 @@ type FeedbackModalProps = {
|
||||
}
|
||||
|
||||
function FeedbackModal({ visible, page, onCancel, onSubmit }: FeedbackModalProps) {
|
||||
const form = useForm<FeedbackFields>({
|
||||
defaultValues: { page, title: '', comment: '' },
|
||||
resolver: zodResolver(formSchema),
|
||||
})
|
||||
const { reset } = form
|
||||
const { isSubmitting } = form.formState
|
||||
|
||||
const handleCancel = () => {
|
||||
reset()
|
||||
onCancel()
|
||||
}
|
||||
|
||||
const handleSubmit: SubmitHandler<FeedbackFields> = (values) => {
|
||||
onSubmit(values)
|
||||
reset()
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
hideFooter
|
||||
header="Leave a comment"
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
onEscapeKeyDown={onCancel}
|
||||
onCancel={handleCancel}
|
||||
onEscapeKeyDown={handleCancel}
|
||||
>
|
||||
<Form
|
||||
initialValues={{ page, comment: '' }}
|
||||
validateOnBlur
|
||||
validate={(vals) => {
|
||||
const errors: Partial<FeedbackFields> = {}
|
||||
|
||||
if (!vals.title) {
|
||||
errors.title = 'Required'
|
||||
}
|
||||
|
||||
if (!vals.comment) {
|
||||
errors.comment = 'Required'
|
||||
}
|
||||
|
||||
return errors
|
||||
}}
|
||||
onReset={onCancel}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
{({ isSubmitting }: { isSubmitting: boolean }) => (
|
||||
<>
|
||||
<Modal.Content className="pt-4 pb-2 flex flex-col gap-2">
|
||||
<Input type="hidden" id="page" name="page" value={page} />
|
||||
<Input type="text" id="title" name="title" label="Title" className="mb-2" />
|
||||
<Input.TextArea
|
||||
label="Comment"
|
||||
id="comment"
|
||||
name="comment"
|
||||
size="medium"
|
||||
className="mb-2"
|
||||
textAreaClassName="resize-none"
|
||||
afterLabel=" (not anonymous)"
|
||||
/>
|
||||
<div className="flex gap-2 text-xs text-foreground-light leading-relaxed">
|
||||
<span className="flex-shrink-0 mt-0.5">💡</span>
|
||||
<div>
|
||||
<strong>Need help or support?</strong> This feedback form is for documentation
|
||||
improvements only. For technical support, please submit a{' '}
|
||||
<a
|
||||
href="https://supabase.com/dashboard/support/new"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-brand-link hover:underline"
|
||||
>
|
||||
support request
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
<Form_Shadcn_ {...form}>
|
||||
<form onSubmit={form.handleSubmit(handleSubmit)}>
|
||||
<Modal.Content className="pt-4 pb-2 flex flex-col gap-2">
|
||||
<input type="hidden" id="page" {...form.register('page')} />
|
||||
<FormField_Shadcn_
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItemLayout layout="vertical" label="Title">
|
||||
<FormControl_Shadcn_ className="col-span-6">
|
||||
<Input_Shadcn_ {...field} />
|
||||
</FormControl_Shadcn_>
|
||||
</FormItemLayout>
|
||||
)}
|
||||
/>
|
||||
<FormField_Shadcn_
|
||||
control={form.control}
|
||||
name="comment"
|
||||
render={({ field }) => (
|
||||
<FormItemLayout layout="vertical" label="Comment" afterLabel="(not anonymous)">
|
||||
<FormControl_Shadcn_ className="col-span-6">
|
||||
<Textarea {...field} rows={4} className="resize-none" />
|
||||
</FormControl_Shadcn_>
|
||||
</FormItemLayout>
|
||||
)}
|
||||
/>
|
||||
<div className="flex gap-2 text-xs text-foreground-light leading-relaxed">
|
||||
<span className="flex-shrink-0 mt-0.5">💡</span>
|
||||
<div>
|
||||
<strong>Need help or support?</strong> This feedback form is for documentation
|
||||
improvements only. For technical support, please submit a{' '}
|
||||
<a
|
||||
href="https://supabase.com/dashboard/support/new"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-brand-link hover:underline"
|
||||
>
|
||||
support request
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
</Modal.Content>
|
||||
<Modal.Separator />
|
||||
<Modal.Content className="pt-2 pb-4">
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<Button htmlType="reset" type="default" onClick={onCancel} disabled={isSubmitting}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button htmlType="submit" loading={isSubmitting} disabled={isSubmitting}>
|
||||
Submit feedback
|
||||
</Button>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
</>
|
||||
)}
|
||||
</Form>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
<Modal.Separator />
|
||||
<Modal.Content className="pt-2 pb-4">
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<Button
|
||||
htmlType="reset"
|
||||
type="default"
|
||||
onClick={handleCancel}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button htmlType="submit" loading={isSubmitting} disabled={isSubmitting}>
|
||||
Submit feedback
|
||||
</Button>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
</form>
|
||||
</Form_Shadcn_>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@har-sdk/openapi-sampler": "^2.2.0",
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@mdx-js/loader": "^3.0.0",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"@next/bundle-analyzer": "15.3.1",
|
||||
@@ -103,6 +104,7 @@
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-dom": "catalog:",
|
||||
"react-error-boundary": "^4.0.12",
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-intersection-observer": "^9.5.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-use": "^17.5.0",
|
||||
|
||||
Generated
+19
-9
@@ -301,6 +301,9 @@ importers:
|
||||
'@har-sdk/openapi-sampler':
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
'@hookform/resolvers':
|
||||
specifier: ^3.1.1
|
||||
version: 3.3.1(react-hook-form@7.47.0(react@18.3.1))
|
||||
'@mdx-js/loader':
|
||||
specifier: ^3.0.0
|
||||
version: 3.1.1(supports-color@8.1.1)(webpack@5.105.4)
|
||||
@@ -478,6 +481,9 @@ importers:
|
||||
react-error-boundary:
|
||||
specifier: ^4.0.12
|
||||
version: 4.0.13(react@18.3.1)
|
||||
react-hook-form:
|
||||
specifier: ^7.45.0
|
||||
version: 7.47.0(react@18.3.1)
|
||||
react-intersection-observer:
|
||||
specifier: ^9.5.3
|
||||
version: 9.8.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -2538,7 +2544,7 @@ importers:
|
||||
version: 2.30.0
|
||||
formik:
|
||||
specifier: ^2.2.9
|
||||
version: 2.4.5(react@18.3.1)
|
||||
version: 2.4.9(@types/react@18.3.3)(react@18.3.1)
|
||||
framer-motion:
|
||||
specifier: ^11.0.3
|
||||
version: 11.11.17(@emotion/is-prop-valid@1.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -9297,8 +9303,10 @@ packages:
|
||||
'@types/hast@3.0.4':
|
||||
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
|
||||
|
||||
'@types/hoist-non-react-statics@3.3.2':
|
||||
resolution: {integrity: sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw==}
|
||||
'@types/hoist-non-react-statics@3.3.7':
|
||||
resolution: {integrity: sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
|
||||
'@types/js-cookie@2.2.7':
|
||||
resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==}
|
||||
@@ -12359,8 +12367,8 @@ packages:
|
||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
|
||||
formik@2.4.5:
|
||||
resolution: {integrity: sha512-Gxlht0TD3vVdzMDHwkiNZqJ7Mvg77xQNfmBRrNtvzcHZs72TJppSTDKHpImCMJZwcWPBJ8jSQQ95GJzXFf1nAQ==}
|
||||
formik@2.4.9:
|
||||
resolution: {integrity: sha512-5nI94BMnlFDdQRBY4Sz39WkhxajZJ57Fzs8wVbtsQlm5ScKIR1QLYqv/ultBnobObtlUyxpxoLodpixrsf36Og==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
|
||||
@@ -26967,7 +26975,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/unist': 2.0.8
|
||||
|
||||
'@types/hoist-non-react-statics@3.3.2':
|
||||
'@types/hoist-non-react-statics@3.3.7(@types/react@18.3.3)':
|
||||
dependencies:
|
||||
'@types/react': 18.3.3
|
||||
hoist-non-react-statics: 3.3.2
|
||||
@@ -30595,9 +30603,9 @@ snapshots:
|
||||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
|
||||
formik@2.4.5(react@18.3.1):
|
||||
formik@2.4.9(@types/react@18.3.3)(react@18.3.1):
|
||||
dependencies:
|
||||
'@types/hoist-non-react-statics': 3.3.2
|
||||
'@types/hoist-non-react-statics': 3.3.7(@types/react@18.3.3)
|
||||
deepmerge: 2.2.1
|
||||
hoist-non-react-statics: 3.3.2
|
||||
lodash: 4.18.1
|
||||
@@ -30605,7 +30613,9 @@ snapshots:
|
||||
react: 18.3.1
|
||||
react-fast-compare: 2.0.4
|
||||
tiny-warning: 1.0.3
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.1
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
forwarded-parse@2.1.2: {}
|
||||
|
||||
|
||||
Reference in new issue
Block a user