DatabasePasswordInput.tsx 3.1 KB

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