add: new button in admin & cabine

This commit is contained in:
2026-03-06 12:35:45 +01:00
parent 7c739f0a64
commit 0930950f5f
3 changed files with 147 additions and 3 deletions
+7
View File
@@ -130,6 +130,13 @@ export const getCommandItems = async (commandId: number) => {
};
};
export const deleteCommand = async (commandId: number) => {
const { data } = await apiClient.delete(
`${V2}/admin/protected/orders/${commandId}`,
);
return { success: true, message: data.message };
};
export const deleteCommandItem = async (commandId: number, itemId: number) => {
const { data } = await apiClient.delete(
`${V2}/admin/protected/orders/${commandId}/items/${itemId}`,
@@ -9,7 +9,7 @@ import {
StatusBar,
Alert,
} from "react-native";
import { useRoute, type RouteProp } from "@react-navigation/native";
import { useRoute, useNavigation, type RouteProp } from "@react-navigation/native";
import { Ionicons } from "@expo/vector-icons";
import MapView, { Marker, Polyline, PROVIDER_DEFAULT } from "react-native-maps";
import { spacing, fontSize, borderRadius } from "../../theme";
@@ -23,6 +23,7 @@ import {
notifyClientToDescend,
getDeliveryPersonDetails,
deleteCommandItem,
deleteCommand,
} from "../../api/api_admin";
import { geocodeAddress, calculateRoute } from "../../api/tomtom";
import type { RouteInfo, LatLng } from "../../api/tomtom";
@@ -41,10 +42,12 @@ const MAP_HEIGHT = 240;
export default function OrderDetailScreen() {
const { colors } = useTheme();
const route = useRoute<Route>();
const navigation = useNavigation();
const { orderId } = route.params;
const [command, setCommand] = useState<any>(null);
const [items, setItems] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [showItemsModal, setShowItemsModal] = useState(false);
// Map / tracking
const mapRef = useRef<MapView | null>(null);
@@ -218,6 +221,28 @@ export default function OrderDetailScreen() {
}
};
const handleDeleteCommand = () => {
Alert.alert(
"Supprimer la commande",
`Supprimer définitivement la commande #${orderId} ?`,
[
{ text: "Annuler", style: "cancel" },
{
text: "Supprimer",
style: "destructive",
onPress: async () => {
try {
await deleteCommand(orderId);
navigation.goBack();
} catch (e: any) {
showError("Erreur", e.message);
}
},
},
],
);
};
const styles = useMemo(
() =>
StyleSheet.create({
@@ -374,6 +399,37 @@ export default function OrderDetailScreen() {
marginTop: spacing.xs,
},
// Items modal
itemsModalOverlay: {
flex: 1,
backgroundColor: "rgba(0,0,0,0.6)",
justifyContent: "flex-end",
},
itemsModalContainer: {
backgroundColor: colors.bgPrimary,
borderTopLeftRadius: borderRadius.lg,
borderTopRightRadius: borderRadius.lg,
maxHeight: "75%",
padding: spacing.l,
},
itemsModalHeader: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: spacing.m,
},
itemsModalTitle: {
fontSize: fontSize.lg,
fontWeight: "700",
color: colors.textWhite,
},
itemsModalCard: {
backgroundColor: colors.bgCard,
borderRadius: borderRadius.sm,
padding: spacing.m,
marginBottom: spacing.s,
},
// Fullscreen
fullscreenContainer: {
flex: 1,
@@ -681,6 +737,12 @@ export default function OrderDetailScreen() {
{/* Actions */}
<Text style={styles.sectionTitle}>Actions</Text>
<View style={styles.actions}>
<Button
title="Voir les items"
onPress={() => setShowItemsModal(true)}
variant="secondary"
fullWidth
/>
{command.status !== "approved" &&
command.status !== "cancelled" && (
<Button
@@ -688,6 +750,7 @@ export default function OrderDetailScreen() {
onPress={handleValidate}
variant="success"
fullWidth
style={{ marginTop: spacing.s }}
/>
)}
{command.status === "pending" && (
@@ -717,16 +780,89 @@ export default function OrderDetailScreen() {
style={{ marginTop: spacing.s }}
/>
)}
{command.status === "livre" && (
{!["approved", "cancelled"].includes(command.status) && (
<Button
title="Confirmer la réception"
title="Confirmer la commande"
onPress={handleConfirmReception}
variant="primary"
fullWidth
style={{ marginTop: spacing.s }}
/>
)}
<Button
title="Supprimer la commande"
onPress={handleDeleteCommand}
variant="danger"
fullWidth
style={{ marginTop: spacing.s }}
/>
</View>
{/* Items modal */}
<Modal
visible={showItemsModal}
animationType="slide"
onRequestClose={() => setShowItemsModal(false)}
transparent
>
<View style={styles.itemsModalOverlay}>
<View style={styles.itemsModalContainer}>
<View style={styles.itemsModalHeader}>
<Text style={styles.itemsModalTitle}>
Articles ({items.length})
</Text>
<TouchableOpacity
style={styles.closeBtn}
onPress={() => setShowItemsModal(false)}
>
<Ionicons
name="close"
size={22}
color={colors.textWhite}
/>
</TouchableOpacity>
</View>
<ScrollView showsVerticalScrollIndicator={false}>
{items.map((item: any) => (
<View key={item.id} style={styles.itemsModalCard}>
<View style={styles.row}>
<Text style={[styles.itemName, { flex: 1 }]}>
{item.produit ?? item.product_name}
</Text>
<TouchableOpacity
style={styles.itemDeleteBtn}
onPress={() => {
setShowItemsModal(false);
handleDeleteItem(
item.id,
item.produit ?? item.product_name,
);
}}
>
<Ionicons
name="trash-outline"
size={18}
color={colors.danger}
/>
</TouchableOpacity>
</View>
<View style={styles.itemDetails}>
<Text style={styles.info}>
Quantité: {item.quantite}
</Text>
<Text style={styles.info}>
Prix: {item.prix?.toFixed(2)}
</Text>
</View>
</View>
))}
{items.length === 0 && (
<Text style={styles.empty}>Aucun article</Text>
)}
</ScrollView>
</View>
</View>
</Modal>
<AlertModal
visible={alert.visible}
type={alert.type}
@@ -213,6 +213,7 @@ export default function OrdersScreen() {
},
actions: {
flexDirection: "row",
flexWrap: "wrap",
gap: spacing.s,
marginTop: spacing.m,
},