Primer commit

This commit is contained in:
2026-08-03 18:01:15 +02:00
commit 99b9fed37f
121 changed files with 18222 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
<script setup>
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
import DeleteUserForm from './Partials/DeleteUserForm.vue';
import UpdatePasswordForm from './Partials/UpdatePasswordForm.vue';
import UpdateProfileInformationForm from './Partials/UpdateProfileInformationForm.vue';
import { Head } from '@inertiajs/vue3';
defineProps({
mustVerifyEmail: {
type: Boolean,
},
status: {
type: String,
},
});
</script>
<template>
<Head title="Profile" />
<AuthenticatedLayout>
<template #header>
<h2 class="h4 mb-0">Profile</h2>
</template>
<div class="container py-4">
<div class="row g-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-body">
<UpdateProfileInformationForm :must-verify-email="mustVerifyEmail" :status="status" />
</div>
</div>
</div>
<div class="col-12">
<div class="card shadow-sm">
<div class="card-body">
<UpdatePasswordForm />
</div>
</div>
</div>
<div class="col-12">
<div class="card shadow-sm">
<div class="card-body">
<DeleteUserForm />
</div>
</div>
</div>
</div>
</div>
</AuthenticatedLayout>
</template>

View File

@@ -0,0 +1,90 @@
<script setup>
import DangerButton from '@/Components/DangerButton.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import Modal from '@/Components/Modal.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import { useForm } from '@inertiajs/vue3';
import { nextTick, ref } from 'vue';
const confirmingUserDeletion = ref(false);
const passwordInput = ref(null);
const form = useForm({
password: '',
});
const confirmUserDeletion = () => {
confirmingUserDeletion.value = true;
nextTick(() => passwordInput.value.focus());
};
const deleteUser = () => {
form.delete(route('profile.destroy'), {
preserveScroll: true,
onSuccess: () => closeModal(),
onError: () => passwordInput.value.focus(),
onFinish: () => form.reset(),
});
};
const closeModal = () => {
confirmingUserDeletion.value = false;
form.clearErrors();
form.reset();
};
</script>
<template>
<section>
<header class="mb-3">
<h2 class="h5 mb-1">Delete Account</h2>
<p class="text-muted mb-0">
Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.
</p>
</header>
<DangerButton @click="confirmUserDeletion">Delete Account</DangerButton>
<Modal :show="confirmingUserDeletion" @close="closeModal">
<div class="p-4">
<h2 class="h5">Are you sure you want to delete your account?</h2>
<p class="text-muted mt-2 mb-3">
Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.
</p>
<div class="mb-3">
<InputLabel for="password" value="Password" class="sr-only" />
<TextInput
id="password"
ref="passwordInput"
v-model="form.password"
type="password"
class="mt-1"
placeholder="Password"
@keyup.enter="deleteUser"
/>
<InputError :message="form.errors.password" />
</div>
<div class="d-flex justify-content-end gap-2">
<SecondaryButton @click="closeModal">Cancel</SecondaryButton>
<DangerButton
:class="{ 'opacity-25': form.processing }"
:disabled="form.processing"
@click="deleteUser"
>
Delete Account
</DangerButton>
</div>
</div>
</Modal>
</section>
</template>

View File

@@ -0,0 +1,97 @@
<script setup>
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import { useForm } from '@inertiajs/vue3';
import { ref } from 'vue';
const passwordInput = ref(null);
const currentPasswordInput = ref(null);
const form = useForm({
current_password: '',
password: '',
password_confirmation: '',
});
const updatePassword = () => {
form.put(route('password.update'), {
preserveScroll: true,
onSuccess: () => form.reset(),
onError: () => {
if (form.errors.password) {
form.reset('password', 'password_confirmation');
passwordInput.value.focus();
}
if (form.errors.current_password) {
form.reset('current_password');
currentPasswordInput.value.focus();
}
},
});
};
</script>
<template>
<section>
<header class="mb-3">
<h2 class="h5 mb-1">Update Password</h2>
<p class="text-muted mb-0">Ensure your account is using a long, random password to stay secure.</p>
</header>
<form @submit.prevent="updatePassword" class="row g-3">
<div class="col-12">
<InputLabel for="current_password" value="Current Password" />
<TextInput
id="current_password"
ref="currentPasswordInput"
v-model="form.current_password"
type="password"
class="mt-1"
autocomplete="current-password"
/>
<InputError :message="form.errors.current_password" />
</div>
<div class="col-12">
<InputLabel for="password" value="New Password" />
<TextInput
id="password"
ref="passwordInput"
v-model="form.password"
type="password"
class="mt-1"
autocomplete="new-password"
/>
<InputError :message="form.errors.password" />
</div>
<div class="col-12">
<InputLabel for="password_confirmation" value="Confirm Password" />
<TextInput
id="password_confirmation"
v-model="form.password_confirmation"
type="password"
class="mt-1"
autocomplete="new-password"
/>
<InputError :message="form.errors.password_confirmation" />
</div>
<div class="col-12 d-flex align-items-center gap-3">
<PrimaryButton :disabled="form.processing">Save</PrimaryButton>
<Transition enter-active-class="transition ease-in-out" enter-from-class="opacity-0" leave-active-class="transition ease-in-out" leave-to-class="opacity-0">
<p v-if="form.recentlySuccessful" class="text-muted mb-0">Saved.</p>
</Transition>
</div>
</form>
</section>
</template>

View File

@@ -0,0 +1,86 @@
<script setup>
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import { Link, useForm, usePage } from '@inertiajs/vue3';
defineProps({
mustVerifyEmail: {
type: Boolean,
},
status: {
type: String,
},
});
const user = usePage().props.auth.user;
const form = useForm({
name: user.name,
email: user.email,
});
</script>
<template>
<section>
<header class="mb-3">
<h2 class="h5 mb-1">Profile Information</h2>
<p class="text-muted mb-0">Update your account's profile information and email address.</p>
</header>
<form @submit.prevent="form.patch(route('profile.update'))" class="row g-3">
<div class="col-12">
<InputLabel for="name" value="Name" />
<TextInput
id="name"
type="text"
class="mt-1"
v-model="form.name"
required
autofocus
autocomplete="name"
/>
<InputError :message="form.errors.name" />
</div>
<div class="col-12">
<InputLabel for="email" value="Email" />
<TextInput
id="email"
type="email"
class="mt-1"
v-model="form.email"
required
autocomplete="username"
/>
<InputError :message="form.errors.email" />
</div>
<div v-if="mustVerifyEmail && user.email_verified_at === null" class="col-12">
<p class="mb-2">
Your email address is unverified.
<Link :href="route('verification.send')" method="post" as="button" class="text-decoration-underline small">
Click here to re-send the verification email.
</Link>
</p>
<div v-show="status === 'verification-link-sent'" class="alert alert-success py-2 mb-0">
A new verification link has been sent to your email address.
</div>
</div>
<div class="col-12 d-flex align-items-center gap-3">
<PrimaryButton :disabled="form.processing">Save</PrimaryButton>
<Transition enter-active-class="transition ease-in-out" enter-from-class="opacity-0" leave-active-class="transition ease-in-out" leave-to-class="opacity-0">
<p v-if="form.recentlySuccessful" class="text-muted mb-0">Saved.</p>
</Transition>
</div>
</form>
</section>
</template>