diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
index d4db61c..b83c6ae 100644
--- a/app/Http/Controllers/DashboardController.php
+++ b/app/Http/Controllers/DashboardController.php
@@ -23,7 +23,7 @@ class DashboardController extends Controller
->first();
return Inertia::render('dashboard', [
- 'member' => $member ? new MemberResource($member) : null,
+ 'member' => $member ? (new MemberResource($member))->resolve() : null,
]);
}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 452e6b6..2218be7 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -2,6 +2,7 @@
namespace App\Providers;
+use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
@@ -19,6 +20,7 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot(): void
{
- //
+ // Disable wrapping for all JSON responses
+ JsonResource::withoutWrapping();
}
}
diff --git a/resources/js/components/features/dashboard/NoMemberCard.tsx b/resources/js/components/features/dashboard/NoMemberCard.tsx
new file mode 100644
index 0000000..6122a62
--- /dev/null
+++ b/resources/js/components/features/dashboard/NoMemberCard.tsx
@@ -0,0 +1,18 @@
+import { KeyRound } from 'lucide-react';
+import { router } from '@inertiajs/react';
+import { Button } from '@/components/ui/button';
+
+export function NoMemberCard() {
+ return (
+
+
+
Pas encore membre ?
+
+ Votre compte n'est pas encore associé à une adhésion. Rejoignez l'association pour accéder aux services.
+
+
+
+ );
+}
diff --git a/resources/js/components/features/dashboard/ServiceCard.tsx b/resources/js/components/features/dashboard/ServiceCard.tsx
new file mode 100644
index 0000000..430950e
--- /dev/null
+++ b/resources/js/components/features/dashboard/ServiceCard.tsx
@@ -0,0 +1,115 @@
+import { useState } from 'react';
+import { Cloud, ExternalLink, Globe, Layers, Mail, Megaphone, Share2 } from 'lucide-react';
+import { Button } from '@/components/ui/button';
+import { cn } from '@/lib/utils';
+import { type DashboardService } from '@/types';
+
+const ACTIVATION_REQUESTED_KEY = 'service_activation_requested';
+
+function getRequestedServices(): string[] {
+ try {
+ return JSON.parse(localStorage.getItem(ACTIVATION_REQUESTED_KEY) ?? '[]');
+ } catch {
+ return [];
+ }
+}
+
+function markServiceRequested(identifier: string): void {
+ const current = getRequestedServices();
+ if (!current.includes(identifier)) {
+ localStorage.setItem(ACTIVATION_REQUESTED_KEY, JSON.stringify([...current, identifier]));
+ }
+}
+
+const iconMap: Record = {
+ envelope: Mail,
+ share: Share2,
+ cloud: Cloud,
+ megaphone: Megaphone,
+ 'globe-alt': Globe,
+};
+
+const colorSchemes = [
+ {
+ card: 'bg-secondary',
+ titleBg: 'bg-accent',
+ titleText: 'text-accent-foreground',
+ linkText: 'text-foreground',
+ iconText: 'text-foreground/10',
+ },
+ {
+ card: 'bg-primary',
+ titleBg: 'bg-white',
+ titleText: 'text-black',
+ linkText: 'text-foreground',
+ iconText: 'text-foreground/10',
+ },
+ {
+ card: 'bg-accent',
+ titleBg: 'bg-primary',
+ titleText: 'text-primary-foreground',
+ linkText: 'text-accent-foreground',
+ iconText: 'text-white/10',
+ },
+];
+
+interface Props {
+ service: DashboardService;
+ index: number;
+ onRequest: (identifier: string) => void;
+}
+
+export function ServiceCard({ service, index, onRequest }: Props) {
+ const [alreadyRequested, setAlreadyRequested] = useState(() =>
+ getRequestedServices().includes(service.identifier),
+ );
+
+ const scheme = colorSchemes[index % colorSchemes.length];
+ const Icon = iconMap[service.icon ?? ''] ?? Layers;
+
+ function handleRequest() {
+ markServiceRequested(service.identifier);
+ setAlreadyRequested(true);
+ onRequest(service.identifier);
+ }
+
+ return (
+
+
+
+
+ {service.name}
+
+
+ {service.description && (
+
{service.description}
+ )}
+
+ {service.is_active ? (
+
+ Accéder au service
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+ );
+}
diff --git a/resources/js/components/features/dashboard/ServicesSection.tsx b/resources/js/components/features/dashboard/ServicesSection.tsx
new file mode 100644
index 0000000..399c779
--- /dev/null
+++ b/resources/js/components/features/dashboard/ServicesSection.tsx
@@ -0,0 +1,32 @@
+import { Loader2 } from 'lucide-react';
+import { type DashboardService } from '@/types';
+import { ServiceCard } from './ServiceCard';
+
+interface Props {
+ services: DashboardService[];
+ submitting: boolean;
+ onRequest: (identifier: string) => void;
+}
+
+export function ServicesSection({ services, submitting, onRequest }: Props) {
+ return (
+
+
Vos services
+ {submitting && (
+
+ Envoi en cours…
+
+ )}
+
+ {services.map((service, index) => (
+
+ ))}
+
+
+ );
+}
diff --git a/resources/js/components/features/dashboard/WelcomeCard.tsx b/resources/js/components/features/dashboard/WelcomeCard.tsx
new file mode 100644
index 0000000..1279ac2
--- /dev/null
+++ b/resources/js/components/features/dashboard/WelcomeCard.tsx
@@ -0,0 +1,51 @@
+import { type DashboardMember } from '@/types';
+import { cn } from '@/lib/utils';
+
+interface Props {
+ member: DashboardMember;
+}
+
+export function WelcomeCard({ member }: Props) {
+ const membership = member.membership;
+
+ return (
+ <>
+
+
+ Bienvenue sur votre espace Retzien, {member.firstname}
+
+
+
+
+ {member.firstname} {member.lastname}
+
+
{member.retzien_email || member.email}
+
+ {membership ? (
+
+
+ {membership.package?.name ?? 'Adhésion'}
+
+
+ {membership.status === 'active' ? 'Actif' : 'En attente'}
+
+ {membership.end_date && (
+
+ Valide jusqu'au {new Date(membership.end_date).toLocaleDateString('fr-FR')}
+
+ )}
+
+ ) : (
+
Aucune adhésion active.
+ )}
+
+ >
+ );
+}
diff --git a/resources/js/pages/dashboard.tsx b/resources/js/pages/dashboard.tsx
index 7d2fb27..563c6f5 100644
--- a/resources/js/pages/dashboard.tsx
+++ b/resources/js/pages/dashboard.tsx
@@ -1,12 +1,12 @@
import AppLayout from '@/layouts/app-layout';
-import { type BreadcrumbItem, type DashboardMember, type DashboardService, type PageProps } from '@/types';
+import { type BreadcrumbItem, type PageProps } from '@/types';
import { Head, router, usePage } from '@inertiajs/react';
-import DashboardController from '@/actions/App/Http/Controllers/DashboardController';
-import { ExternalLink, KeyRound, Loader2 } from 'lucide-react';
-import { Button } from '@/components/ui/button';
-import { FlashMessage } from '@/components/flash-message';
import { useEffect, useState } from 'react';
-import { cn } from '@/lib/utils';
+import DashboardController from '@/actions/App/Http/Controllers/DashboardController';
+import { FlashMessage } from '@/components/flash-message';
+import { WelcomeCard } from '@/components/features/dashboard/WelcomeCard';
+import { NoMemberCard } from '@/components/features/dashboard/NoMemberCard';
+import { ServicesSection } from '@/components/features/dashboard/ServicesSection';
const breadcrumbs: BreadcrumbItem[] = [
{
@@ -15,132 +15,6 @@ const breadcrumbs: BreadcrumbItem[] = [
},
];
-const ACTIVATION_REQUESTED_KEY = 'service_activation_requested';
-
-function getRequestedServices(): string[] {
- try {
- return JSON.parse(localStorage.getItem(ACTIVATION_REQUESTED_KEY) ?? '[]');
- } catch {
- return [];
- }
-}
-
-function markServiceRequested(identifier: string): void {
- const current = getRequestedServices();
- if (!current.includes(identifier)) {
- localStorage.setItem(ACTIVATION_REQUESTED_KEY, JSON.stringify([...current, identifier]));
- }
-}
-
-function WelcomeCard({ member }: { member: DashboardMember }) {
- const membership = member.membership;
-
- return (
-
-
Bienvenue
-
- {member.firstname} {member.lastname}
-
-
{member.retzien_email || member.email}
-
- {membership ? (
-
-
- {membership.package?.name ?? 'Adhésion'}
-
-
- {membership.status === 'active' ? 'Actif' : 'En attente'}
-
- {membership.end_date && (
-
- Valide jusqu'au {new Date(membership.end_date).toLocaleDateString('fr-FR')}
-
- )}
-
- ) : (
-
Aucune adhésion active.
- )}
-
- );
-}
-
-function NoMemberCard() {
- return (
-
-
-
Pas encore membre ?
-
- Votre compte n'est pas encore associé à une adhésion. Rejoignez l'association pour accéder aux services.
-
-
-
- );
-}
-
-function ServiceCard({ service, onRequest }: { service: DashboardService; onRequest: (identifier: string) => void }) {
- const [alreadyRequested, setAlreadyRequested] = useState(() =>
- getRequestedServices().includes(service.identifier),
- );
-
- function handleRequest() {
- markServiceRequested(service.identifier);
- setAlreadyRequested(true);
- onRequest(service.identifier);
- }
-
- return (
-
-
-
-
{service.name}
- {service.description && (
-
{service.description}
- )}
-
-
- {service.is_active ? 'Actif' : 'Inactif'}
-
-
-
- {service.is_active ? (
-
- Accéder au service
-
- ) : (
-
- )}
-
- );
-}
-
export default function Dashboard() {
const { flash, member } = usePage().props;
const [showFlash, setShowFlash] = useState(!!flash);
@@ -181,23 +55,11 @@ export default function Dashboard() {
{services.length > 0 && (
-
-
Vos services
- {submitting && (
-
- Envoi en cours…
-
- )}
-
- {services.map((service) => (
-
- ))}
-
-
+
)}
{services.length === 0 && membership && (
diff --git a/routes/dev-routes.php b/routes/dev-routes.php
index 966ae09..2b1351b 100644
--- a/routes/dev-routes.php
+++ b/routes/dev-routes.php
@@ -30,8 +30,6 @@ Route::get('/test-dolibarr', function () {
});
*/
-
-
// Test ISPConfig
/*Route::get('/test/sync-ispconfig', function () {
@@ -54,3 +52,4 @@ Route::get('/test/isp-mails', function() {
return $ispService->getAllMailDomains();
});*/
+// Test info user on Front