feat: Phase 5 - polish, validation, rate limiting, Dutch translations
This commit is contained in:
@@ -45,6 +45,17 @@
|
||||
<p class="mt-2 text-sm text-slate-600">{{ __('Page:') }} <span class="font-medium text-slate-800">{{ $page->title }}</span></p>
|
||||
</div>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="mb-6 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-900" role="alert">
|
||||
<p class="font-medium">{{ __('Please fix the following:') }}</p>
|
||||
<ul class="mt-2 list-disc space-y-1 pl-5">
|
||||
@foreach ($errors->all() as $message)
|
||||
<li>{{ $message }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($config !== null)
|
||||
<div class="mb-8 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-900">
|
||||
<p class="font-medium">{{ __('Integration active') }}</p>
|
||||
|
||||
@@ -13,6 +13,47 @@
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
</head>
|
||||
<body class="font-sans antialiased bg-slate-100 text-slate-900" x-data="{ sidebarOpen: false }">
|
||||
@php
|
||||
$adminFlashSuccess = session('status');
|
||||
$adminFlashError = session('error');
|
||||
@endphp
|
||||
@if ($adminFlashSuccess !== null || $adminFlashError !== null)
|
||||
<div
|
||||
class="pointer-events-none fixed bottom-4 right-4 z-[100] flex w-full max-w-sm flex-col gap-2 px-4 sm:px-0"
|
||||
aria-live="polite"
|
||||
>
|
||||
@foreach (array_filter([
|
||||
$adminFlashSuccess !== null ? ['type' => 'success', 'message' => $adminFlashSuccess] : null,
|
||||
$adminFlashError !== null ? ['type' => 'error', 'message' => $adminFlashError] : null,
|
||||
]) as $toast)
|
||||
<div
|
||||
x-data="{ visible: true }"
|
||||
x-show="visible"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="translate-y-2 opacity-0"
|
||||
x-transition:enter-end="translate-y-0 opacity-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="translate-y-0 opacity-100"
|
||||
x-transition:leave-end="translate-y-2 opacity-0"
|
||||
x-init="setTimeout(() => visible = false, 6500)"
|
||||
class="pointer-events-auto flex items-start gap-3 rounded-lg border px-4 py-3 text-sm shadow-lg {{ $toast['type'] === 'success' ? 'border-emerald-200 bg-emerald-50 text-emerald-900' : 'border-red-200 bg-red-50 text-red-900' }}"
|
||||
role="{{ $toast['type'] === 'success' ? 'status' : 'alert' }}"
|
||||
>
|
||||
<p class="min-w-0 flex-1 leading-snug">{{ $toast['message'] }}</p>
|
||||
<button
|
||||
type="button"
|
||||
class="shrink-0 rounded p-0.5 opacity-70 hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
||||
@click="visible = false"
|
||||
aria-label="{{ __('Dismiss notification') }}"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
{{-- Mobile overlay --}}
|
||||
<div
|
||||
x-show="sidebarOpen"
|
||||
@@ -114,18 +155,6 @@
|
||||
</header>
|
||||
|
||||
<main class="flex-1 p-4 sm:p-6 lg:p-8">
|
||||
@if (session('status'))
|
||||
<div class="mb-6 rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800" role="status">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (session('error'))
|
||||
<div class="mb-6 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800" role="alert">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@yield('content')
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('Profile') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
@extends('layouts.admin')
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
|
||||
<div class="max-w-xl">
|
||||
@include('profile.partials.update-profile-information-form')
|
||||
</div>
|
||||
</div>
|
||||
@section('title', __('Profile'))
|
||||
|
||||
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
|
||||
<div class="max-w-xl">
|
||||
@include('profile.partials.update-password-form')
|
||||
</div>
|
||||
</div>
|
||||
@section('mobile_title', __('Profile'))
|
||||
|
||||
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
|
||||
<div class="max-w-xl">
|
||||
@include('profile.partials.delete-user-form')
|
||||
</div>
|
||||
</div>
|
||||
@section('content')
|
||||
<div class="mx-auto max-w-3xl space-y-6">
|
||||
<div>
|
||||
<a href="{{ route('admin.dashboard') }}" class="text-sm font-medium text-indigo-600 hover:text-indigo-500">← {{ __('Back to dashboard') }}</a>
|
||||
<h1 class="mt-4 text-2xl font-semibold text-slate-900">{{ __('Profile') }}</h1>
|
||||
<p class="mt-1 text-sm text-slate-600">{{ __('Update your account settings and password.') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-slate-200 bg-white p-6 shadow-sm sm:p-8">
|
||||
@include('profile.partials.update-profile-information-form')
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-slate-200 bg-white p-6 shadow-sm sm:p-8">
|
||||
@include('profile.partials.update-password-form')
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-slate-200 bg-white p-6 shadow-sm sm:p-8">
|
||||
@include('profile.partials.delete-user-form')
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@endsection
|
||||
|
||||
@@ -33,16 +33,6 @@
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<x-primary-button>{{ __('Save') }}</x-primary-button>
|
||||
|
||||
@if (session('status') === 'password-updated')
|
||||
<p
|
||||
x-data="{ show: true }"
|
||||
x-show="show"
|
||||
x-transition
|
||||
x-init="setTimeout(() => show = false, 2000)"
|
||||
class="text-sm text-gray-600"
|
||||
>{{ __('Saved.') }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -49,16 +49,6 @@
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<x-primary-button>{{ __('Save') }}</x-primary-button>
|
||||
|
||||
@if (session('status') === 'profile-updated')
|
||||
<p
|
||||
x-data="{ show: true }"
|
||||
x-show="show"
|
||||
x-transition
|
||||
x-init="setTimeout(() => show = false, 2000)"
|
||||
class="text-sm text-gray-600"
|
||||
>{{ __('Saved.') }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
'subscribeUrl' => route('public.subscribe', ['publicPage' => $page]),
|
||||
'csrfToken' => csrf_token(),
|
||||
'genericError' => __('Something went wrong. Please try again.'),
|
||||
'labelDay' => __('day'),
|
||||
'labelDays' => __('days'),
|
||||
]))"
|
||||
>
|
||||
@if ($logoUrl !== null)
|
||||
@@ -73,7 +75,7 @@
|
||||
>
|
||||
<div>
|
||||
<div class="font-mono text-2xl font-semibold tabular-nums text-white sm:text-3xl" x-text="pad(days)"></div>
|
||||
<div class="mt-1 text-xs uppercase tracking-wide text-white/60">{{ __('days') }}</div>
|
||||
<div class="mt-1 text-xs uppercase tracking-wide text-white/60" x-text="days === 1 ? labelDay : labelDays"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-mono text-2xl font-semibold tabular-nums text-white sm:text-3xl" x-text="pad(hours)"></div>
|
||||
@@ -164,7 +166,7 @@
|
||||
class="mt-2 w-full rounded-lg bg-white px-4 py-3 text-sm font-semibold text-slate-900 shadow transition hover:bg-white/90 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-slate-900 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
:disabled="submitting"
|
||||
>
|
||||
<span x-show="!submitting">{{ __('Register') }}</span>
|
||||
<span x-show="!submitting">{{ __('public.register_button') }}</span>
|
||||
<span x-show="submitting" x-cloak>{{ __('Sending…') }}</span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user