diff --git a/app/admin/clients/page.tsx b/app/admin/clients/page.tsx
index b321ab7..36fa5b6 100644
--- a/app/admin/clients/page.tsx
+++ b/app/admin/clients/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useEffect, useCallback } from "react";
+import { useState, useEffect, useCallback, startTransition } from "react";
import { Card } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@@ -34,7 +34,7 @@ export default function AdminClients() {
}
}, [query]);
- useEffect(() => { load(); }, [load]);
+ useEffect(() => { startTransition(() => load()); }, [load]);
const handleSearch = (e: React.FormEvent) => {
e.preventDefault();
diff --git a/app/admin/commandes/page.tsx b/app/admin/commandes/page.tsx
index 8d0e5f7..1a79da9 100644
--- a/app/admin/commandes/page.tsx
+++ b/app/admin/commandes/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useEffect, useCallback } from "react";
+import { useState, useEffect, useCallback, startTransition } from "react";
import { Card } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@@ -56,7 +56,7 @@ export default function AdminCommandes() {
}
}, [filter]);
- useEffect(() => { load(); }, [load]);
+ useEffect(() => { startTransition(() => load()); }, [load]);
const handleStatus = async (id: string, status: string) => {
setUpdating(id);
diff --git a/app/admin/page.tsx b/app/admin/page.tsx
index f137c03..646dee9 100644
--- a/app/admin/page.tsx
+++ b/app/admin/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useState, startTransition } from "react";
import { Package, CalendarCheck, Clock, TrendingUp, ShoppingBag, Users, AlertTriangle, Euro } from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
@@ -8,6 +8,41 @@ import { useAdmin } from "@/contexts/AdminContext";
import { useLanguage } from "@/contexts/LanguageContext";
import { getDashboardStats, DashboardStats } from "@/lib/api/admin";
+function Skeleton() {
+ return (
+
+ {Array.from({ length: 4 }).map((_, i) => (
+
+
+
+
+
+
+ ))}
+
+ );
+}
+
+function StatGrid({ cards }: { cards: { label: string; value: string | number; icon: React.ElementType; color: string; bg: string }[] }) {
+ return (
+
+ {cards.map((s) => (
+
+
+
+
{s.label}
+
{s.value}
+
+
+
+
+
+
+ ))}
+
+ );
+}
+
export default function AdminOverview() {
const { reservations } = useAdmin();
const { t, locale } = useLanguage();
@@ -40,37 +75,6 @@ export default function AdminOverview() {
]
: [];
- const Skeleton = () => (
-
- {Array.from({ length: 4 }).map((_, i) => (
-
-
-
-
-
-
- ))}
-
- );
-
- const StatGrid = ({ cards }: { cards: { label: string; value: string | number; icon: React.ElementType; color: string; bg: string }[] }) => (
-
- {cards.map((s) => (
-
-
-
-
{s.label}
-
{s.value}
-
-
-
-
-
-
- ))}
-
- );
-
return (
diff --git a/app/admin/planning/page.tsx b/app/admin/planning/page.tsx
index 3ad6145..7c6af30 100644
--- a/app/admin/planning/page.tsx
+++ b/app/admin/planning/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useEffect, useCallback } from "react";
+import { useState, useEffect, useCallback, startTransition } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@@ -263,7 +263,7 @@ function CalendarTab() {
.finally(() => setLoadingSlots(false));
}, [year, month]);
- useEffect(() => { loadSlots(); }, [loadSlots]);
+ useEffect(() => { startTransition(() => loadSlots()); }, [loadSlots]);
const prevMonth = () => {
if (month === 0) { setYear((y) => y - 1); setMonth(11); }
diff --git a/app/admin/services/page.tsx b/app/admin/services/page.tsx
index fd3a482..d32e754 100644
--- a/app/admin/services/page.tsx
+++ b/app/admin/services/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useEffect } from "react";
+import { useState, useEffect, startTransition } from "react";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@@ -54,7 +54,7 @@ export default function AdminServices() {
}
};
- useEffect(() => { load(); }, []);
+ useEffect(() => { startTransition(() => load()); }, []);
const openCreate = () => {
setEditing(null);
diff --git a/app/boutique/page.tsx b/app/boutique/page.tsx
index e930236..b23d8fc 100644
--- a/app/boutique/page.tsx
+++ b/app/boutique/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { Suspense, useState, useEffect } from "react";
+import { Suspense, useState, useEffect, startTransition } from "react";
import { useLanguage } from "@/contexts/LanguageContext";
import { useSearchParams, useRouter } from "next/navigation";
import { categories } from "@/data/products";
@@ -21,7 +21,7 @@ function ShopContent() {
};
useEffect(() => {
- setLoading(true);
+ startTransition(() => setLoading(true));
listProducts({
per_page: 100,
category: selectedCategory === "all" ? undefined : selectedCategory,
diff --git a/app/mon-compte/page.tsx b/app/mon-compte/page.tsx
index f0401c9..855f44d 100644
--- a/app/mon-compte/page.tsx
+++ b/app/mon-compte/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useEffect } from "react";
+import { useState, useEffect, startTransition } from "react";
import { useRouter } from "next/navigation";
import { useAuth } from "@/contexts/AuthContext";
import { useLanguage } from "@/contexts/LanguageContext";
@@ -40,8 +40,10 @@ export default function MonCompte() {
useEffect(() => {
if (user) {
- setName(user.full_name ?? "");
- setPhone(user.phone ?? "");
+ startTransition(() => {
+ setName(user.full_name ?? "");
+ setPhone(user.phone ?? "");
+ });
}
}, [user]);
diff --git a/app/produit/[id]/page.tsx b/app/produit/[id]/page.tsx
index 7a4b3cf..e4b771b 100644
--- a/app/produit/[id]/page.tsx
+++ b/app/produit/[id]/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useEffect } from "react";
+import { useState, useEffect, startTransition } from "react";
import { Star, ChevronLeft, Check } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useLanguage } from "@/contexts/LanguageContext";
@@ -26,7 +26,7 @@ export default function ProductDetail() {
useEffect(() => {
if (!id) return;
- setLoading(true);
+ startTransition(() => setLoading(true));
getProduct(id as string)
.then((p) => {
setProduct(p);
diff --git a/app/reservation/page.tsx b/app/reservation/page.tsx
index a2ba6a9..78f3fcb 100644
--- a/app/reservation/page.tsx
+++ b/app/reservation/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useEffect } from "react";
+import { useState, useEffect, startTransition } from "react";
import { Calendar } from "@/components/ui/calendar";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@@ -43,16 +43,20 @@ export default function Booking() {
useEffect(() => {
if (user) {
- setName(user.full_name ?? "");
- setEmail(user.email ?? "");
- setPhone(user.phone ?? "");
+ startTransition(() => {
+ setName(user.full_name ?? "");
+ setEmail(user.email ?? "");
+ setPhone(user.phone ?? "");
+ });
}
}, [user]);
useEffect(() => {
if (!selectedDate) return;
- setSlotsLoading(true);
- setSelectedSlot(null);
+ startTransition(() => {
+ setSlotsLoading(true);
+ setSelectedSlot(null);
+ });
const dateStr = toDateStr(selectedDate);
getAvailableSlots(dateStr, dateStr)
.then(setSlots)
diff --git a/contexts/AdminContext.tsx b/contexts/AdminContext.tsx
index 25952ed..52c4c53 100644
--- a/contexts/AdminContext.tsx
+++ b/contexts/AdminContext.tsx
@@ -1,6 +1,6 @@
"use client";
-import React, { useContext, useState, useEffect, ReactNode, createContext } from "react";
+import React, { useContext, useState, useEffect, startTransition, ReactNode, createContext } from "react";
import { useAuth } from "@/contexts/AuthContext";
import * as productsApi from "@/lib/api/products";
import * as bookingsApi from "@/lib/api/bookings";
@@ -82,8 +82,10 @@ export const AdminProvider = ({ children }: { children: ReactNode }) => {
useEffect(() => {
if (isAdmin) {
- refreshProducts();
- refreshReservations();
+ startTransition(() => {
+ refreshProducts();
+ refreshReservations();
+ });
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isAdmin]);
diff --git a/contexts/AuthContext.tsx b/contexts/AuthContext.tsx
index 54a4857..688b220 100644
--- a/contexts/AuthContext.tsx
+++ b/contexts/AuthContext.tsx
@@ -1,6 +1,6 @@
"use client";
-import React, { createContext, useContext, useState, useEffect, ReactNode } from "react";
+import React, { createContext, useContext, useState, useEffect, startTransition, ReactNode } from "react";
import { getToken } from "@/lib/api";
import * as authApi from "@/lib/api/auth";
@@ -24,7 +24,7 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
useEffect(() => {
const token = getToken();
if (!token) {
- setIsLoading(false);
+ startTransition(() => setIsLoading(false));
return;
}
authApi.getMe()
diff --git a/hooks/use-mobile.ts b/hooks/use-mobile.ts
index 2b0fe1d..cd560f3 100644
--- a/hooks/use-mobile.ts
+++ b/hooks/use-mobile.ts
@@ -11,7 +11,7 @@ export function useIsMobile() {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
}
mql.addEventListener("change", onChange)
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
+ React.startTransition(() => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT))
return () => mql.removeEventListener("change", onChange)
}, [])