chore: add corrige adresse

This commit is contained in:
2026-03-06 19:29:49 +01:00
parent 3c2083c393
commit 81907b04aa
12 changed files with 598 additions and 31 deletions
+8
View File
@@ -173,6 +173,14 @@ export const validateCommand = async (commandId: number) => {
return { success: true, message: data.message };
};
export const proposeAddressChangeAdmin = async (commandId: number, proposedAddress: string) => {
const { data } = await apiClient.post(
`${V2}/admin/protected/orders/${commandId}/propose-address`,
{ proposed_address: proposedAddress },
);
return { success: true, message: data.message };
};
export const notifyClientToDescend = async (commandId: number) => {
const { data } = await apiClient.post(
`${V2}/admin/protected/orders/${commandId}/notify-client`,
+8
View File
@@ -117,6 +117,14 @@ export const deleteCommand = async (commandId: number) => {
return { success: true, message: data.message };
};
export const proposeAddressChangeCabine = async (commandId: number, proposedAddress: string) => {
const { data } = await apiClient.post(
`${API}/commands/${commandId}/propose-address`,
{ proposed_address: proposedAddress },
);
return { success: true, message: data.message };
};
export const notifyClientToDescendCabine = async (commandId: number) => {
const { data } = await apiClient.post(
`${API}/commands/${commandId}/notify-client`,
@@ -7,6 +7,7 @@ import {
TouchableOpacity,
RefreshControl,
ScrollView,
TextInput,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
@@ -23,6 +24,7 @@ import {
confirmReceptionAdmin,
deleteCommand,
deleteCommandItem,
proposeAddressChangeAdmin,
} from "../../api/api_admin";
import type { CommandResponse } from "../../api/types";
import type { AdminStackParamList } from "../../navigation/types";
@@ -62,6 +64,12 @@ export default function OrdersScreen() {
}>({ visible: false, commandId: null });
const [livreurs, setLivreurs] = useState<any[]>([]);
const [addressModal, setAddressModal] = useState<{
visible: boolean;
commandId: number | null;
input: string;
}>({ visible: false, commandId: null, input: "" });
const [itemsModal, setItemsModal] = useState<{
visible: boolean;
commandId: number | null;
@@ -180,6 +188,17 @@ export default function OrdersScreen() {
);
};
const handleProposeAddress = async () => {
if (!addressModal.commandId || !addressModal.input.trim()) return;
try {
await proposeAddressChangeAdmin(addressModal.commandId, addressModal.input.trim());
setAddressModal({ visible: false, commandId: null, input: "" });
showSuccess("Proposition envoyée", "Le client a été notifié de la nouvelle adresse proposée");
} catch (e: any) {
showError("Erreur", e.message);
}
};
const handleDeleteItem = (commandId: number, itemId: number, itemName: string) => {
showConfirm(
"Supprimer l'article",
@@ -372,6 +391,28 @@ export default function OrdersScreen() {
padding: spacing.xs,
marginLeft: spacing.s,
},
addressInput: {
backgroundColor: colors.bgPrimary,
borderWidth: 1,
borderColor: colors.border,
borderRadius: borderRadius.sm,
color: colors.textWhite,
paddingHorizontal: spacing.m,
paddingVertical: spacing.m,
fontSize: fontSize.md,
marginBottom: spacing.m,
},
addressConfirmBtn: {
backgroundColor: colors.accent,
borderRadius: borderRadius.sm,
paddingVertical: spacing.m,
alignItems: "center",
},
addressConfirmText: {
color: colors.textWhite,
fontSize: fontSize.md,
fontWeight: "700",
},
}),
[colors],
);
@@ -394,6 +435,12 @@ export default function OrdersScreen() {
icon: "receipt-outline" as keyof typeof Ionicons.glyphMap,
onPress: () => { setOpenMenuId(null); openItems(item.id); },
},
{
label: "Proposer adresse",
icon: "location-outline" as keyof typeof Ionicons.glyphMap,
onPress: () => { setOpenMenuId(null); setAddressModal({ visible: true, commandId: item.id, input: "" }); },
condition: !isDone,
},
{
label: "Le client est là",
icon: "notifications-outline" as keyof typeof Ionicons.glyphMap,
@@ -649,6 +696,29 @@ export default function OrdersScreen() {
)}
</Modal>
{/* Modal proposition adresse */}
<Modal
visible={addressModal.visible}
onClose={() => setAddressModal({ visible: false, commandId: null, input: "" })}
title={`Proposer adresse — commande #${addressModal.commandId}`}
icon="location-outline"
>
<TextInput
style={styles.addressInput}
placeholder="Nouvelle adresse..."
placeholderTextColor={colors.textMuted}
value={addressModal.input}
onChangeText={(t) => setAddressModal((prev) => ({ ...prev, input: t }))}
multiline
/>
<TouchableOpacity
style={styles.addressConfirmBtn}
onPress={handleProposeAddress}
>
<Text style={styles.addressConfirmText}>Envoyer la proposition</Text>
</TouchableOpacity>
</Modal>
<AlertModal
visible={alert.visible}
type={alert.type}
@@ -7,6 +7,7 @@ import {
RefreshControl,
ScrollView,
TouchableOpacity,
TextInput,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { spacing, fontSize, borderRadius } from "../../theme";
@@ -20,6 +21,7 @@ import {
getCabineLivreursList,
assignDeliveryPersonByCabine,
resetClientPoints,
proposeAddressChangeCabine,
} from "../../api/api_cabine";
import type { CommandResponse } from "../../api/types";
import StatusBadge from "../../components/StatusBadge";
@@ -71,6 +73,11 @@ export default function OrdersScreen() {
visible: boolean;
commandId: number | null;
}>({ visible: false, commandId: null });
const [addressModal, setAddressModal] = useState<{
visible: boolean;
commandId: number | null;
input: string;
}>({ visible: false, commandId: null, input: "" });
const [livreurs, setLivreurs] = useState<{ id: number; username: string }[]>([]);
const loadData = useCallback(async () => {
@@ -148,6 +155,17 @@ export default function OrdersScreen() {
}
};
const handleProposeAddress = async () => {
if (!addressModal.commandId || !addressModal.input.trim()) return;
try {
await proposeAddressChangeCabine(addressModal.commandId, addressModal.input.trim());
setAddressModal({ visible: false, commandId: null, input: "" });
showSuccess("Proposition envoyée", "Le client a été notifié de la nouvelle adresse proposée");
} catch (e: any) {
showError("Erreur", e.message);
}
};
const handleResetPoints = (clientUsername: string) => {
setOpenMenuId(null);
showConfirm(
@@ -283,6 +301,28 @@ export default function OrdersScreen() {
color: colors.danger,
fontSize: fontSize.sm,
},
addressInput: {
backgroundColor: colors.bgPrimary,
borderWidth: 1,
borderColor: colors.border,
borderRadius: borderRadius.sm,
color: colors.textWhite,
paddingHorizontal: spacing.m,
paddingVertical: spacing.m,
fontSize: fontSize.md,
marginBottom: spacing.m,
},
addressConfirmBtn: {
backgroundColor: colors.accent,
borderRadius: borderRadius.sm,
paddingVertical: spacing.m,
alignItems: "center",
},
addressConfirmText: {
color: colors.textWhite,
fontSize: fontSize.md,
fontWeight: "700",
},
// Modal summary
modalSummary: {
backgroundColor: colors.bgCard,
@@ -396,6 +436,11 @@ export default function OrdersScreen() {
icon: "receipt-outline" as keyof typeof Ionicons.glyphMap,
onPress: () => openItems(item.id),
},
{
label: "Proposer adresse",
icon: "location-outline" as keyof typeof Ionicons.glyphMap,
onPress: () => { setOpenMenuId(null); setAddressModal({ visible: true, commandId: item.id, input: "" }); },
},
{
label: "Le client est là",
icon: "notifications-outline" as keyof typeof Ionicons.glyphMap,
@@ -622,6 +667,29 @@ export default function OrdersScreen() {
)}
</Modal>
{/* Modal proposition adresse */}
<Modal
visible={addressModal.visible}
onClose={() => setAddressModal({ visible: false, commandId: null, input: "" })}
title={`Proposer adresse — commande #${addressModal.commandId}`}
icon="location-outline"
>
<TextInput
style={styles.addressInput}
placeholder="Nouvelle adresse..."
placeholderTextColor={colors.textMuted}
value={addressModal.input}
onChangeText={(t) => setAddressModal((prev) => ({ ...prev, input: t }))}
multiline
/>
<TouchableOpacity
style={styles.addressConfirmBtn}
onPress={handleProposeAddress}
>
<Text style={styles.addressConfirmText}>Envoyer la proposition</Text>
</TouchableOpacity>
</Modal>
<AlertModal
visible={alert.visible}
type={alert.type}