Personal data and password change
This commit is contained in:
@@ -28,6 +28,8 @@ Pfad: `app/Domains/{Domain}/Actions/{ActionName}/`
|
||||
- `$this->users` → `UserRepository`
|
||||
- `$this->tenant` → aktueller `Tenant`
|
||||
|
||||
- Die Controller besitzen ausschließlich eine __invoke() - Funktion
|
||||
- Für die Speichern-Actions werden separate Controller-Klassen erstellt (z. B. `StoreEventParticipantController`)
|
||||
---
|
||||
|
||||
## Repositories
|
||||
@@ -69,3 +71,11 @@ Pfad: `app/Domains/{Domain}/Actions/{ActionName}/`
|
||||
- Attachments werden über `Attachment::fromData(fn () => $content, $filename)->withMime(...)` angehängt
|
||||
- Werden Daten sowohl in `content()` als auch in `attachments()` benötigt, wird eine **private Hilfsmethode mit Lazy-Caching** verwendet (einmaliges Berechnen, Ergebnis in private Property speichern)
|
||||
- Blade-Templates referenzieren Mail-Attachments per `cid:`-Link: `<a href="cid:{{ $filename }}">...</a>`
|
||||
|
||||
## Actions
|
||||
- Die Actions sind in `app/Domains/{Domain}/Actions/{ActionName}/`-Verzeichnissen organisiert
|
||||
- Jede Action besitzt einen Request, einen Command und einen Response
|
||||
- Der Request besitzt auschließlich einen Konstruktor, der die notwendigen Parameter annimmt
|
||||
- Die Response-Klasse enthält ausschließlich die notwendigen Daten für die Antwort
|
||||
- Die Action-Klasse enthält die Logik für die Verarbeitung der Anfrage und die Generierung der Antwort
|
||||
- Die Logik wird in einer execute() - Funktion innerhalb des Commands impplementiert. Private Funktionen, für ausgelagerte Prozesse sind zulässig, wenn der Code damit lesbarer wird.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Dashboard\Actions\UpdatePersonalData;
|
||||
|
||||
use App\Repositories\UserRepository;
|
||||
|
||||
class UpdatePersonalDataCommand
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UpdatePersonalDataRequest $request,
|
||||
private readonly UserRepository $users
|
||||
) {}
|
||||
|
||||
public function execute(): UpdatePersonalDataResponse
|
||||
{
|
||||
$this->users->updatePersonalData($this->request);
|
||||
|
||||
$response = new UpdatePersonalDataResponse();
|
||||
$response->success = true;
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Dashboard\Actions\UpdatePersonalData;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class UpdatePersonalDataRequest
|
||||
{
|
||||
public function __construct(
|
||||
public readonly User $user,
|
||||
public readonly ?string $nickname,
|
||||
public readonly ?string $email,
|
||||
public readonly ?string $phone,
|
||||
public readonly ?string $address1,
|
||||
public readonly ?string $address2,
|
||||
public readonly ?string $postcode,
|
||||
public readonly ?string $city,
|
||||
public readonly ?string $birthday,
|
||||
public readonly ?string $tetanusVaccination,
|
||||
public readonly ?string $medications,
|
||||
public readonly ?string $allergies,
|
||||
public readonly ?string $intolerances,
|
||||
public readonly ?string $eatingHabits,
|
||||
public readonly ?string $swimmingPermission,
|
||||
public readonly ?string $firstAidPermission,
|
||||
public readonly ?string $bankAccountOwner,
|
||||
public readonly ?string $bankAccountIban,
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Dashboard\Actions\UpdatePersonalData;
|
||||
|
||||
class UpdatePersonalDataResponse
|
||||
{
|
||||
public bool $success;
|
||||
}
|
||||
14
app/Domains/Dashboard/Controllers/MessagesController.php
Normal file
14
app/Domains/Dashboard/Controllers/MessagesController.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Dashboard\Controllers;
|
||||
|
||||
use App\Providers\InertiaProvider;
|
||||
use App\Scopes\CommonController;
|
||||
|
||||
class MessagesController extends CommonController {
|
||||
public function __invoke() {
|
||||
$inertiaProvider = new InertiaProvider('Dashboard/Messages', []);
|
||||
|
||||
return $inertiaProvider->render();
|
||||
}
|
||||
}
|
||||
45
app/Domains/Dashboard/Controllers/PersonalDataController.php
Normal file
45
app/Domains/Dashboard/Controllers/PersonalDataController.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Dashboard\Controllers;
|
||||
|
||||
use App\Providers\InertiaProvider;
|
||||
use App\Scopes\CommonController;
|
||||
|
||||
class PersonalDataController extends CommonController
|
||||
{
|
||||
public function __invoke()
|
||||
{
|
||||
if (!$this->checkAuth()) {
|
||||
return redirect()->intended('/login');
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
$data = $this->users->getPersonalData($user);
|
||||
|
||||
$inertiaProvider = new InertiaProvider('Dashboard/PersonalData', [
|
||||
'personalData' => [
|
||||
'firstname' => $data['firstname'],
|
||||
'lastname' => $data['lastname'],
|
||||
'birthday' => $data['birthday'],
|
||||
'nickname' => $data['nickname'],
|
||||
'email' => $data['email'],
|
||||
'phone' => $data['phone'],
|
||||
'address1' => $data['address_1'],
|
||||
'address2' => $data['address_2'],
|
||||
'postcode' => $data['postcode'],
|
||||
'city' => $data['city'],
|
||||
'medications' => $data['medications'],
|
||||
'allergies' => $data['allergies'],
|
||||
'intolerances' => $data['intolerances'],
|
||||
'eatingHabits' => $data['eating_habits'],
|
||||
'swimmingPermission' => $data['swimming_permission'],
|
||||
'firstAidPermission' => $data['first_aid_permission'],
|
||||
'bankAccountOwner' => $data['bank_account_owner'],
|
||||
'bankAccountIban' => $data['bank_account_iban'],
|
||||
'tetanusVaccination' => $data['tetanus_vaccination'],
|
||||
],
|
||||
]);
|
||||
|
||||
return $inertiaProvider->render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Dashboard\Controllers;
|
||||
|
||||
use App\Domains\Dashboard\Actions\UpdatePersonalData\UpdatePersonalDataCommand;
|
||||
use App\Domains\Dashboard\Actions\UpdatePersonalData\UpdatePersonalDataRequest;
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class StorePersonalDataController extends CommonController
|
||||
{
|
||||
public function __invoke(Request $request): JsonResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$actionRequest = new UpdatePersonalDataRequest(
|
||||
user: $user,
|
||||
nickname: $request->input('nickname'),
|
||||
email: $request->input('email'),
|
||||
phone: $request->input('phone'),
|
||||
address1: $request->input('address1'),
|
||||
address2: $request->input('address2'),
|
||||
postcode: $request->input('postcode'),
|
||||
city: $request->input('city'),
|
||||
medications: $request->input('medications'),
|
||||
allergies: $request->input('allergies'),
|
||||
intolerances: $request->input('intolerances'),
|
||||
eatingHabits: $request->input('eatingHabits'),
|
||||
swimmingPermission: $request->input('swimmingPermission'),
|
||||
firstAidPermission: $request->input('firstAidPermission'),
|
||||
bankAccountOwner: $request->input('bankAccountOwner'),
|
||||
bankAccountIban: $request->input('bankAccountIban'),
|
||||
birthday: $request->input('birthday'),
|
||||
tetanusVaccination: $request->input('tetanusVaccination'),
|
||||
);
|
||||
|
||||
$command = new UpdatePersonalDataCommand($actionRequest, $this->users);
|
||||
$command->execute();
|
||||
|
||||
return response()->json(['success' => true, 'message' => 'Deine Daten wurden erfolgreich gespeichert.']);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Domains\Dashboard\Controllers\DashboardController;
|
||||
use App\Domains\Dashboard\Controllers\StorePersonalDataController;
|
||||
use App\Middleware\IdentifyTenant;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@@ -11,7 +12,10 @@ Route::middleware(IdentifyTenant::class)->group(function () {
|
||||
Route::get('/open-cost-units', [DashboardController::class, 'getOpenCostUnits']);
|
||||
Route::get('/upcoming-events', [DashboardController::class, 'getUpcomingEvents']);
|
||||
Route::get('/my-participations', [DashboardController::class, 'getMyParticipations']);
|
||||
Route::post('/personal-data', StorePersonalDataController::class);
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1 +1,16 @@
|
||||
<?php
|
||||
|
||||
use App\Domains\Dashboard\Controllers\DashboardController;
|
||||
use App\Domains\Dashboard\Controllers\MessagesController;
|
||||
use App\Domains\Dashboard\Controllers\PersonalDataController;
|
||||
use App\Middleware\IdentifyTenant;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::middleware(IdentifyTenant::class)->group(function () {
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::get('/personal-data', PersonalDataController::class);
|
||||
Route::get('/messages', MessagesController::class);
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
25
app/Domains/Dashboard/Views/Messages.vue
Normal file
25
app/Domains/Dashboard/Views/Messages.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<script setup>
|
||||
import AppLayout from "../../../../resources/js/layouts/AppLayout.vue";
|
||||
import ShadowedBox from "../../../Views/Components/ShadowedBox.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout title='Meine Nachrichten'>
|
||||
<shadowed-box style="width: 95%; margin: 20px auto; padding: 20px; overflow-x: hidden;">
|
||||
Diese Funktion steht aktuell nicht zur Verfügung.<br />
|
||||
Bitte versuche es später noch einmal.
|
||||
</shadowed-box>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-size: 0.95rem;
|
||||
box-sizing: border-box;
|
||||
resize: vertical;
|
||||
}
|
||||
</style>
|
||||
@@ -27,8 +27,8 @@ function navigateTo(url) {
|
||||
{{participation.arrivalDateReadable}} - {{participation.departureDateReadable}}
|
||||
</td>
|
||||
<td>
|
||||
<Icon name="euro-sign" style="padding: 5px; font-size: 11pt; color: #ffffff; margin-right: 5px;" :class="participation.needs_payment ? 'bg-red' : 'bg-green'" />
|
||||
<Icon name="award" style="padding: 5px; font-size: 11pt; color: #ffffff; margin-right: 5px;" :class="participation.cocColor" />
|
||||
<Icon name="euro-sign" style="padding: 2px; font-size: 10pt; color: #ffffff; margin-right: 5px;" :class="participation.needs_payment ? 'bg-red' : 'bg-green'" />
|
||||
<Icon name="award" style="padding: 2px; font-size: 10pt; color: #ffffff; margin-right: 5px;" :class="participation.cocColor" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
186
app/Domains/Dashboard/Views/PersonalData.vue
Normal file
186
app/Domains/Dashboard/Views/PersonalData.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { request } from '../../../../resources/js/components/HttpClient.js'
|
||||
import AppLayout from "../../../../resources/js/layouts/AppLayout.vue";
|
||||
import ShadowedBox from "../../../Views/Components/ShadowedBox.vue";
|
||||
import {toast} from "vue3-toastify";
|
||||
|
||||
const props = defineProps({
|
||||
personalData: Object,
|
||||
})
|
||||
|
||||
const form = reactive({
|
||||
nickname: props.personalData.nickname ?? '',
|
||||
email: props.personalData.email ?? '',
|
||||
phone: props.personalData.phone ?? '',
|
||||
address1: props.personalData.address1 ?? '',
|
||||
address2: props.personalData.address2 ?? '',
|
||||
postcode: props.personalData.postcode ?? '',
|
||||
city: props.personalData.city ?? '',
|
||||
birthday: props.personalData.birthday ?? '',
|
||||
tetanusVaccination: props.personalData.tetanusVaccination ?? '',
|
||||
medications: props.personalData.medications ?? '',
|
||||
allergies: props.personalData.allergies ?? '',
|
||||
intolerances: props.personalData.intolerances ?? '',
|
||||
eatingHabits: props.personalData.eatingHabits ?? '',
|
||||
swimmingPermission: props.personalData.swimmingPermission ?? '',
|
||||
firstAidPermission: props.personalData.firstAidPermission ?? '',
|
||||
bankAccountOwner: props.personalData.bankAccountOwner ?? '',
|
||||
bankAccountIban: props.personalData.bankAccountIban ?? '',
|
||||
})
|
||||
|
||||
const saving = ref(false)
|
||||
const successMessage = ref('')
|
||||
const errorMessage = ref('')
|
||||
|
||||
const submit = async () => {
|
||||
saving.value = true
|
||||
successMessage.value = ''
|
||||
errorMessage.value = ''
|
||||
|
||||
const result = await request('/api/v1/dashboard/personal-data', {
|
||||
method: 'POST',
|
||||
body: { ...form },
|
||||
})
|
||||
|
||||
saving.value = false
|
||||
|
||||
if (result?.success) {
|
||||
toast.success(result.message)
|
||||
} else {
|
||||
toast.error(result.message)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout title='Persönliche Daten'>
|
||||
<shadowed-box style="width: 95%; margin: 20px auto; padding: 20px; overflow-x: hidden;">
|
||||
|
||||
<div class="max-w-2xl mx-auto p-6">
|
||||
<form @submit.prevent="submit">
|
||||
<table class="form-table" style="width: 90%; margin: 10px;">
|
||||
|
||||
<!-- Nicht veränderbare Felder -->
|
||||
<tr>
|
||||
<td style="width: 200px; padding: 5px;">Vorname:</td>
|
||||
<td><span class="text-gray-700">{{ personalData.firstname }}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 200px; padding: 5px;">Nachname:</td>
|
||||
<td><span class="text-gray-700">{{ personalData.lastname }}</span></td>
|
||||
</tr>
|
||||
|
||||
|
||||
<!-- Veränderbare Felder -->
|
||||
<tr>
|
||||
<td>Pfadiname:</td>
|
||||
<td><input type="text" v-model="form.nickname" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>E-Mail:</td>
|
||||
<td><input type="email" v-model="form.email" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Telefon:</td>
|
||||
<td><input type="text" v-model="form.phone" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Straße / Hausnummer:</td>
|
||||
<td><input type="text" v-model="form.address1" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adresszusatz:</td>
|
||||
<td><input type="text" v-model="form.address2" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PLZ:</td>
|
||||
<td><input type="text" v-model="form.postcode" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ort:</td>
|
||||
<td><input type="text" v-model="form.city" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 200px; padding: 5px;">Geburtsdatum:</td>
|
||||
<td><input type="date" v-model="form.birthday" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Medikamente:</td>
|
||||
<td><input type="text" v-model="form.medications" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Allergien:</td>
|
||||
<td><input type="text" v-model="form.allergies" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unverträglichkeiten:</td>
|
||||
<td><input type="text" v-model="form.intolerances" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Letzte Tetanus-Impfung:</td>
|
||||
<td><input type="date" v-model="form.tetanusVaccination" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ernährungsgewohnheiten:</td>
|
||||
<td>
|
||||
<select v-model="form.eatingHabits">
|
||||
<option value="EATING_HABIT_VEGAN">Vegan</option>
|
||||
<option value="EATING_HABIT_VEGETARIAN">Vegetarisch</option>
|
||||
<option value="EATING_HABIT_OMNIVOR">Omnivor</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Badeerlaubnis:</td>
|
||||
<td>
|
||||
<select v-model="form.swimmingPermission">
|
||||
<option value="SWIMMING_PERMISSION_ALLOWED">Erteilt, kann schwimmen</option>
|
||||
<option value="SWIMMING_PERMISSION_LIMITED">Erteilt, kann nicht schwimmen</option>
|
||||
<option value="SWIMMING_PERMISSION_DENIED">Nicht erteilt</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Erste-Hilfe-Erlaubnis:</td>
|
||||
<td>
|
||||
<select v-model="form.firstAidPermission">
|
||||
<option value="FIRST_AID_PERMISSION_ALLOWED">Erweiterte Erste Hilfe erlaubt</option>
|
||||
<option value="FIRST_AID_PERMISSION_DENIED">Erweiterte Erste Hilfe verweigert</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Kontoinhaber:</td>
|
||||
<td><input type="text" v-model="form.bankAccountOwner" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IBAN:</td>
|
||||
<td><input type="text" v-model="form.bankAccountIban" /></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" class="btn-row" style="padding-top: 20px;">
|
||||
<button type="submit" class="button" :disabled="saving">
|
||||
{{ saving ? 'Wird gespeichert…' : 'Speichern' }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</shadowed-box>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-size: 0.95rem;
|
||||
box-sizing: border-box;
|
||||
resize: vertical;
|
||||
}
|
||||
</style>
|
||||
24
app/Domains/UserManagement/Controllers/ProfileController.php
Normal file
24
app/Domains/UserManagement/Controllers/ProfileController.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\UserManagement\Controllers;
|
||||
|
||||
use App\Providers\InertiaProvider;
|
||||
use App\Scopes\CommonController;
|
||||
|
||||
class ProfileController extends CommonController
|
||||
{
|
||||
public function __invoke()
|
||||
{
|
||||
if (!$this->checkAuth()) {
|
||||
return redirect()->intended('/login');
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
$inertiaProvider = new InertiaProvider('UserManagement/Profile', [
|
||||
'username' => $user->username,
|
||||
]);
|
||||
|
||||
return $inertiaProvider->render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\UserManagement\Controllers;
|
||||
|
||||
use App\Domains\UserManagement\Actions\UserChangePassword\UserChangePasswordCommand;
|
||||
use App\Domains\UserManagement\Actions\UserChangePassword\UserChangePasswordRequest;
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class StoreProfileController extends CommonController
|
||||
{
|
||||
public function __invoke(Request $request): JsonResponse
|
||||
{
|
||||
if (!$this->checkAuth()) {
|
||||
return response()->json(['success' => false, 'message' => 'Unauthorized'], 401);
|
||||
}
|
||||
|
||||
$password = $request->input('password');
|
||||
$passwordConfirmation = $request->input('password_confirmation');
|
||||
|
||||
if (empty($password)) {
|
||||
return response()->json(['success' => false, 'message' => 'Bitte ein Passwort eingeben.'], 422);
|
||||
}
|
||||
|
||||
if ($password !== $passwordConfirmation) {
|
||||
return response()->json(['success' => false, 'message' => 'Die Passwörter stimmen nicht überein.'], 422);
|
||||
}
|
||||
|
||||
$actionRequest = new UserChangePasswordRequest(auth()->user(), $password);
|
||||
$command = new UserChangePasswordCommand($actionRequest);
|
||||
$command->execute();
|
||||
|
||||
auth()->logout();
|
||||
return response()->json(['success' => true, 'message' => 'Dein Passwort wurde erfolgreich geändert.']);
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,15 @@
|
||||
use App\Domains\UserManagement\Controllers\EmailVerificationController;
|
||||
use App\Domains\UserManagement\Controllers\RegistrationController;
|
||||
use App\Domains\UserManagement\Controllers\ResetPasswordController;
|
||||
use App\Domains\UserManagement\Controllers\StoreProfileController;
|
||||
use App\Middleware\IdentifyTenant;
|
||||
use App\Providers\GlobalDataProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Inertia\Inertia;
|
||||
|
||||
Route::prefix('v1')
|
||||
Route::prefix('/api/v1')
|
||||
->group(function () {
|
||||
Route::middleware(IdentifyTenant::class)->group(function () {
|
||||
Route::post('/profile', StoreProfileController::class);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use App\Domains\UserManagement\Controllers\EmailVerificationController;
|
||||
use App\Domains\UserManagement\Controllers\LoginController;
|
||||
use App\Domains\UserManagement\Controllers\LogOutController;
|
||||
use App\Domains\UserManagement\Controllers\ProfileController;
|
||||
use App\Domains\UserManagement\Controllers\RegistrationController;
|
||||
use App\Domains\UserManagement\Controllers\ResetPasswordController;
|
||||
use App\Middleware\IdentifyTenant;
|
||||
@@ -20,6 +21,8 @@ Route::middleware(IdentifyTenant::class)->group(function () {
|
||||
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::post('/logout', [LogoutController::class, 'logout']);
|
||||
Route::get('/profile', ProfileController::class);
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
100
app/Domains/UserManagement/Views/Profile.vue
Normal file
100
app/Domains/UserManagement/Views/Profile.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import AppLayout from '../../../../resources/js/layouts/AppLayout.vue'
|
||||
import ShadowedBox from '../../../Views/Components/ShadowedBox.vue'
|
||||
import { request } from '../../../../resources/js/components/HttpClient.js'
|
||||
import {toast} from "vue3-toastify";
|
||||
|
||||
const props = defineProps({
|
||||
username: String,
|
||||
})
|
||||
|
||||
const password = ref('')
|
||||
const passwordConfirmation = ref('')
|
||||
const saving = ref(false)
|
||||
const successMessage = ref('')
|
||||
const errorMessage = ref('')
|
||||
|
||||
const submit = async () => {
|
||||
if (!password.value) {
|
||||
toast.error('Bitte gib ein neues Passwort ein')
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.value !== passwordConfirmation.value) {
|
||||
toast.error('Die Wiederholung des Passworts stimmt nicht mit dem Passwort überein')
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
saving.value = true
|
||||
successMessage.value = ''
|
||||
errorMessage.value = ''
|
||||
|
||||
const result = await request('/api/v1/profile', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
password: password.value,
|
||||
password_confirmation: passwordConfirmation.value,
|
||||
},
|
||||
})
|
||||
|
||||
saving.value = false
|
||||
|
||||
if (result?.success) {
|
||||
toast.success(result.message)
|
||||
password.value = ''
|
||||
passwordConfirmation.value = ''
|
||||
} else {
|
||||
toast.error(result?.message ?? 'Beim Speichern ist ein Fehler aufgetreten.')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout title="Profil">
|
||||
<shadowed-box style="width: 95%; margin: 20px auto; padding: 20px; overflow-x: hidden;">
|
||||
<h2>Mein Profil</h2>
|
||||
<form @submit.prevent="submit">
|
||||
<table class="form-table" style="width: 90%; margin: auto;">
|
||||
<tr>
|
||||
<td style="width: 250px;">Anmeldename:</td>
|
||||
<td>
|
||||
<span>{{ username }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Neues Passwort:</td>
|
||||
<td>
|
||||
<input type="password" v-model="password" autocomplete="new-password" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Passwort wiederholen:</td>
|
||||
<td>
|
||||
<input type="password" v-model="passwordConfirmation" autocomplete="new-password" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="btn-row">
|
||||
<button type="submit" class="button" :disabled="saving">
|
||||
{{ saving ? 'Wird gespeichert…' : 'Passwort ändern' }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</shadowed-box>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.feedback {
|
||||
padding: 10px 14px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.feedback.success { background: #f0fdf4; color: #15803d; border: 1px solid #bbf7d0; }
|
||||
.feedback.error { background: #fef2f2; color: #b91c1c; border: 1px solid #fecaca; }
|
||||
</style>
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Domains\Dashboard\Actions\UpdatePersonalData\UpdatePersonalDataRequest;
|
||||
use App\Models\User;
|
||||
use DateTime;
|
||||
|
||||
@@ -47,4 +48,51 @@ class UserRepository {
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function getPersonalData(User $user): array
|
||||
{
|
||||
return [
|
||||
'firstname' => $user->firstname ?? '',
|
||||
'lastname' => $user->lastname ?? '',
|
||||
'birthday' => $user->birthday ?? null,
|
||||
'nickname' => $user->nickname ?? null,
|
||||
'email' => $user->email ?? null,
|
||||
'phone' => $user->phone ?? null,
|
||||
'address_1' => $user->address_1 ?? null,
|
||||
'address_2' => $user->address_2 ?? null,
|
||||
'postcode' => $user->postcode ?? null,
|
||||
'city' => $user->city ?? null,
|
||||
'medications' => $user->medications ?? null,
|
||||
'allergies' => $user->allergies ?? null,
|
||||
'intolerances' => $user->intolerances ?? null,
|
||||
'tetanus_vaccination' => $user->tetanus_vaccination ?? null,
|
||||
'eating_habits' => $user->eating_habits ?? null,
|
||||
'swimming_permission' => $user->swimming_permission ?? null,
|
||||
'first_aid_permission' => $user->first_aid_permission ?? null,
|
||||
'bank_account_owner' => $user->bank_account_owner ?? null,
|
||||
'bank_account_iban' => $user->bank_account_iban ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
public function updatePersonalData(UpdatePersonalDataRequest $request): void
|
||||
{
|
||||
$request->user->update([
|
||||
'nickname' => $request->nickname,
|
||||
'email' => $request->email,
|
||||
'phone' => $request->phone,
|
||||
'address_1' => $request->address1,
|
||||
'address_2' => $request->address2,
|
||||
'postcode' => $request->postcode,
|
||||
'city' => $request->city,
|
||||
'medications' => $request->medications,
|
||||
'allergies' => $request->allergies,
|
||||
'tetanus_vaccination' => $request->tetanusVaccination,
|
||||
'intolerances' => $request->intolerances,
|
||||
'eating_habits' => $request->eatingHabits,
|
||||
'swimming_permission' => $request->swimmingPermission,
|
||||
'first_aid_permission' => $request->firstAidPermission,
|
||||
'bank_account_owner' => $request->bankAccountOwner,
|
||||
'bank_account_iban' => $request->bankAccountIban,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
<?php
|
||||
|
||||
require __DIR__.'/../app/Domains/UserManagement/Routes/api.php';
|
||||
|
||||
|
||||
use App\Domains\UserManagement\Controllers\EmailVerificationController;
|
||||
use App\Domains\UserManagement\Controllers\RegistrationController;
|
||||
use App\Domains\UserManagement\Controllers\ResetPasswordController;
|
||||
use App\Middleware\IdentifyTenant;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Inertia\Inertia;
|
||||
|
||||
Route::prefix('v1')
|
||||
->group(function () {
|
||||
|
||||
@@ -14,6 +14,7 @@ use Illuminate\Support\Facades\Route;
|
||||
require_once __DIR__ . '/../app/Domains/Dashboard/Routes/web.php';
|
||||
require_once __DIR__ . '/../app/Domains/Dashboard/Routes/api.php';
|
||||
require_once __DIR__ . '/../app/Domains/UserManagement/Routes/web.php';
|
||||
require_once __DIR__ . '/../app/Domains/UserManagement/Routes/api.php';
|
||||
require_once __DIR__ . '/../app/Domains/CostUnit/Routes/web.php';
|
||||
require_once __DIR__ . '/../app/Domains/CostUnit/Routes/api.php';
|
||||
require_once __DIR__ . '/../app/Domains/Invoice/Routes/web.php';
|
||||
@@ -38,25 +39,6 @@ Route::middleware(IdentifyTenant::class)->group(function () {
|
||||
Route::get('/retrieve-event-setting-data', [GlobalDataProvider::class, 'getEventSettingData']);
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
|
||||
Route::get('/messages', fn () => inertia('Messages'));
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Route::get('/messages', [TestRenderInertiaProvider::class, 'index']);
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user