chore: add view reason of client
This commit is contained in:
@@ -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
|
||||
// ============================================
|
||||
|
||||
@@ -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() {
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<TouchableOpacity
|
||||
style={styles.editIconBtn}
|
||||
onPress={() => openCancelledOrders(item.clientData!)}
|
||||
>
|
||||
<Ionicons
|
||||
name="ban-outline"
|
||||
size={20}
|
||||
color={colors.danger}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.editIconBtn}
|
||||
onPress={() => openEditClient(item.clientData!)}
|
||||
@@ -1178,6 +1209,67 @@ export default function UsersScreen() {
|
||||
cancelText={alert.cancelText}
|
||||
/>
|
||||
|
||||
{/* Modal commandes annulées */}
|
||||
<Modal
|
||||
visible={cancelledModal.visible}
|
||||
onClose={() => setCancelledModal((prev) => ({ ...prev, visible: false }))}
|
||||
title={`Annulations — ${cancelledModal.username}`}
|
||||
icon="ban-outline"
|
||||
iconColor={colors.danger}
|
||||
>
|
||||
{cancelledModal.loading ? (
|
||||
<ActivityIndicator color={colors.danger} style={{ marginVertical: spacing.xl }} />
|
||||
) : cancelledModal.orders.length === 0 ? (
|
||||
<Text style={{ color: colors.textMuted, textAlign: "center", paddingVertical: spacing.xl }}>
|
||||
Aucune commande annulée
|
||||
</Text>
|
||||
) : (
|
||||
<ScrollView style={{ maxHeight: 400 }} showsVerticalScrollIndicator={false}>
|
||||
{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 (
|
||||
<View
|
||||
key={order.id}
|
||||
style={{
|
||||
borderBottomWidth: idx < cancelledModal.orders.length - 1 ? 1 : 0,
|
||||
borderBottomColor: colors.border,
|
||||
paddingVertical: spacing.m,
|
||||
gap: spacing.xs,
|
||||
}}
|
||||
>
|
||||
<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<Text style={{ color: colors.textWhite, fontWeight: "700", fontSize: fontSize.sm }}>
|
||||
Commande #{order.id}
|
||||
</Text>
|
||||
<Text style={{ color: colors.textMuted, fontSize: fontSize.xs }}>{date}</Text>
|
||||
</View>
|
||||
<View style={{ flexDirection: "row", justifyContent: "space-between" }}>
|
||||
<Text style={{ color: colors.textMuted, fontSize: fontSize.xs }}>
|
||||
{order.items_count} article{order.items_count > 1 ? "s" : ""}
|
||||
</Text>
|
||||
<Text style={{ color: colors.danger, fontSize: fontSize.sm, fontWeight: "600" }}>
|
||||
{Number(order.total_prix).toFixed(2)} €
|
||||
</Text>
|
||||
</View>
|
||||
{reason ? (
|
||||
<Text style={{ color: colors.warning, fontSize: fontSize.xs, fontStyle: "italic" }}>
|
||||
Raison : {reason}
|
||||
</Text>
|
||||
) : (
|
||||
<Text style={{ color: colors.textMuted, fontSize: fontSize.xs, fontStyle: "italic" }}>
|
||||
Aucune raison fournie
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</ScrollView>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
{/* Modal crédit parrainage */}
|
||||
<Modal
|
||||
visible={referralModal.visible}
|
||||
|
||||
Reference in New Issue
Block a user