chore: add new features cabine & admin
This commit is contained in:
@@ -119,7 +119,7 @@ export const getCommandByID = async (commandId: number) => {
|
|||||||
|
|
||||||
export const getCommandItems = async (commandId: number) => {
|
export const getCommandItems = async (commandId: number) => {
|
||||||
const { data } = await apiClient.get(
|
const { data } = await apiClient.get(
|
||||||
`${CABINE_URL}/commands/${commandId}/items`,
|
`${V2}/admin/protected/orders/${commandId}/items`,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
@@ -130,6 +130,13 @@ export const getCommandItems = async (commandId: number) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const deleteCommandItem = async (commandId: number, itemId: number) => {
|
||||||
|
const { data } = await apiClient.delete(
|
||||||
|
`${V2}/admin/protected/orders/${commandId}/items/${itemId}`,
|
||||||
|
);
|
||||||
|
return { success: true, message: data.message };
|
||||||
|
};
|
||||||
|
|
||||||
export const updateCommandStatus = async (
|
export const updateCommandStatus = async (
|
||||||
commandId: number,
|
commandId: number,
|
||||||
newStatus: string,
|
newStatus: string,
|
||||||
@@ -159,6 +166,13 @@ export const validateCommand = async (commandId: number) => {
|
|||||||
return { success: true, message: data.message };
|
return { success: true, message: data.message };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const notifyClientToDescend = async (commandId: number) => {
|
||||||
|
const { data } = await apiClient.post(
|
||||||
|
`${V2}/admin/protected/orders/${commandId}/notify-client`,
|
||||||
|
);
|
||||||
|
return { success: true, message: data.message, client_username: data.client_username };
|
||||||
|
};
|
||||||
|
|
||||||
export const confirmReceptionAdmin = async (commandId: number) => {
|
export const confirmReceptionAdmin = async (commandId: number) => {
|
||||||
const { data } = await apiClient.post(
|
const { data } = await apiClient.post(
|
||||||
`${V2}/admin/protected/orders/${commandId}/confirm-reception`,
|
`${V2}/admin/protected/orders/${commandId}/confirm-reception`,
|
||||||
|
|||||||
@@ -117,6 +117,13 @@ export const deleteCommand = async (commandId: number) => {
|
|||||||
return { success: true, message: data.message };
|
return { success: true, message: data.message };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const notifyClientToDescendCabine = async (commandId: number) => {
|
||||||
|
const { data } = await apiClient.post(
|
||||||
|
`${API}/commands/${commandId}/notify-client`,
|
||||||
|
);
|
||||||
|
return { success: true, message: data.message, client_username: data.client_username };
|
||||||
|
};
|
||||||
|
|
||||||
export const getCabineLivreursList = async (): Promise<
|
export const getCabineLivreursList = async (): Promise<
|
||||||
{ id: number; username: string }[]
|
{ id: number; username: string }[]
|
||||||
> => {
|
> => {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ interface ButtonProps {
|
|||||||
| "secondary"
|
| "secondary"
|
||||||
| "danger"
|
| "danger"
|
||||||
| "success"
|
| "success"
|
||||||
|
| "warning"
|
||||||
| "outline"
|
| "outline"
|
||||||
| "ghost";
|
| "ghost";
|
||||||
size?: "sm" | "md" | "lg";
|
size?: "sm" | "md" | "lg";
|
||||||
@@ -46,6 +47,7 @@ export default function Button({
|
|||||||
secondary: colors.bgCard,
|
secondary: colors.bgCard,
|
||||||
danger: colors.danger,
|
danger: colors.danger,
|
||||||
success: colors.success,
|
success: colors.success,
|
||||||
|
warning: colors.warning,
|
||||||
outline: "transparent",
|
outline: "transparent",
|
||||||
ghost: "transparent",
|
ghost: "transparent",
|
||||||
}[variant];
|
}[variant];
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
Modal,
|
Modal,
|
||||||
StatusBar,
|
StatusBar,
|
||||||
|
Alert,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { useRoute, type RouteProp } from "@react-navigation/native";
|
import { useRoute, type RouteProp } from "@react-navigation/native";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
@@ -19,7 +20,9 @@ import {
|
|||||||
updateCommandStatus,
|
updateCommandStatus,
|
||||||
validateCommand,
|
validateCommand,
|
||||||
confirmReceptionAdmin,
|
confirmReceptionAdmin,
|
||||||
|
notifyClientToDescend,
|
||||||
getDeliveryPersonDetails,
|
getDeliveryPersonDetails,
|
||||||
|
deleteCommandItem,
|
||||||
} from "../../api/api_admin";
|
} from "../../api/api_admin";
|
||||||
import { geocodeAddress, calculateRoute } from "../../api/tomtom";
|
import { geocodeAddress, calculateRoute } from "../../api/tomtom";
|
||||||
import type { RouteInfo, LatLng } from "../../api/tomtom";
|
import type { RouteInfo, LatLng } from "../../api/tomtom";
|
||||||
@@ -167,6 +170,40 @@ export default function OrderDetailScreen() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleNotifyClient = async () => {
|
||||||
|
try {
|
||||||
|
await notifyClientToDescend(orderId);
|
||||||
|
showSuccess("Notification envoyée", "Le client a été prévenu de descendre");
|
||||||
|
} catch (e: any) {
|
||||||
|
showError("Erreur", e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteItem = (itemId: number, itemName: string) => {
|
||||||
|
Alert.alert(
|
||||||
|
"Supprimer l'article",
|
||||||
|
`Supprimer "${itemName}" de la commande ?`,
|
||||||
|
[
|
||||||
|
{ text: "Annuler", style: "cancel" },
|
||||||
|
{
|
||||||
|
text: "Supprimer",
|
||||||
|
style: "destructive",
|
||||||
|
onPress: async () => {
|
||||||
|
try {
|
||||||
|
await deleteCommandItem(orderId, itemId);
|
||||||
|
const itemsRes = await getCommandItems(orderId);
|
||||||
|
setItems(itemsRes.items);
|
||||||
|
const cmdRes = await getCommandByID(orderId);
|
||||||
|
setCommand(cmdRes.command);
|
||||||
|
} catch (e: any) {
|
||||||
|
showError("Erreur", e.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleConfirmReception = async () => {
|
const handleConfirmReception = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await confirmReceptionAdmin(orderId);
|
const res = await confirmReceptionAdmin(orderId);
|
||||||
@@ -222,6 +259,11 @@ export default function OrderDetailScreen() {
|
|||||||
itemDetails: {
|
itemDetails: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
itemDeleteBtn: {
|
||||||
|
padding: spacing.xs,
|
||||||
|
marginLeft: spacing.s,
|
||||||
},
|
},
|
||||||
actions: { marginTop: spacing.m, marginBottom: spacing.xxl },
|
actions: { marginTop: spacing.m, marginBottom: spacing.xxl },
|
||||||
empty: {
|
empty: {
|
||||||
@@ -605,7 +647,26 @@ export default function OrderDetailScreen() {
|
|||||||
<Text style={styles.sectionTitle}>Articles ({items.length})</Text>
|
<Text style={styles.sectionTitle}>Articles ({items.length})</Text>
|
||||||
{items.map((item: any) => (
|
{items.map((item: any) => (
|
||||||
<Card key={item.id} style={{ marginBottom: spacing.s }}>
|
<Card key={item.id} style={{ marginBottom: spacing.s }}>
|
||||||
<Text style={styles.itemName}>{item.product_name}</Text>
|
<View style={styles.row}>
|
||||||
|
<Text style={[styles.itemName, { flex: 1 }]}>
|
||||||
|
{item.produit ?? item.product_name}
|
||||||
|
</Text>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.itemDeleteBtn}
|
||||||
|
onPress={() =>
|
||||||
|
handleDeleteItem(
|
||||||
|
item.id,
|
||||||
|
item.produit ?? item.product_name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name="trash-outline"
|
||||||
|
size={18}
|
||||||
|
color={colors.danger}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
<View style={styles.itemDetails}>
|
<View style={styles.itemDetails}>
|
||||||
<Text style={styles.info}>
|
<Text style={styles.info}>
|
||||||
Quantité: {item.quantite}
|
Quantité: {item.quantite}
|
||||||
@@ -647,6 +708,15 @@ export default function OrderDetailScreen() {
|
|||||||
style={{ marginTop: spacing.s }}
|
style={{ marginTop: spacing.s }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{!["approved", "cancelled"].includes(command.status) && (
|
||||||
|
<Button
|
||||||
|
title="Le client est là"
|
||||||
|
onPress={handleNotifyClient}
|
||||||
|
variant="warning"
|
||||||
|
fullWidth
|
||||||
|
style={{ marginTop: spacing.s }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{command.status === "livre" && (
|
{command.status === "livre" && (
|
||||||
<Button
|
<Button
|
||||||
title="Confirmer la réception"
|
title="Confirmer la réception"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
getCommandItems,
|
getCommandItems,
|
||||||
deleteCommand,
|
deleteCommand,
|
||||||
confirmReceptionCabine,
|
confirmReceptionCabine,
|
||||||
|
notifyClientToDescendCabine,
|
||||||
getCabineLivreursList,
|
getCabineLivreursList,
|
||||||
assignDeliveryPersonByCabine,
|
assignDeliveryPersonByCabine,
|
||||||
} from "../../api/api_cabine";
|
} from "../../api/api_cabine";
|
||||||
@@ -51,7 +52,7 @@ export default function OrdersScreen() {
|
|||||||
const [commands, setCommands] = useState<CommandResponse[]>([]);
|
const [commands, setCommands] = useState<CommandResponse[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
const { alert, showError, showConfirm, hideAlert } = useAlert();
|
const { alert, showError, showSuccess, showConfirm, hideAlert } = useAlert();
|
||||||
const [itemsModal, setItemsModal] = useState<{
|
const [itemsModal, setItemsModal] = useState<{
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
commandId: number | null;
|
commandId: number | null;
|
||||||
@@ -135,6 +136,15 @@ export default function OrdersScreen() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleNotifyClient = async (commandId: number) => {
|
||||||
|
try {
|
||||||
|
await notifyClientToDescendCabine(commandId);
|
||||||
|
showSuccess("Notification envoyée", "Le client a été prévenu de descendre");
|
||||||
|
} catch (e: any) {
|
||||||
|
showError("Erreur", e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleDelete = (commandId: number) => {
|
const handleDelete = (commandId: number) => {
|
||||||
showConfirm(
|
showConfirm(
|
||||||
"Supprimer",
|
"Supprimer",
|
||||||
@@ -356,6 +366,12 @@ export default function OrdersScreen() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
title="Le client est là"
|
||||||
|
onPress={() => handleNotifyClient(item.id)}
|
||||||
|
size="sm"
|
||||||
|
variant="warning"
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
title="Assigner"
|
title="Assigner"
|
||||||
onPress={() => openAssignModal(item.id)}
|
onPress={() => openAssignModal(item.id)}
|
||||||
|
|||||||
Reference in New Issue
Block a user