kaze 0.7.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/kaze/commands/install_command.rb +3 -1
- data/lib/kaze/commands/installs_hotwire_stack.rb +2 -2
- data/lib/kaze/commands/installs_inertia_stacks.rb +7 -7
- data/lib/kaze/version.rb +1 -1
- data/stubs/default/app/forms/auth/login_form.rb +2 -2
- data/stubs/default/app/forms/auth/new_password_form.rb +2 -2
- data/stubs/default/app/forms/auth/send_password_reset_link_form.rb +2 -4
- data/stubs/default/app/mailers/application_mailer.rb +1 -1
- data/stubs/default/app/mailers/user_mailer.rb +16 -1
- data/stubs/default/app/models/concerns/can_reset_password.rb +1 -1
- data/stubs/default/app/models/concerns/must_verify_email.rb +15 -0
- data/stubs/default/app/models/session_guard.rb +157 -0
- data/stubs/default/app/models/user.rb +1 -0
- data/stubs/default/app/views/user_mailer/reset_password.html.erb +2 -2
- data/stubs/default/app/views/user_mailer/verify_email.html.erb +33 -0
- data/stubs/default/config/routes.rb +4 -0
- data/stubs/default/db/migrate/20240101000000_create_users.rb +2 -0
- data/stubs/default/test/factories/users.rb +5 -0
- data/stubs/default/test/integration/auth/authentication_test.rb +4 -6
- data/stubs/default/test/integration/auth/email_verification_test.rb +40 -0
- data/stubs/default/test/integration/auth/password_reset_test.rb +3 -3
- data/stubs/default/test/integration/password_update_test.rb +2 -2
- data/stubs/default/test/integration/profile_test.rb +4 -4
- data/stubs/default/test/test_helper.rb +1 -1
- data/stubs/hotwire/app/components/application_logo_component.rb +2 -5
- data/stubs/hotwire/app/components/modal_component.rb +5 -5
- data/stubs/hotwire/app/controllers/auth/authenticated_session_controller.rb +3 -2
- data/stubs/hotwire/app/controllers/auth/email_verification_notification_controller.rb +21 -0
- data/stubs/hotwire/app/controllers/auth/new_password_controller.rb +2 -2
- data/stubs/hotwire/app/controllers/auth/password_reset_link_controller.rb +1 -1
- data/stubs/hotwire/app/controllers/auth/registered_user_controller.rb +6 -2
- data/stubs/hotwire/app/controllers/auth/verified_email_controller.rb +23 -0
- data/stubs/hotwire/app/controllers/concerns/authenticate.rb +10 -0
- data/stubs/hotwire/app/controllers/concerns/set_current_auth.rb +1 -1
- data/stubs/hotwire/app/controllers/concerns/validate_signature.rb +17 -0
- data/stubs/hotwire/app/controllers/password_controller.rb +1 -1
- data/stubs/hotwire/app/controllers/profile_controller.rb +2 -2
- data/stubs/hotwire/app/views/auth/verify_email.html.erb +23 -0
- data/stubs/hotwire/app/views/layouts/_navigation.html.erb +1 -1
- data/stubs/hotwire/app/views/layouts/guest.html.erb +1 -1
- data/stubs/hotwire/app/views/profile/partials/_delete_user_form.html.erb +1 -1
- data/stubs/inertia-common/app/controllers/auth/authenticated_session_controller.rb +3 -3
- data/stubs/inertia-common/app/controllers/auth/email_verification_notification_controller.rb +21 -0
- data/stubs/inertia-common/app/controllers/auth/new_password_controller.rb +2 -3
- data/stubs/inertia-common/app/controllers/auth/password_reset_link_controller.rb +3 -3
- data/stubs/inertia-common/app/controllers/auth/registered_user_controller.rb +6 -2
- data/stubs/inertia-common/app/controllers/auth/verified_email_controller.rb +23 -0
- data/stubs/inertia-common/app/controllers/concerns/authenticate.rb +10 -0
- data/stubs/inertia-common/app/controllers/concerns/set_current_auth.rb +1 -1
- data/stubs/inertia-common/app/controllers/concerns/validate_signature.rb +17 -0
- data/stubs/inertia-common/app/controllers/password_controller.rb +1 -1
- data/stubs/inertia-common/app/controllers/profile_controller.rb +2 -2
- data/stubs/inertia-common/test/integration/password_update_test.rb +2 -2
- data/stubs/inertia-common/test/integration/profile_test.rb +4 -4
- data/stubs/inertia-react-ts/app/javascript/Components/ApplicationLogo.tsx +2 -9
- data/stubs/inertia-react-ts/app/javascript/Components/Checkbox.tsx +1 -4
- data/stubs/inertia-react-ts/app/javascript/Components/DangerButton.tsx +3 -5
- data/stubs/inertia-react-ts/app/javascript/Components/Dropdown.tsx +4 -25
- data/stubs/inertia-react-ts/app/javascript/Components/InputError.tsx +1 -4
- data/stubs/inertia-react-ts/app/javascript/Components/InputLabel.tsx +1 -4
- data/stubs/inertia-react-ts/app/javascript/Components/NavLink.tsx +3 -5
- data/stubs/inertia-react-ts/app/javascript/Components/PrimaryButton.tsx +3 -5
- data/stubs/inertia-react-ts/app/javascript/Components/SecondaryButton.tsx +3 -5
- data/stubs/inertia-react-ts/app/javascript/Components/TextInput.tsx +1 -7
- data/stubs/inertia-react-ts/app/javascript/Layouts/AuthenticatedLayout.tsx +15 -53
- data/stubs/inertia-react-ts/app/javascript/Layouts/GuestLayout.tsx +1 -1
- data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ForgotPassword.tsx +3 -6
- data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Login.tsx +9 -23
- data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Register.tsx +1 -4
- data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ResetPassword.tsx +1 -4
- data/stubs/inertia-react-ts/app/javascript/Pages/Auth/VerifyEmail.tsx +47 -0
- data/stubs/inertia-react-ts/app/javascript/Pages/Dashboard.tsx +2 -8
- data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Edit.tsx +1 -5
- data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.tsx +7 -19
- data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.tsx +7 -15
- data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.tsx +7 -16
- data/stubs/inertia-react-ts/app/javascript/Pages/Welcome.tsx +1 -2
- data/stubs/inertia-react-ts/app/javascript/entrypoints/application.tsx +1 -5
- data/stubs/inertia-react-ts/config/tailwind.config.js +1 -6
- data/stubs/inertia-vue-ts/app/javascript/Components/ApplicationLogo.vue +4 -9
- data/stubs/inertia-vue-ts/app/javascript/Components/Dropdown.vue +1 -4
- data/stubs/inertia-vue-ts/app/javascript/Components/Modal.vue +3 -13
- data/stubs/inertia-vue-ts/app/javascript/Layouts/AuthenticatedLayout.vue +10 -45
- data/stubs/inertia-vue-ts/app/javascript/Layouts/GuestLayout.vue +3 -7
- data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ForgotPassword.vue +4 -11
- data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Login.vue +2 -10
- data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Register.vue +1 -5
- data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ResetPassword.vue +1 -4
- data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/VerifyEmail.vue +50 -0
- data/stubs/inertia-vue-ts/app/javascript/Pages/Dashboard.vue +3 -11
- data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Edit.vue +2 -10
- data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.vue +5 -9
- data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.vue +2 -9
- data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.vue +3 -13
- data/stubs/inertia-vue-ts/app/javascript/Pages/Welcome.vue +2 -5
- data/stubs/inertia-vue-ts/config/tailwind.config.js +1 -6
- metadata +15 -4
- data/MIT-LICENSE +0 -20
- data/stubs/default/app/models/auth.rb +0 -57
@@ -7,10 +7,7 @@ export default function InputLabel({
|
|
7
7
|
...props
|
8
8
|
}: LabelHTMLAttributes<HTMLLabelElement> & { value?: string }) {
|
9
9
|
return (
|
10
|
-
<label
|
11
|
-
{...props}
|
12
|
-
className={`block font-medium text-sm text-gray-700 dark:text-gray-300 ${className}`}
|
13
|
-
>
|
10
|
+
<label {...props} className={`block font-medium text-sm text-gray-700 dark:text-gray-300 ${className}`}>
|
14
11
|
{value ? value : children}
|
15
12
|
</label>
|
16
13
|
)
|
@@ -9,13 +9,11 @@ export default function NavLink({
|
|
9
9
|
return (
|
10
10
|
<Link
|
11
11
|
{...props}
|
12
|
-
className={
|
13
|
-
|
14
|
-
active
|
12
|
+
className={`inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium leading-5 transition duration-150 ease-in-out focus:outline-none ${
|
13
|
+
active
|
15
14
|
? 'border-indigo-400 dark:border-indigo-600 text-gray-900 dark:text-gray-100 focus:border-indigo-700 '
|
16
15
|
: 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-700 focus:text-gray-700 dark:focus:text-gray-300 focus:border-gray-300 dark:focus:border-gray-700 '
|
17
|
-
|
18
|
-
}
|
16
|
+
} ${className}`}
|
19
17
|
>
|
20
18
|
{children}
|
21
19
|
</Link>
|
@@ -9,11 +9,9 @@ export default function PrimaryButton({
|
|
9
9
|
return (
|
10
10
|
<button
|
11
11
|
{...props}
|
12
|
-
className={
|
13
|
-
|
14
|
-
|
15
|
-
} ${className}`
|
16
|
-
}
|
12
|
+
className={`inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150 ${
|
13
|
+
disabled && 'opacity-25'
|
14
|
+
} ${className}`}
|
17
15
|
disabled={disabled}
|
18
16
|
>
|
19
17
|
{children}
|
@@ -11,11 +11,9 @@ export default function SecondaryButton({
|
|
11
11
|
<button
|
12
12
|
{...props}
|
13
13
|
type={type}
|
14
|
-
className={
|
15
|
-
|
16
|
-
|
17
|
-
} ${className}`
|
18
|
-
}
|
14
|
+
className={`inline-flex items-center px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-500 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150 ${
|
15
|
+
disabled && 'opacity-25'
|
16
|
+
} ${className}`}
|
19
17
|
disabled={disabled}
|
20
18
|
>
|
21
19
|
{children}
|
@@ -1,10 +1,4 @@
|
|
1
|
-
import {
|
2
|
-
forwardRef,
|
3
|
-
useEffect,
|
4
|
-
useImperativeHandle,
|
5
|
-
useRef,
|
6
|
-
InputHTMLAttributes,
|
7
|
-
} from 'react'
|
1
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef, InputHTMLAttributes } from 'react'
|
8
2
|
|
9
3
|
export default forwardRef(function TextInput(
|
10
4
|
{
|
@@ -12,8 +12,7 @@ export default function Authenticated({
|
|
12
12
|
header,
|
13
13
|
children,
|
14
14
|
}: PropsWithChildren<{ user: User; header?: ReactNode }>) {
|
15
|
-
const [showingNavigationDropdown, setShowingNavigationDropdown] =
|
16
|
-
useState(false)
|
15
|
+
const [showingNavigationDropdown, setShowingNavigationDropdown] = useState(false)
|
17
16
|
|
18
17
|
const { pathname = '' } = typeof window !== 'undefined' ? window.location : {}
|
19
18
|
|
@@ -25,15 +24,12 @@ export default function Authenticated({
|
|
25
24
|
<div className="flex">
|
26
25
|
<div className="shrink-0 flex items-center">
|
27
26
|
<Link href="/">
|
28
|
-
<ApplicationLogo className="block h-9 w-auto fill-current text-
|
27
|
+
<ApplicationLogo className="block h-9 w-auto fill-current text-red-800" />
|
29
28
|
</Link>
|
30
29
|
</div>
|
31
30
|
|
32
31
|
<div className="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
33
|
-
<NavLink
|
34
|
-
href={dashboard_path()}
|
35
|
-
active={pathname.match(/dashboard/) != null}
|
36
|
-
>
|
32
|
+
<NavLink href={dashboard_path()} active={pathname.match(/dashboard/) != null}>
|
37
33
|
Dashboard
|
38
34
|
</NavLink>
|
39
35
|
</div>
|
@@ -67,14 +63,8 @@ export default function Authenticated({
|
|
67
63
|
</Dropdown.Trigger>
|
68
64
|
|
69
65
|
<Dropdown.Content>
|
70
|
-
<Dropdown.Link href={profile_edit_path()}>
|
71
|
-
|
72
|
-
</Dropdown.Link>
|
73
|
-
<Dropdown.Link
|
74
|
-
href={logout_path()}
|
75
|
-
method="post"
|
76
|
-
as="button"
|
77
|
-
>
|
66
|
+
<Dropdown.Link href={profile_edit_path()}>Profile</Dropdown.Link>
|
67
|
+
<Dropdown.Link href={logout_path()} method="post" as="button">
|
78
68
|
Log Out
|
79
69
|
</Dropdown.Link>
|
80
70
|
</Dropdown.Content>
|
@@ -84,32 +74,19 @@ export default function Authenticated({
|
|
84
74
|
|
85
75
|
<div className="-me-2 flex items-center sm:hidden">
|
86
76
|
<button
|
87
|
-
onClick={() =>
|
88
|
-
setShowingNavigationDropdown(
|
89
|
-
(previousState) => !previousState,
|
90
|
-
)
|
91
|
-
}
|
77
|
+
onClick={() => setShowingNavigationDropdown((previousState) => !previousState)}
|
92
78
|
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out"
|
93
79
|
>
|
94
|
-
<svg
|
95
|
-
className="h-6 w-6"
|
96
|
-
stroke="currentColor"
|
97
|
-
fill="none"
|
98
|
-
viewBox="0 0 24 24"
|
99
|
-
>
|
80
|
+
<svg className="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
100
81
|
<path
|
101
|
-
className={
|
102
|
-
!showingNavigationDropdown ? 'inline-flex' : 'hidden'
|
103
|
-
}
|
82
|
+
className={!showingNavigationDropdown ? 'inline-flex' : 'hidden'}
|
104
83
|
strokeLinecap="round"
|
105
84
|
strokeLinejoin="round"
|
106
85
|
strokeWidth="2"
|
107
86
|
d="M4 6h16M4 12h16M4 18h16"
|
108
87
|
/>
|
109
88
|
<path
|
110
|
-
className={
|
111
|
-
showingNavigationDropdown ? 'inline-flex' : 'hidden'
|
112
|
-
}
|
89
|
+
className={showingNavigationDropdown ? 'inline-flex' : 'hidden'}
|
113
90
|
strokeLinecap="round"
|
114
91
|
strokeLinejoin="round"
|
115
92
|
strokeWidth="2"
|
@@ -121,34 +98,21 @@ export default function Authenticated({
|
|
121
98
|
</div>
|
122
99
|
</div>
|
123
100
|
|
124
|
-
<div
|
125
|
-
className={
|
126
|
-
(showingNavigationDropdown ? 'block' : 'hidden') + ' sm:hidden'
|
127
|
-
}
|
128
|
-
>
|
101
|
+
<div className={(showingNavigationDropdown ? 'block' : 'hidden') + ' sm:hidden'}>
|
129
102
|
<div className="pt-2 pb-3 space-y-1">
|
130
|
-
<ResponsiveNavLink
|
131
|
-
href={dashboard_path()}
|
132
|
-
active={pathname.match(/dashboard/) != null}
|
133
|
-
>
|
103
|
+
<ResponsiveNavLink href={dashboard_path()} active={pathname.match(/dashboard/) != null}>
|
134
104
|
Dashboard
|
135
105
|
</ResponsiveNavLink>
|
136
106
|
</div>
|
137
107
|
|
138
108
|
<div className="pt-4 pb-1 border-t border-gray-200">
|
139
109
|
<div className="px-4">
|
140
|
-
<div className="font-medium text-base text-gray-800">
|
141
|
-
|
142
|
-
</div>
|
143
|
-
<div className="font-medium text-sm text-gray-500">
|
144
|
-
{user.email}
|
145
|
-
</div>
|
110
|
+
<div className="font-medium text-base text-gray-800">{user.name}</div>
|
111
|
+
<div className="font-medium text-sm text-gray-500">{user.email}</div>
|
146
112
|
</div>
|
147
113
|
|
148
114
|
<div className="mt-3 space-y-1">
|
149
|
-
<ResponsiveNavLink href={profile_edit_path()}>
|
150
|
-
Profile
|
151
|
-
</ResponsiveNavLink>
|
115
|
+
<ResponsiveNavLink href={profile_edit_path()}>Profile</ResponsiveNavLink>
|
152
116
|
<ResponsiveNavLink method="post" href={logout_path()} as="button">
|
153
117
|
Log Out
|
154
118
|
</ResponsiveNavLink>
|
@@ -159,9 +123,7 @@ export default function Authenticated({
|
|
159
123
|
|
160
124
|
{header && (
|
161
125
|
<header className="bg-white shadow">
|
162
|
-
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
163
|
-
{header}
|
164
|
-
</div>
|
126
|
+
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">{header}</div>
|
165
127
|
</header>
|
166
128
|
)}
|
167
129
|
|
@@ -7,7 +7,7 @@ export default function Guest({ children }: PropsWithChildren) {
|
|
7
7
|
<div className="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100">
|
8
8
|
<div>
|
9
9
|
<Link href="/">
|
10
|
-
<ApplicationLogo className="w-20 h-20 fill-current text-
|
10
|
+
<ApplicationLogo className="w-20 h-20 fill-current text-red-500" />
|
11
11
|
</Link>
|
12
12
|
</div>
|
13
13
|
|
@@ -22,14 +22,11 @@ export default function ForgotPassword({ status }: { status?: string }) {
|
|
22
22
|
<Head title="Forgot Password" />
|
23
23
|
|
24
24
|
<div className="mb-4 text-sm text-gray-600">
|
25
|
-
Forgot your password? No problem. Just let us know your email address
|
26
|
-
|
27
|
-
choose a new one.
|
25
|
+
Forgot your password? No problem. Just let us know your email address and we will email you a password reset
|
26
|
+
link that will allow you to choose a new one.
|
28
27
|
</div>
|
29
28
|
|
30
|
-
{status &&
|
31
|
-
<div className="mb-4 font-medium text-sm text-green-600">{status}</div>
|
32
|
-
)}
|
29
|
+
{status && <div className="mb-4 font-medium text-sm text-green-600">{status}</div>}
|
33
30
|
|
34
31
|
<form onSubmit={submit}>
|
35
32
|
<TextInput
|
@@ -8,13 +8,7 @@ import TextInput from '@/Components/TextInput'
|
|
8
8
|
import { Head, Link, useForm } from '@inertiajs/react'
|
9
9
|
import { login_path, password_request_path } from '@/routes'
|
10
10
|
|
11
|
-
export default function Login({
|
12
|
-
status,
|
13
|
-
canResetPassword,
|
14
|
-
}: {
|
15
|
-
status?: string
|
16
|
-
canResetPassword: boolean
|
17
|
-
}) {
|
11
|
+
export default function Login({ status }: { status?: string }) {
|
18
12
|
const { data, setData, post, processing, errors, reset } = useForm({
|
19
13
|
email: '',
|
20
14
|
password: '',
|
@@ -37,9 +31,7 @@ export default function Login({
|
|
37
31
|
<GuestLayout>
|
38
32
|
<Head title="Log in" />
|
39
33
|
|
40
|
-
{status &&
|
41
|
-
<div className="mb-4 font-medium text-sm text-green-600">{status}</div>
|
42
|
-
)}
|
34
|
+
{status && <div className="mb-4 font-medium text-sm text-green-600">{status}</div>}
|
43
35
|
|
44
36
|
<form onSubmit={submit}>
|
45
37
|
<div>
|
@@ -77,24 +69,18 @@ export default function Login({
|
|
77
69
|
|
78
70
|
<div className="block mt-4">
|
79
71
|
<label className="flex items-center">
|
80
|
-
<Checkbox
|
81
|
-
name="remember"
|
82
|
-
checked={data.remember}
|
83
|
-
onChange={(e) => setData('remember', e.target.checked)}
|
84
|
-
/>
|
72
|
+
<Checkbox name="remember" checked={data.remember} onChange={(e) => setData('remember', e.target.checked)} />
|
85
73
|
<span className="ms-2 text-sm text-gray-600">Remember me</span>
|
86
74
|
</label>
|
87
75
|
</div>
|
88
76
|
|
89
77
|
<div className="flex items-center justify-end mt-4">
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
</Link>
|
97
|
-
)}
|
78
|
+
<Link
|
79
|
+
href={password_request_path()}
|
80
|
+
className="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
81
|
+
>
|
82
|
+
Forgot your password?
|
83
|
+
</Link>
|
98
84
|
|
99
85
|
<PrimaryButton className="ms-4" disabled={processing}>
|
100
86
|
Log in
|
@@ -84,10 +84,7 @@ export default function Register() {
|
|
84
84
|
</div>
|
85
85
|
|
86
86
|
<div className="mt-4">
|
87
|
-
<InputLabel
|
88
|
-
htmlFor="password_confirmation"
|
89
|
-
value="Confirm Password"
|
90
|
-
/>
|
87
|
+
<InputLabel htmlFor="password_confirmation" value="Confirm Password" />
|
91
88
|
|
92
89
|
<TextInput
|
93
90
|
id="password_confirmation"
|
@@ -49,10 +49,7 @@ export default function ResetPassword({ token }: { token: string }) {
|
|
49
49
|
</div>
|
50
50
|
|
51
51
|
<div className="mt-4">
|
52
|
-
<InputLabel
|
53
|
-
htmlFor="password_confirmation"
|
54
|
-
value="Confirm Password"
|
55
|
-
/>
|
52
|
+
<InputLabel htmlFor="password_confirmation" value="Confirm Password" />
|
56
53
|
|
57
54
|
<TextInput
|
58
55
|
type="password"
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import GuestLayout from '@/Layouts/GuestLayout'
|
2
|
+
import PrimaryButton from '@/Components/PrimaryButton'
|
3
|
+
import { Head, Link, useForm } from '@inertiajs/react'
|
4
|
+
import { FormEventHandler } from 'react'
|
5
|
+
import { logout_path, verification_send_path } from '@/routes'
|
6
|
+
|
7
|
+
export default function VerifyEmail({ status }: { status?: string }) {
|
8
|
+
const { post, processing } = useForm({})
|
9
|
+
|
10
|
+
const submit: FormEventHandler = (e) => {
|
11
|
+
e.preventDefault()
|
12
|
+
|
13
|
+
post(verification_send_path())
|
14
|
+
}
|
15
|
+
|
16
|
+
return (
|
17
|
+
<GuestLayout>
|
18
|
+
<Head title="Email Verification" />
|
19
|
+
|
20
|
+
<div className="mb-4 text-sm text-gray-600 dark:text-gray-400">
|
21
|
+
Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we
|
22
|
+
just emailed to you? If you didn't receive the email, we will gladly send you another.
|
23
|
+
</div>
|
24
|
+
|
25
|
+
{status === 'verification-link-sent' && (
|
26
|
+
<div className="mb-4 font-medium text-sm text-green-600 dark:text-green-400">
|
27
|
+
A new verification link has been sent to the email address you provided during registration.
|
28
|
+
</div>
|
29
|
+
)}
|
30
|
+
|
31
|
+
<form onSubmit={submit}>
|
32
|
+
<div className="mt-4 flex items-center justify-between">
|
33
|
+
<PrimaryButton disabled={processing}>Resend Verification Email</PrimaryButton>
|
34
|
+
|
35
|
+
<Link
|
36
|
+
href={logout_path()}
|
37
|
+
method="post"
|
38
|
+
as="button"
|
39
|
+
className="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800"
|
40
|
+
>
|
41
|
+
Log Out
|
42
|
+
</Link>
|
43
|
+
</div>
|
44
|
+
</form>
|
45
|
+
</GuestLayout>
|
46
|
+
)
|
47
|
+
}
|
@@ -6,20 +6,14 @@ export default function Dashboard({ auth }: PageProps) {
|
|
6
6
|
return (
|
7
7
|
<AuthenticatedLayout
|
8
8
|
user={auth.user}
|
9
|
-
header={
|
10
|
-
<h2 className="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
|
11
|
-
Dashboard
|
12
|
-
</h2>
|
13
|
-
}
|
9
|
+
header={<h2 className="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">Dashboard</h2>}
|
14
10
|
>
|
15
11
|
<Head title="Dashboard" />
|
16
12
|
|
17
13
|
<div className="py-12">
|
18
14
|
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
19
15
|
<div className="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
|
20
|
-
<div className="p-6 text-gray-900 dark:text-gray-100">
|
21
|
-
You're logged in!
|
22
|
-
</div>
|
16
|
+
<div className="p-6 text-gray-900 dark:text-gray-100">You're logged in!</div>
|
23
17
|
</div>
|
24
18
|
</div>
|
25
19
|
</div>
|
@@ -9,11 +9,7 @@ export default function Edit({ auth }: PageProps) {
|
|
9
9
|
return (
|
10
10
|
<AuthenticatedLayout
|
11
11
|
user={auth.user}
|
12
|
-
header={
|
13
|
-
<h2 className="font-semibold text-xl text-gray-800 leading-tight">
|
14
|
-
Profile
|
15
|
-
</h2>
|
16
|
-
}
|
12
|
+
header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Profile</h2>}
|
17
13
|
>
|
18
14
|
<Head title="Profile" />
|
19
15
|
|
@@ -8,11 +8,7 @@ import TextInput from '@/Components/TextInput'
|
|
8
8
|
import { useForm } from '@inertiajs/react'
|
9
9
|
import { profile_destroy_path } from '@/routes'
|
10
10
|
|
11
|
-
export default function DeleteUserForm({
|
12
|
-
className = '',
|
13
|
-
}: {
|
14
|
-
className?: string
|
15
|
-
}) {
|
11
|
+
export default function DeleteUserForm({ className = '' }: { className?: string }) {
|
16
12
|
const [confirmingUserDeletion, setConfirmingUserDeletion] = useState(false)
|
17
13
|
const passwordInput = useRef<HTMLInputElement>(null)
|
18
14
|
|
@@ -54,9 +50,8 @@ export default function DeleteUserForm({
|
|
54
50
|
<h2 className="text-lg font-medium text-gray-900">Delete Account</h2>
|
55
51
|
|
56
52
|
<p className="mt-1 text-sm text-gray-600">
|
57
|
-
Once your account is deleted, all of its resources and data will be
|
58
|
-
|
59
|
-
data or information that you wish to retain.
|
53
|
+
Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your
|
54
|
+
account, please download any data or information that you wish to retain.
|
60
55
|
</p>
|
61
56
|
</header>
|
62
57
|
|
@@ -64,22 +59,15 @@ export default function DeleteUserForm({
|
|
64
59
|
|
65
60
|
<Modal show={confirmingUserDeletion} onClose={closeModal}>
|
66
61
|
<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>
|
62
|
+
<h2 className="text-lg font-medium text-gray-900">Are you sure you want to delete your account?</h2>
|
70
63
|
|
71
64
|
<p className="mt-1 text-sm text-gray-600">
|
72
|
-
Once your account is deleted, all of its resources and data will be
|
73
|
-
|
74
|
-
like to permanently delete your account.
|
65
|
+
Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your
|
66
|
+
password to confirm you would like to permanently delete your account.
|
75
67
|
</p>
|
76
68
|
|
77
69
|
<div className="mt-6">
|
78
|
-
<InputLabel
|
79
|
-
htmlFor="password"
|
80
|
-
value="Password"
|
81
|
-
className="sr-only"
|
82
|
-
/>
|
70
|
+
<InputLabel htmlFor="password" value="Password" className="sr-only" />
|
83
71
|
|
84
72
|
<TextInput
|
85
73
|
id="password"
|
@@ -7,20 +7,15 @@ import { useForm } from '@inertiajs/react'
|
|
7
7
|
import { Transition } from '@headlessui/react'
|
8
8
|
import { password_update_path } from '@/routes'
|
9
9
|
|
10
|
-
export default function UpdatePasswordForm({
|
11
|
-
className = '',
|
12
|
-
}: {
|
13
|
-
className?: string
|
14
|
-
}) {
|
10
|
+
export default function UpdatePasswordForm({ className = '' }: { className?: string }) {
|
15
11
|
const passwordInput = useRef<HTMLInputElement>(null)
|
16
12
|
const currentPasswordInput = useRef<HTMLInputElement>(null)
|
17
13
|
|
18
|
-
const { data, setData, errors, put, reset, processing, recentlySuccessful } =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
})
|
14
|
+
const { data, setData, errors, put, reset, processing, recentlySuccessful } = useForm({
|
15
|
+
current_password: '',
|
16
|
+
password: '',
|
17
|
+
password_confirmation: '',
|
18
|
+
})
|
24
19
|
|
25
20
|
const updatePassword: FormEventHandler = (e) => {
|
26
21
|
e.preventDefault()
|
@@ -86,10 +81,7 @@ export default function UpdatePasswordForm({
|
|
86
81
|
</div>
|
87
82
|
|
88
83
|
<div>
|
89
|
-
<InputLabel
|
90
|
-
htmlFor="password_confirmation"
|
91
|
-
value="Confirm Password"
|
92
|
-
/>
|
84
|
+
<InputLabel htmlFor="password_confirmation" value="Confirm Password" />
|
93
85
|
|
94
86
|
<TextInput
|
95
87
|
id="password_confirmation"
|
data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.tsx
CHANGED
@@ -8,18 +8,13 @@ import { FormEventHandler } from 'react'
|
|
8
8
|
import { PageProps } from '@/types'
|
9
9
|
import { profile_update_path } from '@/routes'
|
10
10
|
|
11
|
-
export default function UpdateProfileInformation({
|
12
|
-
className = '',
|
13
|
-
}: {
|
14
|
-
className?: string
|
15
|
-
}) {
|
11
|
+
export default function UpdateProfileInformation({ className = '' }: { className?: string }) {
|
16
12
|
const user = usePage<PageProps>().props.auth.user
|
17
13
|
|
18
|
-
const { data, setData, patch, errors, processing, recentlySuccessful } =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
})
|
14
|
+
const { data, setData, patch, errors, processing, recentlySuccessful } = useForm({
|
15
|
+
name: user.name,
|
16
|
+
email: user.email,
|
17
|
+
})
|
23
18
|
|
24
19
|
const submit: FormEventHandler = (e) => {
|
25
20
|
e.preventDefault()
|
@@ -30,13 +25,9 @@ export default function UpdateProfileInformation({
|
|
30
25
|
return (
|
31
26
|
<section className={className}>
|
32
27
|
<header>
|
33
|
-
<h2 className="text-lg font-medium text-gray-900">
|
34
|
-
Profile Information
|
35
|
-
</h2>
|
28
|
+
<h2 className="text-lg font-medium text-gray-900">Profile Information</h2>
|
36
29
|
|
37
|
-
<p className="mt-1 text-sm text-gray-600">
|
38
|
-
Update your account's profile information and email address.
|
39
|
-
</p>
|
30
|
+
<p className="mt-1 text-sm text-gray-600">Update your account's profile information and email address.</p>
|
40
31
|
</header>
|
41
32
|
|
42
33
|
<form onSubmit={submit} className="mt-6 space-y-6">
|
@@ -64,8 +64,7 @@ export default function Welcome({
|
|
64
64
|
target="_blank"
|
65
65
|
style={{
|
66
66
|
transition: 'background 0.25s cubic-bezier(0.33, 1, 0.68, 1)',
|
67
|
-
filter:
|
68
|
-
'drop-shadow(0 20px 13px rgb(0 0 0 / 0.03)) drop-shadow(0 8px 5px rgb(0 0 0 / 0.08))',
|
67
|
+
filter: 'drop-shadow(0 20px 13px rgb(0 0 0 / 0.03)) drop-shadow(0 8px 5px rgb(0 0 0 / 0.08))',
|
69
68
|
}}
|
70
69
|
>
|
71
70
|
<img
|
@@ -25,11 +25,7 @@ const appName = import.meta.env.VITE_APP_NAME || 'Rails'
|
|
25
25
|
|
26
26
|
createInertiaApp({
|
27
27
|
title: (title) => `${title} - ${appName}`,
|
28
|
-
resolve: (name) =>
|
29
|
-
resolvePageComponent(
|
30
|
-
`../Pages/${name}.tsx`,
|
31
|
-
import.meta.glob('../Pages/**/*.tsx'),
|
32
|
-
),
|
28
|
+
resolve: (name) => resolvePageComponent(`../Pages/${name}.tsx`, import.meta.glob('../Pages/**/*.tsx')),
|
33
29
|
setup({ el, App, props }) {
|
34
30
|
const root = createRoot(el)
|
35
31
|
|
@@ -3,12 +3,7 @@ import forms from '@tailwindcss/forms'
|
|
3
3
|
|
4
4
|
/** @type {import('tailwindcss').Config} */
|
5
5
|
export default {
|
6
|
-
content: [
|
7
|
-
'./public/*.html',
|
8
|
-
'./app/helpers/**/*.rb',
|
9
|
-
'./app/views/**/*',
|
10
|
-
'./app/javascript/**/*.tsx',
|
11
|
-
],
|
6
|
+
content: ['./public/*.html', './app/helpers/**/*.rb', './app/views/**/*', './app/javascript/**/*.tsx'],
|
12
7
|
|
13
8
|
theme: {
|
14
9
|
extend: {
|
@@ -1,12 +1,7 @@
|
|
1
1
|
<template>
|
2
|
-
<svg viewBox="0
|
3
|
-
<
|
4
|
-
|
5
|
-
|
6
|
-
fill="#c00"
|
7
|
-
fill-rule="nonzero"
|
8
|
-
d="M.985 19.636s.422-4.163 3.375-9.087c2.954-4.924 7.99-8.65 12.083-9.017 8.144-.816 15.46 6.485 15.46 6.485s-.24.168-.494.38C23.42 2.49 18.54 5.274 17.005 6.02c-7.033 3.925-4.91 13.616-4.91 13.616H.987zM24.137 2.32c-.45-.182-.9-.35-1.364-.505l.056-.93c.885.254 1.237.423 1.363.493l-.056.943zM22.8 5.304c.45.028.915.084 1.393.183l-.056.872c-.464-.1-.928-.155-1.392-.17l.056-.885zM17.597.913c-.407 0-.815.015-1.223.058l-.268-.83c.465-.056.915-.084 1.35-.084l.282.858h-.14zm.676 5.178c.35-.154.76-.31 1.237-.45l.31.93c-.41.125-.817.294-1.225.49l-.323-.97zm-6.386-3.7c-.366.184-.718.395-1.083.62l-.647-.985c.38-.225.745-.42 1.097-.604l.633.97zm2.883 6.33c.252-.323.548-.646.87-.942l.634.957c-.31.323-.59.647-.83 1L14.77 8.72zm-2.04 4.53c.112-.506.24-1.027.422-1.547l1.012.802c-.14.548-.24 1.097-.295 1.645l-1.14-.9zM6.57 6.57c-.34.35-.662.73-.958 1.11L4.53 6.752c.323-.352.674-.704 1.04-1.055l1 .872zm-4.25 6.286c-.224.52-.52 1.21-.702 1.688L0 13.954c.14-.38.436-1.084.703-1.69l1.618.592zm10.2 3.967l1.518.548c.084.663.21 1.28.337 1.83l-1.688-.605c-.07-.422-.14-1.027-.168-1.772z"
|
9
|
-
/>
|
10
|
-
</g>
|
2
|
+
<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
|
3
|
+
<path
|
4
|
+
d="m 237.03985,281.43515 c -1.54085,-2.49315 -1.43016,-32.97159 0.24592,-67.72985 3.02813,-62.79557 2.98467,-63.24086 -6.84044,-70.12264 -5.43834,-3.80913 -16.32202,-6.92574 -24.18594,-6.92574 -22.00734,0 -30.84257,-6.63121 -30.84257,-23.14872 0,-18.460367 5.31742,-22.209117 35.7331,-25.191397 27.97004,-2.74248 30.5663,-4.04226 26.94175,-13.48771 -2.14986,-5.6024 -13.90805,-6.59952 -77.8227,-6.59952 -69.400535,0 -75.177944,-0.58548 -73.8551,-7.48424 1.284851,-6.700534 9.490461,-7.708169 78.36353,-9.622595 42.31063,-1.176095 74.04161,-3.44104 70.51333,-5.033217 -11.28272,-5.091508 -103.7232,-12.917843 -134.65799,-11.40068 l -29.878628,1.465415 -3.171696,17.106837 c -1.744436,9.40876 -4.948521,63.009007 -7.120182,119.111597 -2.277699,58.84196 -5.815243,103.87156 -8.360116,106.41647 -2.4264,2.42639 -7.676475,3.15877 -11.666833,1.62754 -5.877786,-2.25554 -6.747202,-6.22009 -4.579445,-20.88223 1.471667,-9.954 3.74014,-63.32438 5.041047,-118.60085 2.647925,-112.511911 3.2489,-117.857541 13.890324,-123.552663 4.513472,-2.415528 45.033525,-3.067128 100.341569,-1.613517 109.0299,2.86548 110.09891,3.263428 110.09891,40.985371 0,30.923222 -7.28516,39.906492 -35.24013,43.454229 -29.06687,3.68892 -37.46391,6.17185 -37.46391,11.07783 0,2.19365 11.40965,3.98851 25.35478,3.98851 37.65833,0 38.79584,2.06051 38.79584,70.27428 0,31.25825 -1.20855,65.65073 -2.68573,76.42778 -2.59506,18.93304 -11.18137,28.79145 -16.94872,19.45971 z M 102.84208,259.48743 c -5.809371,-2.9396 -13.184926,-10.12819 -16.390123,-15.97462 -8.396565,-15.3158 2.912296,-41.49358 19.494463,-45.12587 20.60401,-4.51326 22.42665,-5.69589 22.42665,-14.55198 0,-6.8018 -2.78507,-8.68766 -12.83013,-8.68766 -16.253558,0 -29.936969,-13.44405 -29.936969,-29.41328 0,-14.42513 5.553783,-19.82093 24.591079,-23.89154 9.82484,-2.1008 13.8993,-5.37975 13.8993,-11.1856 0,-6.50902 -3.05408,-8.21363 -14.71608,-8.21363 -16.019022,0 -24.105594,-7.285117 -14.699611,-13.242787 3.241585,-2.05321 12.812471,-3.76252 21.268621,-3.79858 19.92576,-0.0847 30.60952,11.25947 28.76224,30.540617 -1.22046,12.73879 -3.23695,14.76612 -18.47681,18.57607 -30.922304,7.73057 -36.377959,19.24518 -9.11843,19.24518 22.57064,0 29.1179,7.65172 27.56665,32.21701 l -1.34139,21.24186 -20.81946,5.13821 c -11.45071,2.826 -21.79219,6.1109 -22.981063,7.29978 -4.590664,4.59067 3.475793,15.68791 14.430943,19.85304 16.19851,6.15868 88.0503,3.43548 90.32313,-3.42324 1.28741,-3.88501 -5.33813,-5.34589 -24.24513,-5.34589 -19.38669,0 -26.01664,-1.51819 -26.01664,-5.9575 0,-8.34429 9.63998,-11.14934 38.3165,-11.14934 28.67934,0 35.63045,5.45011 33.61018,26.35253 -0.96086,9.94142 -4.50427,15.66293 -12.05276,19.46151 -14.27136,7.1817 -96.89032,7.20826 -111.06516,0.0342 z m 57.07409,-60.66299 c -4.41463,-11.5043 3.01548,-16.23905 21.50632,-13.70463 20.26375,2.77747 30.64103,-1.74032 26.8271,-11.67922 -1.8078,-4.7111 -8.00515,-6.84671 -19.86838,-6.84671 -19.48707,0 -22.72529,-6.68 -6.27087,-12.93598 25.01034,-9.50892 44.62703,0.19588 44.62703,22.07791 0,17.75258 -8.58709,23.84253 -37.57444,26.6478 -21.20481,2.05209 -27.38199,1.30033 -29.24676,-3.55917 z"
|
5
|
+
/>
|
11
6
|
</svg>
|
12
7
|
</template>
|
@@ -66,10 +66,7 @@ const open = ref(false)
|
|
66
66
|
style="display: none"
|
67
67
|
@click="open = false"
|
68
68
|
>
|
69
|
-
<div
|
70
|
-
class="rounded-md ring-1 ring-black ring-opacity-5"
|
71
|
-
:class="contentClasses"
|
72
|
-
>
|
69
|
+
<div class="rounded-md ring-1 ring-black ring-opacity-5" :class="contentClasses">
|
73
70
|
<slot name="content" />
|
74
71
|
</div>
|
75
72
|
</div>
|
@@ -60,11 +60,7 @@ const maxWidthClass = computed(() => {
|
|
60
60
|
<template>
|
61
61
|
<Teleport to="body">
|
62
62
|
<Transition leave-active-class="duration-200">
|
63
|
-
<div
|
64
|
-
v-show="show"
|
65
|
-
class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50"
|
66
|
-
scroll-region
|
67
|
-
>
|
63
|
+
<div v-show="show" class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50" scroll-region>
|
68
64
|
<Transition
|
69
65
|
enter-active-class="ease-out duration-300"
|
70
66
|
enter-from-class="opacity-0"
|
@@ -73,14 +69,8 @@ const maxWidthClass = computed(() => {
|
|
73
69
|
leave-from-class="opacity-100"
|
74
70
|
leave-to-class="opacity-0"
|
75
71
|
>
|
76
|
-
<div
|
77
|
-
|
78
|
-
class="fixed inset-0 transform transition-all"
|
79
|
-
@click="close"
|
80
|
-
>
|
81
|
-
<div
|
82
|
-
class="absolute inset-0 bg-gray-500 dark:bg-gray-900 opacity-75"
|
83
|
-
/>
|
72
|
+
<div v-show="show" class="fixed inset-0 transform transition-all" @click="close">
|
73
|
+
<div class="absolute inset-0 bg-gray-500 dark:bg-gray-900 opacity-75" />
|
84
74
|
</div>
|
85
75
|
</Transition>
|
86
76
|
|