Initial commit
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
<x-forms.action-section>
|
||||
<x-slot name="title">
|
||||
{{ __('Delete Account') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('Permanently delete your account.') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
<div class="max-w-xl text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ __('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.') }}
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
<x-button class="btn-error text-white" wire:click="confirmUserDeletion" wire:loading.attr="disabled">
|
||||
{{ __('Delete Account') }}
|
||||
</x-button>
|
||||
</div>
|
||||
|
||||
<!-- Delete User Confirmation Modal -->
|
||||
<x-dialog-modal wire:model.live="confirmingUserDeletion">
|
||||
<x-slot name="title">
|
||||
{{ __('Delete Account') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
{{ __('Are you sure you want to delete your account? 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.') }}
|
||||
|
||||
<div class="mt-4" x-data="{}" x-on:confirming-delete-user.window="setTimeout(() => $refs.password.focus(), 250)">
|
||||
<x-input type="password" class="mt-1 block w-3/4"
|
||||
autocomplete="current-password"
|
||||
placeholder="{{ __('Password') }}"
|
||||
x-ref="password"
|
||||
wire:model="password"
|
||||
wire:keydown.enter="deleteUser" />
|
||||
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="footer">
|
||||
<x-button class="btn-outline" wire:click="$toggle('confirmingUserDeletion')" wire:loading.attr="disabled">
|
||||
{{ __('Cancel') }}
|
||||
</x-button>
|
||||
|
||||
<x-button class="ms-3 btn-error text-white" wire:click="deleteUser" wire:loading.attr="disabled">
|
||||
{{ __('Delete Account') }}
|
||||
</x-button>
|
||||
</x-slot>
|
||||
</x-dialog-modal>
|
||||
</x-slot>
|
||||
</x-forms.action-section>
|
||||
@@ -0,0 +1,97 @@
|
||||
<x-forms.action-section>
|
||||
<x-slot name="title">
|
||||
{{ __('Browser Sessions') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('Manage and log out your active sessions on other browsers and devices.') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
<div class="max-w-xl text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ __('If necessary, you may log out of all of your other browser sessions across all of your devices. Some of your recent sessions are listed below; however, this list may not be exhaustive. If you feel your account has been compromised, you should also update your password.') }}
|
||||
</div>
|
||||
|
||||
@if (count($this->sessions) > 0)
|
||||
<div class="mt-5 space-y-6">
|
||||
<!-- Other Browser Sessions -->
|
||||
@foreach ($this->sessions as $session)
|
||||
<div class="flex items-center">
|
||||
<div>
|
||||
@if ($session->agent->isDesktop())
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-8 h-8 text-gray-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25" />
|
||||
</svg>
|
||||
@else
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-8 h-8 text-gray-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 1.5H8.25A2.25 2.25 0 006 3.75v16.5a2.25 2.25 0 002.25 2.25h7.5A2.25 2.25 0 0018 20.25V3.75a2.25 2.25 0 00-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3" />
|
||||
</svg>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="ms-3">
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ $session->agent->platform() ? $session->agent->platform() : __('Unknown') }} - {{ $session->agent->browser() ? $session->agent->browser() : __('Unknown') }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-xs text-gray-500">
|
||||
{{ $session->ip_address }},
|
||||
|
||||
@if ($session->is_current_device)
|
||||
<span class="text-green-500 font-semibold">{{ __('This device') }}</span>
|
||||
@else
|
||||
{{ __('Last active') }} {{ $session->last_active }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex items-center mt-5">
|
||||
<x-button type="submit" wire:click="confirmLogout" wire:loading.attr="disabled">
|
||||
{{ __('Log Out Other Browser Sessions') }}
|
||||
</x-button>
|
||||
|
||||
<x-forms.action-message class="ms-3" on="loggedOut">
|
||||
{{ __('Done.') }}
|
||||
</x-forms.action-message>
|
||||
</div>
|
||||
|
||||
<!-- Log Out Other Devices Confirmation Modal -->
|
||||
<x-dialog-modal wire:model.live="confirmingLogout">
|
||||
<x-slot name="title">
|
||||
{{ __('Log Out Other Browser Sessions') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
{{ __('Please enter your password to confirm you would like to log out of your other browser sessions across all of your devices.') }}
|
||||
|
||||
<div class="mt-4" x-data="{}" x-on:confirming-logout-other-browser-sessions.window="setTimeout(() => $refs.password.focus(), 250)">
|
||||
<x-input type="password" class="mt-1 block w-3/4"
|
||||
autocomplete="current-password"
|
||||
placeholder="{{ __('Password') }}"
|
||||
x-ref="password"
|
||||
wire:model="password"
|
||||
wire:keydown.enter="logoutOtherBrowserSessions" />
|
||||
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="footer">
|
||||
<x-button class="btn-outline" wire:click="$toggle('confirmingLogout')" wire:loading.attr="disabled">
|
||||
{{ __('Cancel') }}
|
||||
</x-button>
|
||||
|
||||
<x-button type="submit" class="ms-3"
|
||||
wire:click="logoutOtherBrowserSessions"
|
||||
wire:loading.attr="disabled">
|
||||
{{ __('Log Out Other Browser Sessions') }}
|
||||
</x-button>
|
||||
</x-slot>
|
||||
</x-dialog-modal>
|
||||
</x-slot>
|
||||
</x-forms.action-section>
|
||||
@@ -0,0 +1,40 @@
|
||||
<x-app-layout>
|
||||
|
||||
<div>
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
@if (Laravel\Fortify\Features::canUpdateProfileInformation())
|
||||
@livewire('profile.update-profile-information-form')
|
||||
|
||||
<x-section-border />
|
||||
@endif
|
||||
|
||||
@if (Laravel\Fortify\Features::enabled(Laravel\Fortify\Features::updatePasswords()))
|
||||
<div class="mt-10 sm:mt-0">
|
||||
@livewire('profile.update-password-form')
|
||||
</div>
|
||||
|
||||
<x-section-border />
|
||||
@endif
|
||||
|
||||
@if (Laravel\Fortify\Features::canManageTwoFactorAuthentication())
|
||||
<div class="mt-10 sm:mt-0">
|
||||
@livewire('profile.two-factor-authentication-form')
|
||||
</div>
|
||||
|
||||
<x-section-border />
|
||||
@endif
|
||||
|
||||
<div class="mt-10 sm:mt-0">
|
||||
@livewire('profile.logout-other-browser-sessions-form')
|
||||
</div>
|
||||
|
||||
@if (Laravel\Jetstream\Jetstream::hasAccountDeletionFeatures())
|
||||
<x-section-border />
|
||||
|
||||
<div class="mt-10 sm:mt-0">
|
||||
@livewire('profile.delete-user-form')
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@@ -0,0 +1,123 @@
|
||||
<x-forms.action-section>
|
||||
<x-slot name="title">
|
||||
{{ __('Two Factor Authentication') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('Add additional security to your account using two factor authentication.') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
@if ($this->enabled)
|
||||
@if ($showingConfirmation)
|
||||
{{ __('Finish enabling two factor authentication.') }}
|
||||
@else
|
||||
{{ __('You have enabled two factor authentication.') }}
|
||||
@endif
|
||||
@else
|
||||
{{ __('You have not enabled two factor authentication.') }}
|
||||
@endif
|
||||
</h3>
|
||||
|
||||
<div class="mt-3 max-w-xl text-sm text-gray-600 dark:text-gray-400">
|
||||
<p>
|
||||
{{ __('When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone\'s Google Authenticator application.') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@if ($this->enabled)
|
||||
@if ($showingQrCode)
|
||||
<div class="mt-4 max-w-xl text-sm text-gray-600 dark:text-gray-400">
|
||||
<p class="font-semibold">
|
||||
@if ($showingConfirmation)
|
||||
{{ __('To finish enabling two factor authentication, scan the following QR code using your phone\'s authenticator application or enter the setup key and provide the generated OTP code.') }}
|
||||
@else
|
||||
{{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application or enter the setup key.') }}
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 p-2 inline-block bg-white">
|
||||
{!! $this->user->twoFactorQrCodeSvg() !!}
|
||||
</div>
|
||||
|
||||
<div class="mt-4 max-w-xl text-sm text-gray-600 dark:text-gray-400">
|
||||
<p class="font-semibold">
|
||||
{{ __('Setup Key') }}: {{ decrypt($this->user->two_factor_secret) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@if ($showingConfirmation)
|
||||
<div class="mt-4">
|
||||
|
||||
|
||||
<x-input id="code" label="{{ __('Code') }}" type="text" name="code" class="block mt-1 w-1/2" inputmode="numeric" autofocus autocomplete="one-time-code"
|
||||
wire:model="code"
|
||||
wire:keydown.enter="confirmTwoFactorAuthentication" />
|
||||
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if ($showingRecoveryCodes)
|
||||
<div class="mt-4 max-w-xl text-sm text-gray-600 dark:text-gray-400">
|
||||
<p class="font-semibold">
|
||||
{{ __('Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-1 max-w-xl mt-4 px-4 py-4 font-mono text-sm bg-gray-100 dark:bg-gray-900 dark:text-gray-100 rounded-lg">
|
||||
@foreach (json_decode(decrypt($this->user->two_factor_recovery_codes), true) as $code)
|
||||
<div>{{ $code }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
<div class="mt-5">
|
||||
@if (! $this->enabled)
|
||||
<x-forms.confirms-password wire:then="enableTwoFactorAuthentication">
|
||||
<x-button type="button" wire:loading.attr="disabled">
|
||||
{{ __('Enable') }}
|
||||
</x-button>
|
||||
</x-forms.confirms-password>
|
||||
@else
|
||||
@if ($showingRecoveryCodes)
|
||||
<x-forms.confirms-password wire:then="regenerateRecoveryCodes">
|
||||
<x-button class="btn-outline" class="me-3">
|
||||
{{ __('Regenerate Recovery Codes') }}
|
||||
</x-button>
|
||||
</x-forms.confirms-password>
|
||||
@elseif ($showingConfirmation)
|
||||
<x-forms.confirms-password wire:then="confirmTwoFactorAuthentication">
|
||||
<x-button type="button" class="me-3" wire:loading.attr="disabled">
|
||||
{{ __('Confirm') }}
|
||||
</x-button>
|
||||
</x-forms.confirms-password>
|
||||
@else
|
||||
<x-forms.confirms-password wire:then="showRecoveryCodes">
|
||||
<x-button class="btn-outline" class="me-3">
|
||||
{{ __('Show Recovery Codes') }}
|
||||
</x-button>
|
||||
</x-forms.confirms-password>
|
||||
@endif
|
||||
|
||||
@if ($showingConfirmation)
|
||||
<x-forms.confirms-password wire:then="disableTwoFactorAuthentication">
|
||||
<x-button class="btn-outline" wire:loading.attr="disabled">
|
||||
{{ __('Cancel') }}
|
||||
</x-button>
|
||||
</x-forms.confirms-password>
|
||||
@else
|
||||
<x-forms.confirms-password wire:then="disableTwoFactorAuthentication">
|
||||
<x-button class="btn-error text-white" wire:loading.attr="disabled">
|
||||
{{ __('Disable') }}
|
||||
</x-button>
|
||||
</x-forms.confirms-password>
|
||||
@endif
|
||||
|
||||
@endif
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-forms.action-section>
|
||||
@@ -0,0 +1,40 @@
|
||||
<x-forms.form-section submit="updatePassword">
|
||||
<x-slot name="title">
|
||||
{{ __('Update Password') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('Ensure your account is using a long, random password to stay secure.') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="form">
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
|
||||
<x-input id="current_password" label="{{ __('Current Password') }}" type="password" class="mt-1 block w-full" wire:model="state.current_password" error-field="current_password" autocomplete="current-password" />
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
|
||||
<x-input id="password" label="{{ __('New Password') }}" type="password" class="mt-1 block w-full" wire:model="state.password" error-field="password" autocomplete="new-password" />
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
|
||||
<x-input id="password_confirmation" label="{{ __('Confirm Password') }}" type="password" class="mt-1 block w-full" wire:model="state.password_confirmation" error-field="password_confirmation" autocomplete="new-password" />
|
||||
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="actions">
|
||||
<x-forms.action-message class="me-3" on="saved">
|
||||
{{ __('Saved.') }}
|
||||
</x-forms.action-message>
|
||||
|
||||
<x-button type="submit">
|
||||
{{ __('Save') }}
|
||||
</x-button>
|
||||
</x-slot>
|
||||
</x-forms.form-section>
|
||||
@@ -0,0 +1,97 @@
|
||||
<x-forms.form-section submit="updateProfileInformation">
|
||||
<x-slot name="title">
|
||||
{{ __('Profile Information') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('Update your account\'s profile information and email address.') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="form">
|
||||
|
||||
<!-- Profile Photo -->
|
||||
@if (Laravel\Jetstream\Jetstream::managesProfilePhotos())
|
||||
<div x-data="{photoName: null, photoPreview: null}" class="col-span-6 sm:col-span-4">
|
||||
|
||||
<!-- Profile Photo File Input -->
|
||||
<input type="file" id="photo" class="hidden"
|
||||
wire:model.live="photo"
|
||||
x-ref="photo"
|
||||
x-on:change="
|
||||
photoName = $refs.photo.files[0].name;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
photoPreview = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL($refs.photo.files[0]);
|
||||
" />
|
||||
|
||||
<label for="photo" class="pt-0 label label-text font-semibold">
|
||||
<span>{{ __('Photo') }} </span>
|
||||
</label>
|
||||
|
||||
<!-- Current Profile Photo -->
|
||||
<div class="mt-2" x-show="! photoPreview">
|
||||
<img src="{{ $this->user->profile_photo_url }}" alt="{{ $this->user->name }}" class="rounded-full h-20 w-20 object-cover">
|
||||
</div>
|
||||
|
||||
<!-- New Profile Photo Preview -->
|
||||
<div class="mt-2" x-show="photoPreview" style="display: none;">
|
||||
<span class="block rounded-full w-20 h-20 bg-cover bg-no-repeat bg-center"
|
||||
x-bind:style="'background-image: url(\'' + photoPreview + '\');'">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<x-button class="btn-outline" class="mt-2 me-2" type="button" x-on:click.prevent="$refs.photo.click()">
|
||||
{{ __('Select A New Photo') }}
|
||||
</x-button>
|
||||
|
||||
@if ($this->user->profile_photo_path)
|
||||
<x-button class="btn-outline" type="button" class="mt-2" wire:click="deleteProfilePhoto">
|
||||
{{ __('Remove Photo') }}
|
||||
</x-button>
|
||||
@endif
|
||||
|
||||
@if ($errors->has('photo') && is_array($errors->get('photo')))
|
||||
<p class="text-sm text-red-600 dark:text-red-400">{{ $errors->get('photo')[0] }}</p>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Name -->
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<x-input id="name" label="{{ __('Name') }}" type="text" class="mt-1 block w-full" wire:model="state.name" error-field="name" required autocomplete="name" />
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<x-input id="email" label="{{ __('Email') }}" type="email" class="mt-1 block w-full" wire:model="state.email" error-field="email" required autocomplete="username" />
|
||||
|
||||
@if (Laravel\Fortify\Features::enabled(Laravel\Fortify\Features::emailVerification()) && ! $this->user->hasVerifiedEmail())
|
||||
<p class="text-sm mt-2 dark:text-white">
|
||||
{{ __('Your email address is unverified.') }}
|
||||
|
||||
<button type="button" class="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" wire:click.prevent="sendEmailVerification">
|
||||
{{ __('Click here to re-send the verification email.') }}
|
||||
</button>
|
||||
</p>
|
||||
|
||||
@if ($this->verificationLinkSent)
|
||||
<p class="mt-2 font-medium text-sm text-green-600 dark:text-green-400">
|
||||
{{ __('A new verification link has been sent to your email address.') }}
|
||||
</p>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="actions">
|
||||
<x-forms.action-message class="me-3" on="saved">
|
||||
{{ __('Saved.') }}
|
||||
</x-forms.action-message>
|
||||
|
||||
<x-button type="submit" wire:loading.attr="disabled" wire:target="photo">
|
||||
{{ __('Save') }}
|
||||
</x-button>
|
||||
</x-slot>
|
||||
</x-forms.form-section>
|
||||
Reference in New Issue
Block a user