Skip to content

Commit 4d787e4

Browse files
Add new account page
1 parent 023f5a3 commit 4d787e4

File tree

13 files changed

+206
-136
lines changed

13 files changed

+206
-136
lines changed

app/Http/Controllers/AccountController.php

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111

1212
class AccountController extends Controller
1313
{
14+
public function show(): View
15+
{
16+
$this->authorize('viewAccount', User::class);
17+
18+
return view('account.account_show');
19+
}
20+
1421
public function edit(): View
1522
{
1623
$this->authorize('editAccount', User::class);

app/Http/Controllers/UserController.php

+1-29
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
use App\Http\Requests\UserRequest;
77
use App\Models\User;
88
use App\Models\UserRole;
9-
use Illuminate\Database\Eloquent\Relations\HasMany;
10-
use Illuminate\Database\Eloquent\Relations\MorphToMany;
119
use Illuminate\Http\RedirectResponse;
1210
use Illuminate\Support\Facades\Session;
1311
use Illuminate\View\View;
@@ -61,33 +59,7 @@ public function show(User $user): View
6159
$this->authorize('view', $user);
6260

6361
return view('users.user_show', [
64-
'user' => $user->load([
65-
'bookings.bookingOption.event.location',
66-
'documents',
67-
'responsibleForEvents' => fn (MorphToMany $events) => $events
68-
->with([
69-
'bookingOptions' => fn (HasMany $bookingOptions) => $bookingOptions
70-
->withCount([
71-
'bookings',
72-
]),
73-
])
74-
->withCount([
75-
'documents',
76-
'groups',
77-
]),
78-
'responsibleForEventSeries' => fn (MorphToMany $eventSeries) => $eventSeries
79-
->withCount([
80-
'documents',
81-
'events',
82-
])
83-
->withMin('events', 'started_at')
84-
->withMax('events', 'started_at')
85-
->withCasts([
86-
'events_min_started_at' => 'datetime',
87-
'events_max_started_at' => 'datetime',
88-
]),
89-
'responsibleForOrganizations',
90-
]),
62+
'user' => $user->loadProfileData(),
9163
]);
9264
}
9365

app/Models/User.php

+41-2
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,15 @@ public function name(): Attribute
114114

115115
public function bookings(): HasMany
116116
{
117-
return $this->hasMany(Booking::class, 'booked_by_user_id');
117+
return $this->hasMany(Booking::class, 'booked_by_user_id')
118+
->orderByDesc('booked_at')
119+
->orderByDesc('created_at');
118120
}
119121

120122
public function documents(): HasMany
121123
{
122-
return $this->hasMany(Document::class, 'uploaded_by_user_id');
124+
return $this->hasMany(Document::class, 'uploaded_by_user_id')
125+
->orderBy('title');
123126
}
124127

125128
/**
@@ -222,6 +225,42 @@ public function hasAbility(Ability $ability): bool
222225
return false;
223226
}
224227

228+
public function loadProfileData(): self
229+
{
230+
$this->load([
231+
'bookings.bookingOption.event.location',
232+
'documents.reference',
233+
'responsibleForEvents' => fn (MorphToMany $events) => $events
234+
->with([
235+
'bookingOptions' => fn (HasMany $bookingOptions) => $bookingOptions
236+
->withCount([
237+
'bookings',
238+
]),
239+
])
240+
->withCount([
241+
'documents',
242+
'groups',
243+
]),
244+
'responsibleForEventSeries' => fn (MorphToMany $eventSeries) => $eventSeries
245+
->withCount([
246+
'documents',
247+
'events',
248+
])
249+
->withMin('events', 'started_at')
250+
->withMax('events', 'started_at')
251+
->withCasts([
252+
'events_min_started_at' => 'datetime',
253+
'events_max_started_at' => 'datetime',
254+
]),
255+
'responsibleForOrganizations',
256+
]);
257+
258+
// Set backwards relation for documents.
259+
$this->documents->each(fn (Document $document) => $document->setRelation('uploadedByUser', $this));
260+
261+
return $this;
262+
}
263+
225264
public function sendEmailVerificationNotification(): void
226265
{
227266
$this->notify(new VerifyEmailNotification($this));

app/Options/Ability.php

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ enum Ability: string
88
{
99
use NamedOption;
1010

11+
case ViewAccount = 'users.view_account';
1112
case EditAccount = 'users.edit_account';
1213
case ManagePersonalAccessTokens = 'personal_access_tokens.manage_own';
1314

@@ -64,6 +65,7 @@ enum Ability: string
6465
public function getTranslatedName(): string
6566
{
6667
return match ($this) {
68+
self::ViewAccount => __('View own account'),
6769
self::EditAccount => __('Edit own account'),
6870
self::ManagePersonalAccessTokens => __('Manage personal access tokens'),
6971

app/Policies/UserPolicy.php

+12-4
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ public function viewAny(User $user): Response
2020
}
2121

2222
/**
23-
* Determine whether the user can view the model.
23+
* Determine whether the user can view the user's profile.
2424
*/
2525
public function view(User $user, User $model): Response
2626
{
27-
if ($user->is($model)) {
28-
return $this->allow();
29-
}
27+
/**
28+
* {@see self::viewAccount()} for own profile.
29+
*/
3030

3131
return $this->viewAny($user);
3232
}
@@ -71,6 +71,14 @@ public function forceDelete(User $user, User $model): Response
7171
return $this->deny();
7272
}
7373

