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