kaze 0.4.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kaze/commands/install_command.rb +25 -13
  3. data/lib/kaze/commands/installs_hotwire_stack.rb +11 -8
  4. data/lib/kaze/commands/installs_inertia_stacks.rb +34 -24
  5. data/lib/kaze/commands/version_command.rb +6 -0
  6. data/lib/kaze/version.rb +1 -1
  7. data/lib/kaze.rb +1 -3
  8. data/stubs/default/app/forms/auth/login_form.rb +2 -8
  9. data/stubs/default/app/forms/auth/new_password_form.rb +1 -1
  10. data/stubs/default/app/forms/update_profile_information_form.rb +1 -1
  11. data/stubs/default/app/mailers/application_mailer.rb +4 -4
  12. data/stubs/default/app/mailers/user_mailer.rb +1 -1
  13. data/stubs/default/app/models/auth.rb +57 -0
  14. data/stubs/default/app/models/current.rb +1 -1
  15. data/stubs/default/app/validators/current_password_validator.rb +1 -1
  16. data/stubs/default/app/validators/email_validator.rb +1 -1
  17. data/stubs/default/app/validators/lowercase_validator.rb +2 -2
  18. data/stubs/default/app/views/layouts/mailer.html.erb +367 -372
  19. data/stubs/default/app/views/layouts/mailer.text.erb +1 -4
  20. data/stubs/default/app/views/user_mailer/reset_password.html.erb +21 -26
  21. data/stubs/default/config/routes.rb +16 -16
  22. data/stubs/default/db/migrate/20240101000001_create_delayed_jobs.rb +1 -1
  23. data/stubs/default/test/factories/users.rb +7 -0
  24. data/stubs/default/test/integration/auth/authentication_test.rb +43 -0
  25. data/stubs/default/test/integration/auth/password_reset_test.rb +41 -0
  26. data/stubs/default/test/integration/auth/registration_test.rb +21 -0
  27. data/stubs/default/test/integration/password_update_test.rb +28 -0
  28. data/stubs/default/test/integration/profile_test.rb +51 -0
  29. data/stubs/default/test/test_helper.rb +38 -0
  30. data/stubs/hotwire/app/components/danger_button_component.rb +1 -1
  31. data/stubs/hotwire/app/components/dropdown_component.html.erb +17 -18
  32. data/stubs/hotwire/app/components/dropdown_component.rb +7 -7
  33. data/stubs/hotwire/app/components/modal_component.html.erb +55 -59
  34. data/stubs/hotwire/app/components/modal_component.rb +6 -6
  35. data/stubs/hotwire/app/components/primary_button_component.rb +1 -1
  36. data/stubs/hotwire/app/components/secondary_button_component.rb +1 -1
  37. data/stubs/hotwire/app/controllers/application_controller.rb +1 -0
  38. data/stubs/hotwire/app/controllers/auth/authenticated_session_controller.rb +12 -9
  39. data/stubs/hotwire/app/controllers/auth/new_password_controller.rb +7 -5
  40. data/stubs/hotwire/app/controllers/auth/password_reset_link_controller.rb +7 -5
  41. data/stubs/hotwire/app/controllers/auth/registered_user_controller.rb +7 -5
  42. data/stubs/hotwire/app/controllers/concerns/authenticate.rb +5 -20
  43. data/stubs/hotwire/app/controllers/concerns/redirect_if_authenticated.rb +19 -0
  44. data/stubs/hotwire/app/controllers/concerns/set_current_auth.rb +9 -0
  45. data/stubs/hotwire/app/controllers/password_controller.rb +3 -3
  46. data/stubs/hotwire/app/controllers/profile_controller.rb +11 -9
  47. data/stubs/hotwire/app/controllers/welcome_controller.rb +1 -1
  48. data/stubs/hotwire/app/javascript/application.js +3 -3
  49. data/stubs/hotwire/app/views/auth/forgot_password.html.erb +12 -17
  50. data/stubs/hotwire/app/views/auth/login.html.erb +0 -9
  51. data/stubs/hotwire/app/views/auth/register.html.erb +0 -13
  52. data/stubs/hotwire/app/views/auth/reset_password.html.erb +0 -7
  53. data/stubs/hotwire/app/views/dashboard/index.html.erb +9 -10
  54. data/stubs/hotwire/app/views/layouts/_navigation.html.erb +77 -87
  55. data/stubs/hotwire/app/views/layouts/application.html.erb +0 -9
  56. data/stubs/hotwire/app/views/layouts/guest.html.erb +0 -6
  57. data/stubs/hotwire/app/views/profile/edit.html.erb +19 -22
  58. data/stubs/hotwire/app/views/profile/partials/_delete_user_form.html.erb +32 -42
  59. data/stubs/hotwire/app/views/profile/partials/_update_password_form.html.erb +42 -55
  60. data/stubs/hotwire/app/views/profile/partials/_update_profile_information_form.html.erb +36 -46
  61. data/stubs/hotwire/app/views/welcome/index.html.erb +34 -46
  62. data/stubs/hotwire/config/importmap.rb +3 -3
  63. data/stubs/hotwire/config/tailwind.config.js +2 -2
  64. data/stubs/inertia-common/app/controllers/application_controller.rb +1 -0
  65. data/stubs/inertia-common/app/controllers/auth/authenticated_session_controller.rb +11 -8
  66. data/stubs/inertia-common/app/controllers/auth/new_password_controller.rb +5 -3
  67. data/stubs/inertia-common/app/controllers/auth/password_reset_link_controller.rb +5 -3
  68. data/stubs/inertia-common/app/controllers/auth/registered_user_controller.rb +5 -3
  69. data/stubs/inertia-common/app/controllers/concerns/authenticate.rb +5 -20
  70. data/stubs/inertia-common/app/controllers/concerns/handle_inertia_requests.rb +1 -1
  71. data/stubs/inertia-common/app/controllers/concerns/redirect_if_authenticated.rb +19 -0
  72. data/stubs/inertia-common/app/controllers/concerns/set_current_auth.rb +9 -0
  73. data/stubs/inertia-common/app/controllers/concerns/verify_csrf_token.rb +4 -4
  74. data/stubs/inertia-common/app/controllers/dashboard_controller.rb +1 -1
  75. data/stubs/inertia-common/app/controllers/password_controller.rb +1 -1
  76. data/stubs/inertia-common/app/controllers/profile_controller.rb +7 -5
  77. data/stubs/inertia-common/app/controllers/welcome_controller.rb +2 -2
  78. data/stubs/inertia-common/bin/vite +6 -6
  79. data/stubs/inertia-common/test/integration/password_update_test.rb +28 -0
  80. data/stubs/inertia-common/test/integration/profile_test.rb +51 -0
  81. data/stubs/inertia-react-ts/app/javascript/Components/ApplicationLogo.tsx +13 -9
  82. data/stubs/inertia-react-ts/app/javascript/Components/Checkbox.tsx +15 -12
  83. data/stubs/inertia-react-ts/app/javascript/Components/DangerButton.tsx +20 -15
  84. data/stubs/inertia-react-ts/app/javascript/Components/Dropdown.tsx +119 -87
  85. data/stubs/inertia-react-ts/app/javascript/Components/InputError.tsx +14 -7
  86. data/stubs/inertia-react-ts/app/javascript/Components/InputLabel.tsx +18 -7
  87. data/stubs/inertia-react-ts/app/javascript/Components/Modal.tsx +60 -60
  88. data/stubs/inertia-react-ts/app/javascript/Components/NavLink.tsx +21 -16
  89. data/stubs/inertia-react-ts/app/javascript/Components/PrimaryButton.tsx +20 -15
  90. data/stubs/inertia-react-ts/app/javascript/Components/ResponsiveNavLink.tsx +19 -14
  91. data/stubs/inertia-react-ts/app/javascript/Components/SecondaryButton.tsx +22 -16
  92. data/stubs/inertia-react-ts/app/javascript/Components/TextInput.tsx +35 -24
  93. data/stubs/inertia-react-ts/app/javascript/Layouts/AuthenticatedLayout.tsx +157 -117
  94. data/stubs/inertia-react-ts/app/javascript/Layouts/GuestLayout.tsx +15 -15
  95. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ForgotPassword.tsx +52 -49
  96. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Login.tsx +90 -82
  97. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Register.tsx +118 -115
  98. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ResetPassword.tsx +63 -60
  99. data/stubs/inertia-react-ts/app/javascript/Pages/Dashboard.tsx +23 -17
  100. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Edit.tsx +31 -27
  101. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.tsx +109 -99
  102. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.tsx +121 -113
  103. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.tsx +76 -69
  104. data/stubs/inertia-react-ts/app/javascript/Pages/Welcome.tsx +87 -63
  105. data/stubs/inertia-react-ts/app/javascript/entrypoints/application.tsx +32 -25
  106. data/stubs/inertia-react-ts/app/views/layouts/application.html.erb +0 -4
  107. data/stubs/inertia-react-ts/config/tailwind.config.js +2 -2
  108. data/stubs/inertia-react-ts/vite.config.ts +2 -5
  109. data/stubs/inertia-vue-ts/app/javascript/Components/ApplicationLogo.vue +10 -6
  110. data/stubs/inertia-vue-ts/app/javascript/Components/Checkbox.vue +18 -18
  111. data/stubs/inertia-vue-ts/app/javascript/Components/DangerButton.vue +5 -5
  112. data/stubs/inertia-vue-ts/app/javascript/Components/Dropdown.vue +60 -57
  113. data/stubs/inertia-vue-ts/app/javascript/Components/DropdownLink.vue +9 -9
  114. data/stubs/inertia-vue-ts/app/javascript/Components/InputError.vue +7 -7
  115. data/stubs/inertia-vue-ts/app/javascript/Components/InputLabel.vue +6 -6
  116. data/stubs/inertia-vue-ts/app/javascript/Components/Modal.vue +84 -74
  117. data/stubs/inertia-vue-ts/app/javascript/Components/NavLink.vue +12 -12
  118. data/stubs/inertia-vue-ts/app/javascript/Components/PrimaryButton.vue +5 -5
  119. data/stubs/inertia-vue-ts/app/javascript/Components/ResponsiveNavLink.vue +12 -12
  120. data/stubs/inertia-vue-ts/app/javascript/Components/SecondaryButton.vue +13 -13
  121. data/stubs/inertia-vue-ts/app/javascript/Components/TextInput.vue +13 -13
  122. data/stubs/inertia-vue-ts/app/javascript/Layouts/AuthenticatedLayout.vue +168 -136
  123. data/stubs/inertia-vue-ts/app/javascript/Layouts/GuestLayout.vue +15 -13
  124. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ForgotPassword.vue +56 -49
  125. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Login.vue +78 -72
  126. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Register.vue +101 -97
  127. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ResetPassword.vue +71 -68
  128. data/stubs/inertia-vue-ts/app/javascript/Pages/Dashboard.vue +22 -14
  129. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Edit.vue +34 -30
  130. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.vue +87 -83
  131. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.vue +105 -98
  132. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.vue +69 -59
  133. data/stubs/inertia-vue-ts/app/javascript/Pages/Welcome.vue +74 -47
  134. data/stubs/inertia-vue-ts/app/views/layouts/application.html.erb +0 -4
  135. data/stubs/inertia-vue-ts/config/tailwind.config.js +2 -2
  136. data/stubs/inertia-vue-ts/vite.config.ts +2 -5
  137. metadata +19 -6
  138. data/stubs/hotwire/bin/vite +0 -27
  139. data/stubs/inertia-common/Procfile.dev +0 -3
  140. /data/stubs/{hotwire → default}/Procfile.dev +0 -0
  141. /data/stubs/hotwire/app/javascript/{alpinejs.js → alpinejs.stub} +0 -0