74+
/**
75+
* Determine whether a user can view his/her profile.
76+
*/
77+
public function viewAccount(User $user): Response
78+
{
79+
return $this->requireAbility($user, Ability::ViewAccount);
80+
}
81+
7482
/**
7583
* Determine whether a user can edit his/her profile.
7684
*/

lang/de.json

+2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
"Edit event series": "Veranstaltungsreihen bearbeiten",
108108
"Edit events": "Veranstaltungen bearbeiten",
109109
"Edit locations": "Standorte bearbeiten",
110+
"Edit my account": "Mein Konto bearbeiten",
110111
"Edit organizations": "Organisationen bearbeiten",
111112
"Edit own account": "Eigenes Konto bearbeiten",
112113
"Edit payment status": "Zahlungsstatus bearbeiten",
@@ -309,6 +310,7 @@
309310
"View events": "Veranstaltungen ansehen",
310311
"View locations": "Standorte ansehen",
311312
"View organizations": "Organisationen ansehen",
313+
"View own account": "Eigenes Konto ansehen",
312314
"View payment status": "Zahlungsstatus ansehen",
313315
"View private event series": "Private Veranstaltungsreihen ansehen",
314316
"View private events": "Private Veranstaltungen ansehen",

resources/views/account/account_form.blade.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
@endphp
77

88
@section('title')
9-
{{ __('My account') }}
9+
{{ __('Edit my account') }}
1010
@endsection
1111

1212
@section('content')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
@extends('layouts.app')
2+
3+
@php
4+
/** @var \App\Models\User $user */
5+
$user = \Illuminate\Support\Facades\Auth::user()->loadProfileData();
6+
@endphp
7+
8+
@section('title')
9+
{{ __('My account') }}: {{ $user->name }}
10+
@endsection
11+
12+
@section('headline-buttons')
13+
@can('editAccount', \App\Models\User::class)
14+
<x-bs::button.link href="{{ route('account.edit') }}">{{ __('Edit my account') }}</x-bs::button.link>
15+
@endif
16+
@endsection
17+
18+
@section('content')
19+
@include('users.shared.user_profile', [
20+
'user' => $user,
21+
])
22+
@endsection

