PasswordPage.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { Transition } from '@headlessui/react';
  2. import { Form, Head } from '@inertiajs/react';
  3. import { useRef } from 'react';
  4. import PasswordController from '@/actions/App/Http/Controllers/Settings/PasswordController';
  5. import { HeadingSmall } from '@/common/HeadingSmall';
  6. import { InputError } from '@/common/InputError';
  7. import { type BreadcrumbItem } from '@/common/types';
  8. import AppLayout from '@/pages/layouts/AppLayout';
  9. import SettingsLayout from '@/pages/layouts/settings/layout';
  10. import { edit } from '@/routes/password';
  11. import { Button } from '@/shadcn/button';
  12. import { Input } from '@/shadcn/input';
  13. import { Label } from '@/shadcn/label';
  14. const breadcrumbs: BreadcrumbItem[] = [
  15. {
  16. title: 'Password settings',
  17. href: edit().url,
  18. },
  19. ];
  20. export default function PasswordPage() {
  21. const passwordInput = useRef<HTMLInputElement>(null);
  22. const currentPasswordInput = useRef<HTMLInputElement>(null);
  23. return (
  24. <AppLayout breadcrumbs={breadcrumbs}>
  25. <Head title="Password settings" />
  26. <SettingsLayout>
  27. <div className="space-y-6">
  28. <HeadingSmall title="Update password" description="Ensure your account is using a long, random password to stay secure" />
  29. <Form
  30. {...PasswordController.update.form()}
  31. options={{
  32. preserveScroll: true,
  33. }}
  34. resetOnError={['password', 'password_confirmation', 'current_password']}
  35. resetOnSuccess
  36. onError={(errors) => {
  37. if (errors.password) {
  38. passwordInput.current?.focus();
  39. }
  40. if (errors.current_password) {
  41. currentPasswordInput.current?.focus();
  42. }
  43. }}
  44. className="space-y-6"
  45. >
  46. {({ errors, processing, recentlySuccessful }) => (
  47. <>
  48. <div className="grid gap-2">
  49. <Label htmlFor="current_password">Current password</Label>
  50. <Input
  51. id="current_password"
  52. ref={currentPasswordInput}
  53. name="current_password"
  54. type="password"
  55. className="mt-1 block w-full"
  56. autoComplete="current-password"
  57. placeholder="Current password"
  58. />
  59. <InputError message={errors.current_password} />
  60. </div>
  61. <div className="grid gap-2">
  62. <Label htmlFor="password">New password</Label>
  63. <Input
  64. id="password"
  65. ref={passwordInput}
  66. name="password"
  67. type="password"
  68. className="mt-1 block w-full"
  69. autoComplete="new-password"
  70. placeholder="New password"
  71. />
  72. <InputError message={errors.password} />
  73. </div>
  74. <div className="grid gap-2">
  75. <Label htmlFor="password_confirmation">Confirm password</Label>
  76. <Input
  77. id="password_confirmation"
  78. name="password_confirmation"
  79. type="password"
  80. className="mt-1 block w-full"
  81. autoComplete="new-password"
  82. placeholder="Confirm password"
  83. />
  84. <InputError message={errors.password_confirmation} />
  85. </div>
  86. <div className="flex items-center gap-4">
  87. <Button disabled={processing}>Save password</Button>
  88. <Transition
  89. show={recentlySuccessful}
  90. enter="transition ease-in-out"
  91. enterFrom="opacity-0"
  92. leave="transition ease-in-out"
  93. leaveTo="opacity-0"
  94. >
  95. <p className="text-sm text-neutral-600">Saved</p>
  96. </Transition>
  97. </div>
  98. </>
  99. )}
  100. </Form>
  101. </div>
  102. </SettingsLayout>
  103. </AppLayout>
  104. );
  105. }