From ac0a89e34d6c404e7d98929828146b744a233eb0 Mon Sep 17 00:00:00 2001
From: "Sabrina B."
Date: Sun, 26 Oct 2025 00:16:25 +0200
Subject: [PATCH] feat(Notification & membership route)
---
.../Forms/ContactFormController.php | 2 +-
.../Forms/MembershipFormController.php | 9 +-
app/Http/Requests/Forms/ContactRequest.php | 2 +-
app/Http/Requests/Forms/MembershipRequest.php | 5 +-
.../NotifyAdminForMembershipRequest.php | 6 +-
app/Models/Member.php | 3 +-
app/Models/Membership.php | 2 +-
app/Services/ContactService.php | 4 +
app/Services/MemberService.php | 8 +-
config/logging.php | 9 +-
..._10_20_111428_create_memberships_table.php | 2 +-
lang/fr/{membership.php => memberships.php} | 0
.../Forms/MembershipFormController.ts | 24 +-
resources/js/components/flash-message.tsx | 41 ++
resources/js/pages/forms/contact.tsx | 47 +-
resources/js/pages/forms/membership.tsx | 458 ++++++++++--------
resources/js/routes/index.ts | 14 +-
resources/js/routes/membership/index.ts | 10 +-
resources/js/types/index.d.ts | 26 +
19 files changed, 393 insertions(+), 279 deletions(-)
rename lang/fr/{membership.php => memberships.php} (100%)
create mode 100644 resources/js/components/flash-message.tsx
diff --git a/app/Http/Controllers/Forms/ContactFormController.php b/app/Http/Controllers/Forms/ContactFormController.php
index 64c3769..3c6efa9 100644
--- a/app/Http/Controllers/Forms/ContactFormController.php
+++ b/app/Http/Controllers/Forms/ContactFormController.php
@@ -27,7 +27,7 @@ class ContactFormController extends Controller
{
$validated = $request->validated();
try {
- $contact = $this->contactService->registerNewContactRequest($validated);
+ $this->contactService->registerNewContactRequest($validated);
} catch (\Throwable $e) {
\Log::error('Erreur lors de la création d\'un contact', [
'error' => $e->getMessage(),
diff --git a/app/Http/Controllers/Forms/MembershipFormController.php b/app/Http/Controllers/Forms/MembershipFormController.php
index 880d7bd..0447a86 100644
--- a/app/Http/Controllers/Forms/MembershipFormController.php
+++ b/app/Http/Controllers/Forms/MembershipFormController.php
@@ -4,13 +4,11 @@ namespace App\Http\Controllers\Forms;
use App\Http\Controllers\Controller;
use App\Http\Requests\Forms\MembershipRequest;
-use App\Models\Member;
use App\Models\Membership;
use App\Models\Package;
use App\Services\MemberService;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
-use Illuminate\Http\Request;
use Inertia\Inertia;
class MembershipFormController extends Controller
@@ -25,7 +23,7 @@ class MembershipFormController extends Controller
return Inertia::render('forms/membership', [
'plans' => Package::query()
->where('is_active', true)
- ->select('id', 'name', 'price', 'description')
+ ->select('id', 'identifier', 'name', 'price', 'description')
->get()
]);
}
@@ -36,6 +34,7 @@ class MembershipFormController extends Controller
*/
public function store(MembershipRequest $request): RedirectResponse
{
+ dd($request->validated());
$validated = $request->validated();
try {
@@ -49,11 +48,11 @@ class MembershipFormController extends Controller
return redirect()
->route('membership')
- ->with('error', __('memberships.subscription.error'));
+ ->with('error', Membership::getAttributeLabel('memberships.subscription.error'));
}
return redirect()
->route('membership')
- ->with('success', __('memberships.subscription.success'));
+ ->with('success', Membership::getAttributeLabel('memberships.subscription.success'));
}
}
diff --git a/app/Http/Requests/Forms/ContactRequest.php b/app/Http/Requests/Forms/ContactRequest.php
index 77fed5e..5d52e3f 100644
--- a/app/Http/Requests/Forms/ContactRequest.php
+++ b/app/Http/Requests/Forms/ContactRequest.php
@@ -11,7 +11,7 @@ class ContactRequest extends FormRequest
*/
public function authorize(): bool
{
- return false;
+ return true;
}
/**
diff --git a/app/Http/Requests/Forms/MembershipRequest.php b/app/Http/Requests/Forms/MembershipRequest.php
index b6e010f..ee9fd4a 100644
--- a/app/Http/Requests/Forms/MembershipRequest.php
+++ b/app/Http/Requests/Forms/MembershipRequest.php
@@ -11,7 +11,7 @@ class MembershipRequest extends FormRequest
*/
public function authorize(): bool
{
- return false;
+ return true;
}
/**
@@ -26,12 +26,11 @@ class MembershipRequest extends FormRequest
'lastname' => 'required|string|max:255',
'firstname' => 'required|string|max:255',
'email' => 'required|email|max:255',
- 'company' => 'required|string|max:255',
+ 'company' => 'string|max:255',
'address' => 'required|string|max:255',
'zipcode' => 'required|string|max:255',
'city' => 'required|string|max:255',
'phone1' => 'required|string|max:255',
- 'group_id' => 'required|string|max:255',
// Membership
'package' => 'required|string|max:255',
diff --git a/app/Listeners/NotifyAdminForMembershipRequest.php b/app/Listeners/NotifyAdminForMembershipRequest.php
index 4c89c15..43b689b 100644
--- a/app/Listeners/NotifyAdminForMembershipRequest.php
+++ b/app/Listeners/NotifyAdminForMembershipRequest.php
@@ -3,6 +3,7 @@
namespace App\Listeners;
use App\Events\MemberRegistered;
+use App\Models\User;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
@@ -21,6 +22,9 @@ class NotifyAdminForMembershipRequest
*/
public function handle(MemberRegistered $event): void
{
- //
+ $admin = User::where('name', 'SuperAdmin')->first();
+
+ $admin->notify(new AdminNewUserPending($event->user));
+
}
}
diff --git a/app/Models/Member.php b/app/Models/Member.php
index fd4b3c4..6a10569 100644
--- a/app/Models/Member.php
+++ b/app/Models/Member.php
@@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Notifications\Notifiable;
/**
* @property int $id
@@ -63,7 +64,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
*/
class Member extends Model
{
- use HasFactory;
+ use HasFactory, Notifiable;
protected $fillable = [
'user_id',
'keycloak_id',
diff --git a/app/Models/Membership.php b/app/Models/Membership.php
index d319725..017501c 100644
--- a/app/Models/Membership.php
+++ b/app/Models/Membership.php
@@ -59,7 +59,7 @@ class Membership extends Model
public static function getAttributeLabel(string $attribute): string
{
- return __("membership.fields.$attribute");
+ return __("memberships.fields.$attribute");
}
public function member(): BelongsTo
diff --git a/app/Services/ContactService.php b/app/Services/ContactService.php
index 4bcb00b..6cbcfec 100644
--- a/app/Services/ContactService.php
+++ b/app/Services/ContactService.php
@@ -17,5 +17,9 @@ class ContactService
$contact->fill($data);
$contact->save();
+ // Envoyer un email à l'administrateur
+
+ return $contact;
+
}
}
diff --git a/app/Services/MemberService.php b/app/Services/MemberService.php
index 3d5c5c6..fd8780a 100644
--- a/app/Services/MemberService.php
+++ b/app/Services/MemberService.php
@@ -2,6 +2,7 @@
namespace App\Services;
+use App\Events\MemberRegistered;
use App\Models\Member;
use App\Models\MemberGroup;
use App\Models\Package;
@@ -29,7 +30,6 @@ class MemberService
$member->firstname = $data['firstname'];
$member->email = $data['email'];
$member->company = $data['company'] ?? null;
- $member->date_of_birth = Carbon::parse($data['date_of_birth'])->format('Y-m-d H:i:s') ?? null;
$member->address = $data['address'];
$member->zipcode = $data['zipcode'];
$member->city = $data['city'];
@@ -38,7 +38,7 @@ class MemberService
$member->save();
}
- $package = Package::where('id', $data['package_id'])
+ $package = Package::where('identifier', $data['package'])
->where('is_active', true)
->firstOrFail();
@@ -47,11 +47,13 @@ class MemberService
'status' => 'pending',
'package_id' => $package->id ?? null,
'amount' => $data['amount'],
- 'payment_status' => 'pending',
+ 'payment_status' => 'unpaid',
]);
// Notify Admin
+ $admin = Member::where('role', 'admin')->first();
+ event(new MemberRegistered($admin));
return $member;
diff --git a/config/logging.php b/config/logging.php
index 9e998a4..1a7ddb2 100644
--- a/config/logging.php
+++ b/config/logging.php
@@ -18,7 +18,7 @@ return [
|
*/
- 'default' => env('LOG_CHANNEL', 'stack'),
+ 'default' => env('LOG_CHANNEL', 'daily'),
/*
|--------------------------------------------------------------------------
@@ -126,7 +126,12 @@ return [
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
-
+ 'query' => [
+ 'driver' => 'daily',
+ 'path' => storage_path('logs/db/query.log'),
+ 'level' => 'debug',
+ 'days' => 3,
+ ],
],
];
diff --git a/database/migrations/2025_10_20_111428_create_memberships_table.php b/database/migrations/2025_10_20_111428_create_memberships_table.php
index bc489a3..0b719f1 100644
--- a/database/migrations/2025_10_20_111428_create_memberships_table.php
+++ b/database/migrations/2025_10_20_111428_create_memberships_table.php
@@ -16,7 +16,7 @@ return new class extends Migration
$table->foreignId('member_id')->constrained('members')->onDelete('cascade');
$table->foreignId('admin_id')->nullable()->constrained('users')->onDelete('set null');
$table->foreignId('package_id')->constrained('packages')->onDelete('cascade');
- $table->date('start_date');
+ $table->date('start_date')->nullable();
$table->date('end_date')->nullable();
$table->enum('status', ['active', 'expired', 'pending'])->default('pending');
$table->decimal('amount', 10, 2)->default(0);
diff --git a/lang/fr/membership.php b/lang/fr/memberships.php
similarity index 100%
rename from lang/fr/membership.php
rename to lang/fr/memberships.php
diff --git a/resources/js/actions/App/Http/Controllers/Forms/MembershipFormController.ts b/resources/js/actions/App/Http/Controllers/Forms/MembershipFormController.ts
index e89fceb..1710ea9 100644
--- a/resources/js/actions/App/Http/Controllers/Forms/MembershipFormController.ts
+++ b/resources/js/actions/App/Http/Controllers/Forms/MembershipFormController.ts
@@ -1,7 +1,7 @@
import { queryParams, type RouteQueryOptions, type RouteDefinition, type RouteFormDefinition } from './../../../../../wayfinder'
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::create
-* @see app/Http/Controllers/Forms/MembershipFormController.php:23
+* @see app/Http/Controllers/Forms/MembershipFormController.php:21
* @route '/membership'
*/
export const create = (options?: RouteQueryOptions): RouteDefinition<'get'> => ({
@@ -16,7 +16,7 @@ create.definition = {
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::create
-* @see app/Http/Controllers/Forms/MembershipFormController.php:23
+* @see app/Http/Controllers/Forms/MembershipFormController.php:21
* @route '/membership'
*/
create.url = (options?: RouteQueryOptions) => {
@@ -25,7 +25,7 @@ create.url = (options?: RouteQueryOptions) => {
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::create
-* @see app/Http/Controllers/Forms/MembershipFormController.php:23
+* @see app/Http/Controllers/Forms/MembershipFormController.php:21
* @route '/membership'
*/
create.get = (options?: RouteQueryOptions): RouteDefinition<'get'> => ({
@@ -35,7 +35,7 @@ create.get = (options?: RouteQueryOptions): RouteDefinition<'get'> => ({
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::create
-* @see app/Http/Controllers/Forms/MembershipFormController.php:23
+* @see app/Http/Controllers/Forms/MembershipFormController.php:21
* @route '/membership'
*/
create.head = (options?: RouteQueryOptions): RouteDefinition<'head'> => ({
@@ -45,7 +45,7 @@ create.head = (options?: RouteQueryOptions): RouteDefinition<'head'> => ({
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::create
-* @see app/Http/Controllers/Forms/MembershipFormController.php:23
+* @see app/Http/Controllers/Forms/MembershipFormController.php:21
* @route '/membership'
*/
const createForm = (options?: RouteQueryOptions): RouteFormDefinition<'get'> => ({
@@ -55,7 +55,7 @@ const createForm = (options?: RouteQueryOptions): RouteFormDefinition<'get'> =>
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::create
-* @see app/Http/Controllers/Forms/MembershipFormController.php:23
+* @see app/Http/Controllers/Forms/MembershipFormController.php:21
* @route '/membership'
*/
createForm.get = (options?: RouteQueryOptions): RouteFormDefinition<'get'> => ({
@@ -65,7 +65,7 @@ createForm.get = (options?: RouteQueryOptions): RouteFormDefinition<'get'> => ({
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::create
-* @see app/Http/Controllers/Forms/MembershipFormController.php:23
+* @see app/Http/Controllers/Forms/MembershipFormController.php:21
* @route '/membership'
*/
createForm.head = (options?: RouteQueryOptions): RouteFormDefinition<'get'> => ({
@@ -82,7 +82,7 @@ create.form = createForm
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::store
-* @see app/Http/Controllers/Forms/MembershipFormController.php:37
+* @see app/Http/Controllers/Forms/MembershipFormController.php:35
* @route '/membership'
*/
export const store = (options?: RouteQueryOptions): RouteDefinition<'post'> => ({
@@ -97,7 +97,7 @@ store.definition = {
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::store
-* @see app/Http/Controllers/Forms/MembershipFormController.php:37
+* @see app/Http/Controllers/Forms/MembershipFormController.php:35
* @route '/membership'
*/
store.url = (options?: RouteQueryOptions) => {
@@ -106,7 +106,7 @@ store.url = (options?: RouteQueryOptions) => {
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::store
-* @see app/Http/Controllers/Forms/MembershipFormController.php:37
+* @see app/Http/Controllers/Forms/MembershipFormController.php:35
* @route '/membership'
*/
store.post = (options?: RouteQueryOptions): RouteDefinition<'post'> => ({
@@ -116,7 +116,7 @@ store.post = (options?: RouteQueryOptions): RouteDefinition<'post'> => ({
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::store
-* @see app/Http/Controllers/Forms/MembershipFormController.php:37
+* @see app/Http/Controllers/Forms/MembershipFormController.php:35
* @route '/membership'
*/
const storeForm = (options?: RouteQueryOptions): RouteFormDefinition<'post'> => ({
@@ -126,7 +126,7 @@ const storeForm = (options?: RouteQueryOptions): RouteFormDefinition<'post'> =>
/**
* @see \App\Http\Controllers\Forms\MembershipFormController::store
-* @see app/Http/Controllers/Forms/MembershipFormController.php:37
+* @see app/Http/Controllers/Forms/MembershipFormController.php:35
* @route '/membership'
*/
storeForm.post = (options?: RouteQueryOptions): RouteFormDefinition<'post'> => ({
diff --git a/resources/js/components/flash-message.tsx b/resources/js/components/flash-message.tsx
new file mode 100644
index 0000000..152e857
--- /dev/null
+++ b/resources/js/components/flash-message.tsx
@@ -0,0 +1,41 @@
+import {FlashMessages} from '@/types';
+import {Alert, AlertDescription} from '@/components/ui/alert';
+import {CheckCircle2, AlertCircle, AlertTriangle, Info} from 'lucide-react';
+
+interface FlashMessageProps {
+ messages: FlashMessages;
+}
+
+export function FlashMessage({messages}: FlashMessageProps) {
+ if (!messages || Object.keys(messages).length === 0) return null;
+
+ return (
+
+ {messages.success && (
+
+
+ {messages.success}
+
+ )}
+ {messages.error && (
+
+
+ {messages.error}
+
+ )}
+ {messages.warning && (
+
+
+ {messages.warning}
+
+ )}
+ {messages.info && (
+
+
+ {messages.info}
+
+ )}
+
+ );
+}
+
diff --git a/resources/js/pages/forms/contact.tsx b/resources/js/pages/forms/contact.tsx
index 831f267..47dcff1 100644
--- a/resources/js/pages/forms/contact.tsx
+++ b/resources/js/pages/forms/contact.tsx
@@ -1,7 +1,5 @@
import {useEffect, useState} from "react";
import {Form, Head, usePage} from "@inertiajs/react";
-import {Alert, AlertDescription, AlertTitle} from "@/components/ui/alert";
-import {CheckCircle2} from "lucide-react";
import {LoaderCircle} from 'lucide-react';
import ContactFormController from "@/actions/App/Http/Controllers/Forms/ContactFormController";
import {Label} from "@/components/ui/label";
@@ -19,28 +17,31 @@ import {
} from "@/components/ui/select";
import {Textarea} from "@/components/ui/textarea";
import NavGuestLayout from "@/layouts/nav-guest-layout";
+import {PageProps} from "@/types";
+import {FlashMessage} from "@/components/flash-message";
export default function Contact() {
- const {flash} = usePage().props;
+ const {flash} = usePage().props as PageProps;
- const [showSuccess, setShowSuccess] = useState(!!flash?.success);
+ const [showFlashMessage, setFlashMessage] = useState(!!flash);
useEffect(() => {
- if (flash?.success) {
- setShowSuccess(true);
- const timer = setTimeout(() => setShowSuccess(false), 5000);
+ if (flash) {
+ setFlashMessage(true);
+ const timer = setTimeout(() => setFlashMessage(false), 5000);
return () => clearTimeout(timer);
}
}, [flash]);
+
return (
<>
+ className="flex flex-col items-center bg-[#F5F5F5] p-6 text-[#1b1b18] lg:justify-center lg:p-8 dark:bg-[#0a0a0a]">
-
+
Nous contacter
@@ -48,15 +49,8 @@ export default function Contact() {
- {showSuccess && (
-
-
- Message envoyé !
- {flash.success}
-
-
- // Clean form
-
+ {showFlashMessage && (
+
)}