resources/views/documents/shared/document_uploaded_by.blade.php

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
@can('update', $document->uploadedByUser)
1+
@can('view', $document->uploadedByUser)
2+
{!! __('File uploaded by :name', [
3+
'name' => sprintf(
4+
'<a href="%s">%s</a>',
5+
route('users.show', $document->uploadedByUser),
6+
$document->uploadedByUser->name
7+
),
8+
]) !!}
9+
@elsecan('update', $document->uploadedByUser)
210
{!! __('File uploaded by :name', [
311
'name' => sprintf(
412
'<a href="%s">%s</a>',

resources/views/layouts/header.blade.php

+7-4
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,15 @@
9898
<i class="fa fa-user-circle"></i>
9999
{{ $loggedInUser->name }}
100100
<x-slot:dropdown class="dropdown-menu-end">
101-
@if($loggedInUser->can('editAccount', \App\Models\User::class))
101+
@can('viewAccount', \App\Models\User::class)
102+
<x-bs::dropdown.item href="{{ route('account.show') }}">
103+
<i class="fa fa-fw fa-user-cog"></i> {{ __('My account') }}
104+
</x-bs::dropdown.item>
105+
@elsecan('editAccount', \App\Models\User::class)
102106
<x-bs::dropdown.item href="{{ route('account.edit') }}">
103-
<i class="fa fa-fw fa-user-cog"></i>
104-
{{ __('My account') }}
107+
<i class="fa fa-fw fa-user-cog"></i> {{ __('My account') }}
105108
</x-bs::dropdown.item>
106-
@endif
109+
@endcan
107110
@if($loggedInUser->can('viewOwn', \App\Models\PersonalAccessToken::class))
108111
<x-bs::dropdown.item href="{{ route('personal-access-tokens.index') }}">
109112
<i class="fa fa-fw fa-id-card-clip"></i>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
@php
2+
/** @var \App\Models\User $user */
3+
@endphp
4+
5+
<div class="my-1">
6+
<span class="text-nowrap me-3"><x-badge.active-status :active="$user->status"/></span>
7+
<span class="text-nowrap me-3"><i class="fa fa-fw fa-sign-in-alt"></i> {{ __('Last login') }}
8+
{{ $user->last_login_at ? formatDateTime($user->last_login_at) : __('never') }}</span>
9+
@if($user->userRoles->isNotEmpty())
10+
<span class="me-3">
11+
<i class="fa fa-fw fa-user-group" title="{{ __('User roles') }}"></i>
12+
@foreach($user->userRoles->sortBy('name') as $userRole)
13+
<x-bs::badge variant="primary">{{ $userRole->name }}</x-bs::badge>
14+
@endforeach
15+
</span>
16+
@endif
17+
</div>
18+
19+
<div class="mb-3">
20+
@isset($user->date_of_birth)
21+
<span class="text-nowrap me-3"><i class="fa fa-fw fa-cake-candles" title="{{ __('Date of birth') }}"></i> {{ formatDate($user->date_of_birth) }}</span>
22+
@endisset
23+
@isset($user->phone)
24+
<span class="text-nowrap me-3"><i class="fa fa-fw fa-phone" title="{{ __('Phone number') }}"></i> {{ $user->phone }}</span>
25+
@endisset
26+
<span class="text-nowrap me-3"><i class="fa fa-fw fa-at" title="{{ __('E-mail') }}"></i> {{ $user->email }}
27+
@isset($user->email_verified_at)
28+
<x-bs::badge variant="success">{{ __('verified') }}</x-bs::badge>
29+
@else
30+
<x-bs::badge variant="danger">{{ __('not verified') }}</x-bs::badge>
31+
@endisset
32+
</span>
33+
@if(count($user->addressBlock) > 0)
34+
<span class="text-nowrap me-3"><i class="fa fa-fw fa-location-pin" title="{{ __('Address') }}"></i> {{ implode(', ', $user->addressBlock) }}</span>
35+
@endif
36+
</div>
37+
38+
<div class="row">
39+
<div id="responsibilities" class="col-12 col-xl-6 col-xxl-4">
40+
<h2>{{ __('Responsibilities') }}</h2>
41+
@if(
42+
$user->responsibleForEvents->isEmpty()
43+
&& $user->responsibleForEventSeries->isEmpty()
44+
&& $user->responsibleForOrganizations->isEmpty()
45+
)
46+
<x-bs::alert class="danger">{{ __(':name has not been assigned any responsibilities.', [
47+
'name' => $user->first_name,
48+
]) }}</x-bs::alert>
49+
@endif
50+
@if($user->responsibleForOrganizations->isNotEmpty())
51+
<div class="mb-3">
52+
<h3>{{ __('Organizations') }}</h3>
53+
@include('organizations.shared.organization_list', [
54+
'organizations' => $user->responsibleForOrganizations,
55+
])
56+
</div>
57+
@endif
58+
@if($user->responsibleForEventSeries->isNotEmpty())
59+
<div class="mb-3">
60+
<h3>{{ __('Event series') }}</h3>
61+
@include('event_series.shared.event_series_list', [
62+
'eventSeries' => $user->responsibleForEventSeries,
63+
])
64+
</div>
65+
@endif
66+
@if($user->responsibleForEvents->isNotEmpty())
67+
<div class="mb-3">
68+
<h3>{{ __('Events') }}</h3>
69+
@include('events.shared.event_list', [
70+
'events' => $user->responsibleForEvents,
71+
])
72+
</div>
73+
@endif
74+
</div>
75+
<div id="bookings" class="col-12 col-xl-6 col-xxl-4">
76+
<h2>{{ __('Bookings') }}</h2>
77+
@if($user->bookings->count() === 0)
78+
<x-bs::alert class="danger">{{ __(':name does not have any bookings yet.', [
79+
'name' => $user->first_name,
80+
]) }}</x-bs::alert>
81+
@endif
82+
@include('bookings.shared.booking_list', [
83+
'bookings' => $user->bookings,
84+
])
85+
</div>
86+
<div id="documents" class="col-12 col-xl-6 col-xxl-4">
87+
<h2>{{ __('Documents') }}</h2>
88+
@if($user->documents->count() === 0)
89+
<x-bs::alert class="danger">{{ __(':name has not uploaded any documents yet.', [
90+
'name' => $user->first_name,
91+
]) }}</x-bs::alert>
92+
@endif
93+
@include('documents.shared.document_list', [
94+
'documents' => $user->documents,
95+
])
96+
</div>
97+
</div>

0 commit comments

Comments
 (0)