@@ -1,100 +1,110 @@
1
- import { useRef, useState, FormEventHandler } from 'react';
2
- import DangerButton from '@/Components/DangerButton';
3
- import InputError from '@/Components/InputError';
4
- import InputLabel from '@/Components/InputLabel';
5
- import Modal from '@/Components/Modal';
6
- import SecondaryButton from '@/Components/SecondaryButton';
7
- import TextInput from '@/Components/TextInput';
8
- import { useForm } from '@inertiajs/react';
9
- import { profile_destroy_path } from '@/routes';
10
-
11
- export default function DeleteUserForm({ className = '' }: { className?: string }) {
12
- const [confirmingUserDeletion, setConfirmingUserDeletion] = useState(false);
13
- const passwordInput = useRef<HTMLInputElement>(null);
14
-
15
- const {
16
- data,
17
- setData,
18
- delete: destroy,
19
- processing,
20
- reset,
21
- errors,
22
- } = useForm({
23
- password: '',
24
- });
25
-
26
- const confirmUserDeletion = () => {
27
- setConfirmingUserDeletion(true);
28
- };
29
-
30
- const deleteUser: FormEventHandler = (e) => {
31
- e.preventDefault();
32
-
33
- destroy(profile_destroy_path(), {
34
- preserveScroll: true,
35
- onSuccess: () => closeModal(),
36
- onError: () => passwordInput.current?.focus(),
37
- onFinish: () => reset(),
38
- });
39
- };
40
-
41
- const closeModal = () => {
42
- setConfirmingUserDeletion(false);
43
-
44
- reset();
45
- };
46
-
47
- return (
48
- <section className={`space-y-6 ${className}`}>
49
- <header>
50
- <h2 className="text-lg font-medium text-gray-900">Delete Account</h2>
51
-
52
- <p className="mt-1 text-sm text-gray-600">
53
- Once your account is deleted, all of its resources and data will be permanently deleted. Before
54
- deleting your account, please download any data or information that you wish to retain.
55
- </p>
56
- </header>
57
-
58
- <DangerButton onClick={confirmUserDeletion}>Delete Account</DangerButton>
59
-
60
- <Modal show={confirmingUserDeletion} onClose={closeModal}>
61
- <form onSubmit={deleteUser} className="p-6">
62
- <h2 className="text-lg font-medium text-gray-900">
63
- Are you sure you want to delete your account?
64
- </h2>
65
-
66
- <p className="mt-1 text-sm text-gray-600">
67
- Once your account is deleted, all of its resources and data will be permanently deleted. Please
68
- enter your password to confirm you would like to permanently delete your account.
69
- </p>
70
-
71
- <div className="mt-6">
72
- <InputLabel htmlFor="password" value="Password" className="sr-only" />
73
-
74
- <TextInput
75
- id="password"
76
- type="password"
77
- name="password"
78
- ref={passwordInput}
79
- value={data.password}
80
- onChange={(e) => setData('password', e.target.value)}
81
- className="mt-1 block w-3/4"
82
- isFocused
83
- placeholder="Password"
84
- />
85
-
86
- <InputError message={errors.password} className="mt-2" />
87
- </div>
88
-
89
- <div className="mt-6 flex justify-end">
90
- <SecondaryButton onClick={closeModal}>Cancel</SecondaryButton>
91
-
92
- <DangerButton className="ms-3" disabled={processing}>
93
- Delete Account
94
- </DangerButton>
95
- </div>
96
- </form>
97
- </Modal>
98
- </section>
99
- );
1
+ import { useRef, useState, FormEventHandler } from 'react'
2
+ import DangerButton from '@/Components/DangerButton'
3
+ import InputError from '@/Components/InputError'
4
+ import InputLabel from '@/Components/InputLabel'
5
+ import Modal from '@/Components/Modal'
6
+ import SecondaryButton from '@/Components/SecondaryButton'
7
+ import TextInput from '@/Components/TextInput'
8
+ import { useForm } from '@inertiajs/react'
9
+ import { profile_destroy_path } from '@/routes'
10
+
11
+ export default function DeleteUserForm({
12
+ className = '',
13
+ }: {
14
+ className?: string
15
+ }) {
16
+ const [confirmingUserDeletion, setConfirmingUserDeletion] = useState(false)
17
+ const passwordInput = useRef<HTMLInputElement>(null)
18
+
19
+ const {
20
+ data,
21
+ setData,
22
+ delete: destroy,
23
+ processing,
24
+ reset,
25
+ errors,
26
+ } = useForm({
27
+ password: '',
28
+ })
29
+
30
+ const confirmUserDeletion = () => {
31
+ setConfirmingUserDeletion(true)
32
+ }
33
+
34
+ const deleteUser: FormEventHandler = (e) => {
35
+ e.preventDefault()
36
+
37
+ destroy(profile_destroy_path(), {
38
+ preserveScroll: true,
39
+ onSuccess: () => closeModal(),
40
+ onError: () => passwordInput.current?.focus(),
41
+ onFinish: () => reset(),
42
+ })
43
+ }
44
+
45
+ const closeModal = () => {
46
+ setConfirmingUserDeletion(false)
47
+
48
+ reset()
49
+ }
50
+
51
+ return (
52
+ <section className={`space-y-6 ${className}`}>
53
+ <header>
54
+ <h2 className="text-lg font-medium text-gray-900">Delete Account</h2>
55
+
56
+ <p className="mt-1 text-sm text-gray-600">
57
+ Once your account is deleted, all of its resources and data will be
58
+ permanently deleted. Before deleting your account, please download any
59
+ data or information that you wish to retain.
60
+ </p>
61
+ </header>
62
+
63
+ <DangerButton onClick={confirmUserDeletion}>Delete Account</DangerButton>
64
+
65
+ <Modal show={confirmingUserDeletion} onClose={closeModal}>
66
+ <form onSubmit={deleteUser} className="p-6">
67
+ <h2 className="text-lg font-medium text-gray-900">
68
+ Are you sure you want to delete your account?
69
+ </h2>
70
+
71
+ <p className="mt-1 text-sm text-gray-600">
72
+ Once your account is deleted, all of its resources and data will be
73
+ permanently deleted. Please enter your password to confirm you would
74
+ like to permanently delete your account.
75
+ </p>
76
+
77
+ <div className="mt-6">
78
+ <InputLabel
79
+ htmlFor="password"
80
+ value="Password"
81
+ className="sr-only"
82
+ />
83
+
84
+ <TextInput
85
+ id="password"
86
+ type="password"
87
+ name="password"
88
+ ref={passwordInput}
89
+ value={data.password}
90
+ onChange={(e) => setData('password', e.target.value)}
91
+ className="mt-1 block w-3/4"
92
+ isFocused
93
+ placeholder="Password"
94
+ />
95
+
96
+ <InputError message={errors.password} className="mt-2" />
97
+ </div>
98
+
99
+ <div className="mt-6 flex justify-end">
100
+ <SecondaryButton onClick={closeModal}>Cancel</SecondaryButton>
101
+
102
+ <DangerButton className="ms-3" disabled={processing}>
103
+ Delete Account
104
+ </DangerButton>
105
+ </div>
106
+ </form>
107
+ </Modal>
108
+ </section>
109
+ )
100
110
  }
@@ -1,114 +1,122 @@
1
- import { useRef, FormEventHandler } from 'react';
2
- import InputError from '@/Components/InputError';
3
- import InputLabel from '@/Components/InputLabel';
4
- import PrimaryButton from '@/Components/PrimaryButton';
5
- import TextInput from '@/Components/TextInput';
6
- import { useForm } from '@inertiajs/react';
7
- import { Transition } from '@headlessui/react';
8
- import { password_update_path } from '@/routes';
9
-
10
- export default function UpdatePasswordForm({ className = '' }: { className?: string }) {
11
- const passwordInput = useRef<HTMLInputElement>(null);
12
- const currentPasswordInput = useRef<HTMLInputElement>(null);
13
-
14
- const { data, setData, errors, put, reset, processing, recentlySuccessful } = useForm({
15
- current_password: '',
16
- password: '',
17
- password_confirmation: '',
18
- });
19
-
20
- const updatePassword: FormEventHandler = (e) => {
21
- e.preventDefault();
22
-
23
- put(password_update_path(), {
24
- preserveScroll: true,
25
- onSuccess: () => reset(),
26
- onError: (errors) => {
27
- if (errors.password) {
28
- reset('password', 'password_confirmation');
29
- passwordInput.current?.focus();
30
- }
31
-
32
- if (errors.current_password) {
33
- reset('current_password');
34
- currentPasswordInput.current?.focus();
35
- }
36
- },
37
- });
38
- };
39
-
40
- return (
41
- <section className={className}>
42
- <header>
43
- <h2 className="text-lg font-medium text-gray-900">Update Password</h2>
44
-
45
- <p className="mt-1 text-sm text-gray-600">
46
- Ensure your account is using a long, random password to stay secure.
47
- </p>
48
- </header>
49
-
50
- <form onSubmit={updatePassword} className="mt-6 space-y-6">
51
- <div>
52
- <InputLabel htmlFor="current_password" value="Current Password" />
53
-
54
- <TextInput
55
- id="current_password"
56
- ref={currentPasswordInput}
57
- value={data.current_password}
58
- onChange={(e) => setData('current_password', e.target.value)}
59
- type="password"
60
- className="mt-1 block w-full"
61
- autoComplete="current-password"
62
- />
63
-
64
- <InputError message={errors.current_password} className="mt-2" />
65
- </div>
66
-
67
- <div>
68
- <InputLabel htmlFor="password" value="New Password" />
69
-
70
- <TextInput
71
- id="password"
72
- ref={passwordInput}
73
- value={data.password}
74
- onChange={(e) => setData('password', e.target.value)}
75
- type="password"
76
- className="mt-1 block w-full"
77
- autoComplete="new-password"
78
- />
79
-
80
- <InputError message={errors.password} className="mt-2" />
81
- </div>
82
-
83
- <div>
84
- <InputLabel htmlFor="password_confirmation" value="Confirm Password" />
85
-
86
- <TextInput
87
- id="password_confirmation"
88
- value={data.password_confirmation}
89
- onChange={(e) => setData('password_confirmation', e.target.value)}
90
- type="password"
91
- className="mt-1 block w-full"
92
- autoComplete="new-password"
93
- />
94
-
95
- <InputError message={errors.password_confirmation} className="mt-2" />
96
- </div>
97
-
98
- <div className="flex items-center gap-4">
99
- <PrimaryButton disabled={processing}>Save</PrimaryButton>
100
-
101
- <Transition
102
- show={recentlySuccessful}
103
- enter="transition ease-in-out"
104
- enterFrom="opacity-0"
105
- leave="transition ease-in-out"
106
- leaveTo="opacity-0"
107
- >
108
- <p className="text-sm text-gray-600">Saved.</p>
109
- </Transition>
110
- </div>
111
- </form>
112
- </section>
113
- );
1
+ import { useRef, FormEventHandler } from 'react'
2
+ import InputError from '@/Components/InputError'
3
+ import InputLabel from '@/Components/InputLabel'
4
+ import PrimaryButton from '@/Components/PrimaryButton'
5
+ import TextInput from '@/Components/TextInput'
6
+ import { useForm } from '@inertiajs/react'
7
+ import { Transition } from '@headlessui/react'
8
+ import { password_update_path } from '@/routes'
9
+
10
+ export default function UpdatePasswordForm({
11
+ className = '',
12
+ }: {
13
+ className?: string
14
+ }) {
15
+ const passwordInput = useRef<HTMLInputElement>(null)
16
+ const currentPasswordInput = useRef<HTMLInputElement>(null)
17
+
18
+ const { data, setData, errors, put, reset, processing, recentlySuccessful } =
19
+ useForm({
20
+ current_password: '',
21
+ password: '',
22
+ password_confirmation: '',
23
+ })
24
+
25
+ const updatePassword: FormEventHandler = (e) => {
26
+ e.preventDefault()
27
+
28
+ put(password_update_path(), {
29
+ preserveScroll: true,
30
+ onSuccess: () => reset(),
31
+ onError: (errors) => {
32
+ if (errors.password) {
33
+ reset('password', 'password_confirmation')
34
+ passwordInput.current?.focus()
35
+ }
36
+
37
+ if (errors.current_password) {
38
+ reset('current_password')
39
+ currentPasswordInput.current?.focus()
40
+ }
41
+ },
42
+ })
43
+ }
44
+
45
+ return (
46
+ <section className={className}>
47
+ <header>
48
+ <h2 className="text-lg font-medium text-gray-900">Update Password</h2>
49
+
50
+ <p className="mt-1 text-sm text-gray-600">
51
+ Ensure your account is using a long, random password to stay secure.
52
+ </p>
53
+ </header>
54
+
55
+ <form onSubmit={updatePassword} className="mt-6 space-y-6">
56
+ <div>
57
+ <InputLabel htmlFor="current_password" value="Current Password" />
58
+
59
+ <TextInput
60
+ id="current_password"
61
+ ref={currentPasswordInput}
62
+ value={data.current_password}
63
+ onChange={(e) => setData('current_password', e.target.value)}
64
+ type="password"
65
+ className="mt-1 block w-full"
66
+ autoComplete="current-password"
67
+ />
68
+
69
+ <InputError message={errors.current_password} className="mt-2" />
70
+ </div>
71
+
72
+ <div>
73
+ <InputLabel htmlFor="password" value="New Password" />
74
+
75
+ <TextInput
76
+ id="password"
77
+ ref={passwordInput}
78
+ value={data.password}
79
+ onChange={(e) => setData('password', e.target.value)}
80
+ type="password"
81
+ className="mt-1 block w-full"
82
+ autoComplete="new-password"
83
+ />
84
+
85
+ <InputError message={errors.password} className="mt-2" />
86
+ </div>
87
+
88
+ <div>
89
+ <InputLabel
90
+ htmlFor="password_confirmation"
91
+ value="Confirm Password"
92
+ />
93
+
94
+ <TextInput
95
+ id="password_confirmation"
96
+ value={data.password_confirmation}
97
+ onChange={(e) => setData('password_confirmation', e.target.value)}
98
+ type="password"
99
+ className="mt-1 block w-full"
100
+ autoComplete="new-password"
101
+ />
102
+
103
+ <InputError message={errors.password_confirmation} className="mt-2" />
104
+ </div>
105
+
106
+ <div className="flex items-center gap-4">
107
+ <PrimaryButton disabled={processing}>Save</PrimaryButton>
108
+
109
+ <Transition
110
+ show={recentlySuccessful}
111
+ enter="transition ease-in-out"
112
+ enterFrom="opacity-0"
113
+ leave="transition ease-in-out"
114
+ leaveTo="opacity-0"
115
+ >
116
+ <p className="text-sm text-gray-600">Saved.</p>
117
+ </Transition>
118
+ </div>
119
+ </form>
120
+ </section>
121
+ )
114
122
  }
@@ -1,84 +1,91 @@
1
- import InputError from '@/Components/InputError';
2
- import InputLabel from '@/Components/InputLabel';
3
- import PrimaryButton from '@/Components/PrimaryButton';
4
- import TextInput from '@/Components/TextInput';
5
- import { useForm, usePage } from '@inertiajs/react';
6
- import { Transition } from '@headlessui/react';
7
- import { FormEventHandler } from 'react';
8
- import { PageProps } from '@/types';
9
- import { profile_update_path } from '@/routes';
1
+ import InputError from '@/Components/InputError'
2
+ import InputLabel from '@/Components/InputLabel'
3
+ import PrimaryButton from '@/Components/PrimaryButton'
4
+ import TextInput from '@/Components/TextInput'
5
+ import { useForm, usePage } from '@inertiajs/react'
6
+ import { Transition } from '@headlessui/react'
7
+ import { FormEventHandler } from 'react'
8
+ import { PageProps } from '@/types'
9
+ import { profile_update_path } from '@/routes'
10
10
 
11
- export default function UpdateProfileInformation({ className = '' }: { className?: string }) {
12
- const user = usePage<PageProps>().props.auth.user;
11
+ export default function UpdateProfileInformation({
12
+ className = '',
13
+ }: {
14
+ className?: string
15
+ }) {
16
+ const user = usePage<PageProps>().props.auth.user
13
17
 
14
- const { data, setData, patch, errors, processing, recentlySuccessful } = useForm({
15
- name: user.name,
16
- email: user.email,
17
- });
18
+ const { data, setData, patch, errors, processing, recentlySuccessful } =
19
+ useForm({
20
+ name: user.name,
21
+ email: user.email,
22
+ })
18
23
 
19
- const submit: FormEventHandler = (e) => {
20
- e.preventDefault();
24
+ const submit: FormEventHandler = (e) => {
25
+ e.preventDefault()
21
26
 
22
- patch(profile_update_path());
23
- };
27
+ patch(profile_update_path())
28
+ }
24
29
 
25
- return (
26
- <section className={className}>
27
- <header>
28
- <h2 className="text-lg font-medium text-gray-900">Profile Information</h2>
30
+ return (
31
+ <section className={className}>
32
+ <header>
33
+ <h2 className="text-lg font-medium text-gray-900">
34
+ Profile Information
35
+ </h2>
29
36
 
30
- <p className="mt-1 text-sm text-gray-600">
31
- Update your account's profile information and email address.
32
- </p>
33
- </header>
37
+ <p className="mt-1 text-sm text-gray-600">
38
+ Update your account's profile information and email address.
39
+ </p>
40
+ </header>
34
41
 
35
- <form onSubmit={submit} className="mt-6 space-y-6">
36
- <div>
37
- <InputLabel htmlFor="name" value="Name" />
42
+ <form onSubmit={submit} className="mt-6 space-y-6">
43
+ <div>
44
+ <InputLabel htmlFor="name" value="Name" />
38
45
 
39
- <TextInput
40
- id="name"
41
- className="mt-1 block w-full"
42
- value={data.name}
43
- onChange={(e) => setData('name', e.target.value)}
44
- required
45
- isFocused
46
- autoComplete="name"
47
- />
46
+ <TextInput
47
+ id="name"
48
+ className="mt-1 block w-full"
49
+ value={data.name}
50
+ onChange={(e) => setData('name', e.target.value)}
51
+ required
52
+ isFocused
53
+ autoComplete="name"
54
+ />
48
55
 
49
- <InputError className="mt-2" message={errors.name} />
50
- </div>
56
+ <InputError className="mt-2" message={errors.name} />
57
+ </div>
51
58
 
52
- <div>
53
- <InputLabel htmlFor="email" value="Email" />
59
+ <div>
60
+ <InputLabel htmlFor="email" value="Email" />
54
61
 
55
- <TextInput
56
- id="email"
57
- type="email"
58
- className="mt-1 block w-full"
59
- value={data.email}
60
- onChange={(e) => setData('email', e.target.value)}
61
- required
62
- autoComplete="username"
63
- />
62
+ <TextInput
63
+ id="email"
64
+ type="email"
65
+ className="mt-1 block w-full"
66
+ value={data.email}
67
+ onChange={(e) => setData('email', e.target.value)}
68
+ required
69
+ autoComplete="username"
70
+ />
64
71
 
65
- <InputError className="mt-2" message={errors.email} />
66
- </div>
72
+ <InputError className="mt-2" message={errors.email} />
73
+ </div>
67
74
 
68
- <div className="flex items-center gap-4">
69
- <PrimaryButton disabled={processing}>Save</PrimaryButton>
75
+ <div className="flex items-center gap-4">
76
+ <PrimaryButton disabled={processing}>Save</PrimaryButton>
70
77
 
71
- <Transition
72
- show={recentlySuccessful}
73
- enter="transition ease-in-out"
74
- enterFrom="opacity-0"
75
- leave="transition ease-in-out"
76
- leaveTo="opacity-0"
77
- >
78
- <p className="text-sm text-gray-600">Saved.</p>
79
- </Transition>
80
- </div>
81
- </form>
82
- </section>
83
- );
78
+ <Transition
79
+ show={recentlySuccessful}
80
+ enter="transition ease-in-out"
81
+ enterFrom="opacity-0"
82
+ leave="transition ease-in-out"
83
+ leaveTo="opacity-0"
84
+ >
85
+ <p className="text-sm text-gray-600">Saved.</p>
86
+ </Transition>
87
+ </div>
88
+ </form>
89
+ </section>
90
+ )
84
91
  }