add: new button in admin & cabine
This commit is contained in:
@@ -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) => {
|
export const deleteCommandItem = async (commandId: number, itemId: number) => {
|
||||||
const { data } = await apiClient.delete(
|
const { data } = await apiClient.delete(
|
||||||
`${V2}/admin/protected/orders/${commandId}/items/${itemId}`,
|
`${V2}/admin/protected/orders/${commandId}/items/${itemId}`,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
StatusBar,
|
StatusBar,
|
||||||
Alert,
|
Alert,
|
||||||
} from "react-native";
|
} 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 { Ionicons } from "@expo/vector-icons";
|
||||||
import MapView, { Marker, Polyline, PROVIDER_DEFAULT } from "react-native-maps";
|
import MapView, { Marker, Polyline, PROVIDER_DEFAULT } from "react-native-maps";
|
||||||
import { spacing, fontSize, borderRadius } from "../../theme";
|
import { spacing, fontSize, borderRadius } from "../../theme";
|
||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
notifyClientToDescend,
|
notifyClientToDescend,
|
||||||
getDeliveryPersonDetails,
|
getDeliveryPersonDetails,
|
||||||
deleteCommandItem,
|
deleteCommandItem,
|
||||||
|
deleteCommand,
|
||||||
} 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";
|
||||||
@@ -41,10 +42,12 @@ const MAP_HEIGHT = 240;
|
|||||||
export default function OrderDetailScreen() {
|
export default function OrderDetailScreen() {
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const route = useRoute<Route>();
|
const route = useRoute<Route>();
|
||||||
|
const navigation = useNavigation();
|
||||||
const { orderId } = route.params;
|
const { orderId } = route.params;
|
||||||
const [command, setCommand] = useState<any>(null);
|
const [command, setCommand] = useState<any>(null);
|
||||||
const [items, setItems] = useState<any[]>([]);
|
const [items, setItems] = useState<any[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [showItemsModal, setShowItemsModal] = useState(false);
|
||||||
|
|
||||||
// Map / tracking
|
// Map / tracking
|
||||||
const mapRef = useRef<MapView | null>(null);
|
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(
|
const styles = useMemo(
|
||||||
() =>
|
() =>
|
||||||
StyleSheet.create({
|
StyleSheet.create({
|
||||||
@@ -374,6 +399,37 @@ export default function OrderDetailScreen() {
|
|||||||
marginTop: spacing.xs,
|
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
|
// Fullscreen
|
||||||
fullscreenContainer: {
|
fullscreenContainer: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -681,6 +737,12 @@ export default function OrderDetailScreen() {
|
|||||||
{/* Actions */}
|
{/* Actions */}
|
||||||
<Text style={styles.sectionTitle}>Actions</Text>
|
<Text style={styles.sectionTitle}>Actions</Text>
|
||||||
<View style={styles.actions}>
|
<View style={styles.actions}>
|
||||||
|
<Button
|
||||||
|
title="Voir les items"
|
||||||
|
onPress={() => setShowItemsModal(true)}
|
||||||
|
variant="secondary"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
{command.status !== "approved" &&
|
{command.status !== "approved" &&
|
||||||
command.status !== "cancelled" && (
|
command.status !== "cancelled" && (
|
||||||
<Button
|
<Button
|
||||||
@@ -688,6 +750,7 @@ export default function OrderDetailScreen() {
|
|||||||
onPress={handleValidate}
|
onPress={handleValidate}
|
||||||
variant="success"
|
variant="success"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
style={{ marginTop: spacing.s }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{command.status === "pending" && (
|
{command.status === "pending" && (
|
||||||
@@ -717,16 +780,89 @@ export default function OrderDetailScreen() {
|
|||||||
style={{ marginTop: spacing.s }}
|
style={{ marginTop: spacing.s }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{command.status === "livre" && (
|
{!["approved", "cancelled"].includes(command.status) && (
|
||||||
<Button
|
<Button
|
||||||
title="Confirmer la réception"
|
title="Confirmer la commande"
|
||||||
onPress={handleConfirmReception}
|
onPress={handleConfirmReception}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
fullWidth
|
fullWidth
|
||||||
style={{ marginTop: spacing.s }}
|
style={{ marginTop: spacing.s }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<Button
|
||||||
|
title="Supprimer la commande"
|
||||||
|
onPress={handleDeleteCommand}
|
||||||
|
variant="danger"
|
||||||
|
fullWidth
|
||||||
|
style={{ marginTop: spacing.s }}
|
||||||
|
/>
|
||||||
</View>
|
</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
|
<AlertModal
|
||||||
visible={alert.visible}
|
visible={alert.visible}
|
||||||
type={alert.type}
|
type={alert.type}
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ export default function OrdersScreen() {
|
|||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
|
flexWrap: "wrap",
|
||||||
gap: spacing.s,
|
gap: spacing.s,
|
||||||
marginTop: spacing.m,
|
marginTop: spacing.m,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user