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
|
// ALERTES
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
FlatList,
|
FlatList,
|
||||||
|
ScrollView,
|
||||||
RefreshControl,
|
RefreshControl,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
TextInput as RNTextInput,
|
TextInput as RNTextInput,
|
||||||
|
ActivityIndicator,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { spacing, fontSize, borderRadius } from "../../theme";
|
import { spacing, fontSize, borderRadius } from "../../theme";
|
||||||
@@ -21,8 +23,10 @@ import {
|
|||||||
createClientByAdmin,
|
createClientByAdmin,
|
||||||
createUserByAdmin,
|
createUserByAdmin,
|
||||||
creditClientReferral,
|
creditClientReferral,
|
||||||
|
getClientCancelledOrders,
|
||||||
getSettings,
|
getSettings,
|
||||||
} from "../../api/api_admin";
|
} from "../../api/api_admin";
|
||||||
|
import type { CancelledOrder } from "../../api/api_admin";
|
||||||
import type { ClientResponse } from "../../api/types";
|
import type { ClientResponse } from "../../api/types";
|
||||||
import LoadingSpinner from "../../components/ui/LoadingSpinner";
|
import LoadingSpinner from "../../components/ui/LoadingSpinner";
|
||||||
import Card from "../../components/ui/Card";
|
import Card from "../../components/ui/Card";
|
||||||
@@ -176,6 +180,14 @@ export default function UsersScreen() {
|
|||||||
const [referralAmount, setReferralAmount] = useState("");
|
const [referralAmount, setReferralAmount] = useState("");
|
||||||
const [referralLoading, setReferralLoading] = useState(false);
|
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();
|
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
|
// Create user
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
@@ -759,6 +780,16 @@ export default function UsersScreen() {
|
|||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.editIconBtn}
|
||||||
|
onPress={() => openCancelledOrders(item.clientData!)}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name="ban-outline"
|
||||||
|
size={20}
|
||||||
|
color={colors.danger}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.editIconBtn}
|
style={styles.editIconBtn}
|
||||||
onPress={() => openEditClient(item.clientData!)}
|
onPress={() => openEditClient(item.clientData!)}
|
||||||
@@ -1178,6 +1209,67 @@ export default function UsersScreen() {
|
|||||||
cancelText={alert.cancelText}
|
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 crédit parrainage */}
|
||||||
<Modal
|
<Modal
|
||||||
visible={referralModal.visible}
|
visible={referralModal.visible}
|
||||||
|
|||||||
Reference in New Issue
Block a user