Initial commit device-management
tests / ci (push) Has been cancelled

This commit is contained in:
Wian Drs
2026-08-25 09:42:00 +07:00
commit 1e80be180e
1159 changed files with 149545 additions and 0 deletions
@@ -0,0 +1,32 @@
import { Head } from '@inertiajs/react';
import AppearanceTabs from '@/components/appearance-tabs';
import Heading from '@/components/heading';
import { edit as editAppearance } from '@/routes/appearance';
export default function Appearance() {
return (
<>
<Head title="Appearance settings" />
<h1 className="sr-only">Appearance settings</h1>
<div className="space-y-6">
<Heading
variant="small"
title="Appearance settings"
description="Update the appearance settings for your account"
/>
<AppearanceTabs />
</div>
</>
);
}
Appearance.layout = {
breadcrumbs: [
{
title: 'Appearance settings',
href: editAppearance(),
},
],
};
+138
View File
@@ -0,0 +1,138 @@
import { Form, Head, usePage } from '@inertiajs/react';
import { Link } from '@inertiajs/react';
import ProfileController from '@/actions/App/Http/Controllers/Settings/ProfileController';
import DeleteUser from '@/components/delete-user';
import Heading from '@/components/heading';
import InputError from '@/components/input-error';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { edit } from '@/routes/profile';
import { send } from '@/routes/verification';
import type { Auth } from '@/types';
type PageProps = {
auth: Auth;
};
export default function Profile({
mustVerifyEmail,
status,
}: {
mustVerifyEmail: boolean;
status?: string;
}) {
const { auth } = usePage<PageProps>().props;
return (
<>
<Head title="Profile settings" />
<h1 className="sr-only">Profile settings</h1>
<div className="space-y-6">
<Heading
variant="small"
title="Profile"
description="Update your name and email address"
/>
<Form
{...ProfileController.update.form()}
options={{
preserveScroll: true,
}}
className="space-y-6"
>
{({ processing, errors }) => (
<>
<div className="grid gap-2">
<Label htmlFor="name">Name</Label>
<Input
id="name"
className="mt-1 block w-full"
defaultValue={auth.user.name}
name="name"
required
autoComplete="name"
placeholder="Full name"
/>
<InputError
className="mt-2"
message={errors.name}
/>
</div>
<div className="grid gap-2">
<Label htmlFor="email">Email address</Label>
<Input
id="email"
type="email"
className="mt-1 block w-full"
defaultValue={auth.user.email}
name="email"
required
autoComplete="username"
placeholder="Email address"
/>
<InputError
className="mt-2"
message={errors.email}
/>
</div>
{mustVerifyEmail &&
auth.user.email_verified_at === null && (
<div>
<p className="-mt-4 text-sm text-muted-foreground">
Your email address is unverified.{' '}
<Link
href={send()}
as="button"
className="text-foreground underline decoration-neutral-300 underline-offset-4 transition-colors duration-300 ease-out hover:decoration-current! dark:decoration-neutral-500"
>
Click here to re-send the
verification email.
</Link>
</p>
{status ===
'verification-link-sent' && (
<div className="mt-2 text-sm font-medium text-green-600">
A new verification link has been
sent to your email address.
</div>
)}
</div>
)}
<div className="flex items-center gap-4">
<Button
disabled={processing}
data-test="update-profile-button"
>
Save
</Button>
</div>
</>
)}
</Form>
</div>
<DeleteUser />
</>
);
}
Profile.layout = {
breadcrumbs: [
{
title: 'Profile settings',
href: edit(),
},
],
};
+147
View File
@@ -0,0 +1,147 @@
import { Form, Head } from '@inertiajs/react';
import { useRef } from 'react';
import SecurityController from '@/actions/App/Http/Controllers/Settings/SecurityController';
import Heading from '@/components/heading';
import InputError from '@/components/input-error';
import type { Props as ManagePasskeysProps } from '@/components/manage-passkeys';
import ManagePasskeys from '@/components/manage-passkeys';
import type { Props as ManageTwoFactorProps } from '@/components/manage-two-factor';
import ManageTwoFactor from '@/components/manage-two-factor';
import PasswordInput from '@/components/password-input';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { edit } from '@/routes/security';
type Props = {
passwordRules: string;
} & ManagePasskeysProps &
ManageTwoFactorProps;
export default function Security(props: Props) {
const passwordInput = useRef<HTMLInputElement>(null);
const currentPasswordInput = useRef<HTMLInputElement>(null);
return (
<>
<Head title="Security settings" />
<h1 className="sr-only">Security settings</h1>
<div className="space-y-6">
<Heading
variant="small"
title="Update password"
description="Ensure your account is using a long, random password to stay secure"
/>
<Form
{...SecurityController.update.form()}
options={{
preserveScroll: true,
}}
resetOnError={[
'password',
'password_confirmation',
'current_password',
]}
resetOnSuccess
onError={(errors) => {
if (errors.password) {
passwordInput.current?.focus();
}
if (errors.current_password) {
currentPasswordInput.current?.focus();
}
}}
className="space-y-6"
>
{({ errors, processing }) => (
<>
<div className="grid gap-2">
<Label htmlFor="current_password">
Current password
</Label>
<PasswordInput
id="current_password"
ref={currentPasswordInput}
name="current_password"
className="mt-1 block w-full"
autoComplete="current-password"
placeholder="Current password"
/>
<InputError message={errors.current_password} />
</div>
<div className="grid gap-2">
<Label htmlFor="password">New password</Label>
<PasswordInput
id="password"
ref={passwordInput}
name="password"
className="mt-1 block w-full"
autoComplete="new-password"
placeholder="New password"
passwordrules={props.passwordRules}
/>
<InputError message={errors.password} />
</div>
<div className="grid gap-2">
<Label htmlFor="password_confirmation">
Confirm password
</Label>
<PasswordInput
id="password_confirmation"
name="password_confirmation"
className="mt-1 block w-full"
autoComplete="new-password"
placeholder="Confirm password"
passwordrules={props.passwordRules}
/>
<InputError
message={errors.password_confirmation}
/>
</div>
<div className="flex items-center gap-4">
<Button
disabled={processing}
data-test="update-password-button"
>
Save
</Button>
</div>
</>
)}
</Form>
</div>
<ManageTwoFactor
canManageTwoFactor={props.canManageTwoFactor}
requiresConfirmation={props.requiresConfirmation}
twoFactorEnabled={props.twoFactorEnabled}
/>
<ManagePasskeys
canManagePasskeys={props.canManagePasskeys}
passkeys={props.passkeys}
/>
</>
);
}
Security.layout = {
breadcrumbs: [
{
title: 'Security settings',
href: edit(),
},
],
};