diff --git a/frontend-admin/src/api/api_admin.ts b/frontend-admin/src/api/api_admin.ts
index 93ccd1d2..e250b7cb 100644
--- a/frontend-admin/src/api/api_admin.ts
+++ b/frontend-admin/src/api/api_admin.ts
@@ -509,6 +509,38 @@ export const getClientReferralAdmin = async (
}
};
+export interface CancelledOrder {
+ id: number;
+ username: string;
+ total_prix: number;
+ created_at: string;
+ updated_at: string;
+ items_count: number;
+ cancel_reason: string;
+ cancellation?: {
+ cancelled_at: string;
+ cancelled_by: string;
+ reason: string;
+ };
+}
+
+export const getClientCancelledOrders = async (
+ username: string,
+): Promise<{ success: boolean; orders: CancelledOrder[] }> => {
+ try {
+ const { data } = await apiClient.get(
+ `${V2}/admin/protected/orders/cancelled`,
+ { params: { username } },
+ );
+ return {
+ success: true,
+ orders: data.data?.cancelled_orders ?? [],
+ };
+ } catch {
+ return { success: false, orders: [] };
+ }
+};
+
// ============================================
// ALERTES
// ============================================
diff --git a/frontend-admin/src/screens/admin/UsersScreen.tsx b/frontend-admin/src/screens/admin/UsersScreen.tsx
index 65601b3d..b661b87f 100644
--- a/frontend-admin/src/screens/admin/UsersScreen.tsx
+++ b/frontend-admin/src/screens/admin/UsersScreen.tsx
@@ -4,9 +4,11 @@ import {
Text,
StyleSheet,
FlatList,
+ ScrollView,
RefreshControl,
TouchableOpacity,
TextInput as RNTextInput,
+ ActivityIndicator,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { spacing, fontSize, borderRadius } from "../../theme";
@@ -21,8 +23,10 @@ import {
createClientByAdmin,
createUserByAdmin,
creditClientReferral,
+ getClientCancelledOrders,
getSettings,
} from "../../api/api_admin";
+import type { CancelledOrder } from "../../api/api_admin";
import type { ClientResponse } from "../../api/types";
import LoadingSpinner from "../../components/ui/LoadingSpinner";
import Card from "../../components/ui/Card";
@@ -176,6 +180,14 @@ export default function UsersScreen() {
const [referralAmount, setReferralAmount] = useState("");
const [referralLoading, setReferralLoading] = useState(false);
+ // Cancelled orders modal
+ const [cancelledModal, setCancelledModal] = useState<{
+ visible: boolean;
+ username: string;
+ orders: CancelledOrder[];
+ loading: boolean;
+ }>({ visible: false, username: "", orders: [], loading: false });
+
const { alert, showError, showConfirm, hideAlert } = useAlert();
// --------------------------------------------------
@@ -417,6 +429,15 @@ export default function UsersScreen() {
}
};
+ // --------------------------------------------------
+ // Cancelled orders
+ // --------------------------------------------------
+ const openCancelledOrders = async (client: ClientResponse) => {
+ setCancelledModal({ visible: true, username: client.username, orders: [], loading: true });
+ const res = await getClientCancelledOrders(client.username);
+ setCancelledModal((prev) => ({ ...prev, orders: res.orders, loading: false }));
+ };
+
// --------------------------------------------------
// Create user
// --------------------------------------------------
@@ -759,6 +780,16 @@ export default function UsersScreen() {
/>
)}
+ openCancelledOrders(item.clientData!)}
+ >
+
+
openEditClient(item.clientData!)}
@@ -1178,6 +1209,67 @@ export default function UsersScreen() {
cancelText={alert.cancelText}
/>
+ {/* Modal commandes annulées */}
+ setCancelledModal((prev) => ({ ...prev, visible: false }))}
+ title={`Annulations — ${cancelledModal.username}`}
+ icon="ban-outline"
+ iconColor={colors.danger}
+ >
+ {cancelledModal.loading ? (
+
+ ) : cancelledModal.orders.length === 0 ? (
+
+ Aucune commande annulée
+
+ ) : (
+
+ {cancelledModal.orders.map((order, idx) => {
+ const date = order.cancellation?.cancelled_at
+ ? new Date(order.cancellation.cancelled_at).toLocaleDateString("fr-FR", { day: "2-digit", month: "2-digit", year: "numeric" })
+ : new Date(order.updated_at).toLocaleDateString("fr-FR", { day: "2-digit", month: "2-digit", year: "numeric" });
+ const reason = order.cancel_reason || order.cancellation?.reason || "";
+ return (
+
+
+
+ Commande #{order.id}
+
+ {date}
+
+
+
+ {order.items_count} article{order.items_count > 1 ? "s" : ""}
+
+
+ {Number(order.total_prix).toFixed(2)} €
+
+
+ {reason ? (
+
+ Raison : {reason}
+
+ ) : (
+
+ Aucune raison fournie
+
+ )}
+
+ );
+ })}
+
+ )}
+
+
{/* Modal crédit parrainage */}