DatabasePasswordInput.tsx92 lines · main
1import { UseFormReturn } from 'react-hook-form'
2import { FormControl, FormField } from 'ui'
3import { Input } from 'ui-patterns/DataInputs/Input'
4import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
5
6import { DATABASE_PASSWORD_REGEX } from './ProjectCreation.constants'
7import { CreateProjectForm } from './ProjectCreation.schema'
8import { SpecialSymbolsCallout } from './SpecialSymbolsCallout'
9import Panel from '@/components/ui/Panel'
10import { PasswordStrengthBar } from '@/components/ui/PasswordStrengthBar'
11import { passwordStrength } from '@/lib/password-strength'
12import { generateStrongPassword } from '@/lib/project'
13
14interface DatabasePasswordInputProps {
15 form: UseFormReturn<CreateProjectForm>
16}
17
18const updatePasswordStrength = async (form: UseFormReturn<CreateProjectForm>, value: string) => {
19 try {
20 const { warning, message, strength } = await passwordStrength(value)
21 form.setValue('dbPassStrength', strength, { shouldValidate: false, shouldDirty: false })
22 form.setValue('dbPassStrengthMessage', message ?? '', {
23 shouldValidate: false,
24 shouldDirty: false,
25 })
26 form.setValue('dbPassStrengthWarning', warning ?? '', {
27 shouldValidate: false,
28 shouldDirty: false,
29 })
30
31 form.trigger('dbPass')
32 } catch (error) {
33 console.error(error)
34 }
35}
36
37export const DatabasePasswordInput = ({ form }: DatabasePasswordInputProps) => {
38 // [Refactor] DB Password could be a common component used in multiple pages with repeated logic
39 async function generatePassword() {
40 const password = generateStrongPassword()
41 form.setValue('dbPass', password)
42
43 updatePasswordStrength(form, password)
44 }
45
46 return (
47 <Panel.Content>
48 <FormField
49 control={form.control}
50 name="dbPass"
51 render={({ field }) => {
52 const isInvalidDatabasePassword =
53 field.value.length > 0 && !field.value.match(DATABASE_PASSWORD_REGEX)
54
55 return (
56 <FormItemLayout
57 label="Database password"
58 layout="horizontal"
59 description={
60 <>
61 {isInvalidDatabasePassword && <SpecialSymbolsCallout />}
62 <PasswordStrengthBar
63 passwordStrengthScore={form.getValues('dbPassStrength')}
64 password={field.value}
65 passwordStrengthMessage={form.getValues('dbPassStrengthMessage')}
66 generateStrongPassword={generatePassword}
67 />
68 </>
69 }
70 >
71 <FormControl>
72 <Input
73 copy={field.value.length > 0}
74 type="password"
75 placeholder="Type in a strong password"
76 {...field}
77 autoComplete="off"
78 onChange={async (event) => {
79 const newValue = event.target.value
80 field.onChange(event)
81
82 updatePasswordStrength(form, newValue)
83 }}
84 />
85 </FormControl>
86 </FormItemLayout>
87 )
88 }}
89 />
90 </Panel.Content>
91 )
92}