chore: add ansible backend docker frontend-prep
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,363 @@
|
||||
export interface AdminLogin {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface ApiResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
access_token?: string;
|
||||
token_type?: string;
|
||||
expires_in?: number;
|
||||
user?: AdminResponse;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface AdminResponse {
|
||||
id: number;
|
||||
username: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Deliveryman Location Response
|
||||
*/
|
||||
export interface DeliverymanLocation {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
last_update: number;
|
||||
last_update_ago: number;
|
||||
is_recent: boolean;
|
||||
}
|
||||
|
||||
export interface DeliverymanInfo {
|
||||
username: string;
|
||||
status: string;
|
||||
current_command: number;
|
||||
queue_size: number;
|
||||
location: DeliverymanLocation;
|
||||
}
|
||||
|
||||
export interface CommandETA {
|
||||
minutes: number;
|
||||
has_eta: boolean;
|
||||
set_at: number;
|
||||
}
|
||||
|
||||
export interface DeliverymanLocationResponse {
|
||||
success: boolean;
|
||||
data?: {
|
||||
command_id: number;
|
||||
client: string;
|
||||
command_status: string;
|
||||
deliveryman: DeliverymanInfo;
|
||||
eta: CommandETA;
|
||||
};
|
||||
requested_by?: {
|
||||
username: string;
|
||||
role: string;
|
||||
};
|
||||
error?: string;
|
||||
message?: string;
|
||||
command_info?: {
|
||||
command_id: number;
|
||||
client: string;
|
||||
deliveryman?: string;
|
||||
status: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ProductPrice {
|
||||
id?: number;
|
||||
product_id?: number;
|
||||
quantity: number;
|
||||
price: number;
|
||||
created_at?: string;
|
||||
}
|
||||
|
||||
export interface Media {
|
||||
id?: number;
|
||||
product_id?: number;
|
||||
type: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
id?: number;
|
||||
name: string;
|
||||
category: string;
|
||||
description: string;
|
||||
stock: number;
|
||||
prices: ProductPrice[];
|
||||
media?: Media[];
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
export interface ProductResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
product?: Product;
|
||||
data?: Product;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface ProductListResponse {
|
||||
success: boolean;
|
||||
data?: Product[];
|
||||
count?: number;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface CreateProductData {
|
||||
name: string;
|
||||
category: string;
|
||||
description: string;
|
||||
stock: number;
|
||||
prices: ProductPrice[];
|
||||
media?: File[];
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Informations détaillées d'un livreur
|
||||
*/
|
||||
export interface DeliveryPersonDetails {
|
||||
id: number;
|
||||
username: string;
|
||||
role: string;
|
||||
status: "available" | "busy" | "offline";
|
||||
current_command?: number | null;
|
||||
queue_size: number;
|
||||
total_deliveries?: number;
|
||||
completed_deliveries?: number;
|
||||
pending_deliveries?: number;
|
||||
location?: {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
last_update: number;
|
||||
last_update_ago: number;
|
||||
is_recent: boolean;
|
||||
};
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Statistiques d'un livreur
|
||||
*/
|
||||
export interface DeliveryPersonStats {
|
||||
username: string;
|
||||
total_deliveries: number;
|
||||
completed_deliveries: number;
|
||||
cancelled_deliveries: number;
|
||||
pending_deliveries: number;
|
||||
in_progress_deliveries: number;
|
||||
average_delivery_time?: number; // en minutes
|
||||
success_rate?: number; // en pourcentage
|
||||
total_distance?: number; // en km
|
||||
current_queue_size: number;
|
||||
last_delivery_date?: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Historique des livraisons d'un livreur
|
||||
*/
|
||||
export interface DeliveryHistory {
|
||||
command_id: number;
|
||||
client: string;
|
||||
status: string;
|
||||
adresse: string;
|
||||
total_prix: number;
|
||||
assigned_at: string;
|
||||
completed_at?: string;
|
||||
delivery_time?: number; // en minutes
|
||||
distance?: number; // en km
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Position GPS d'un livreur
|
||||
*/
|
||||
export interface DeliveryPersonLocation {
|
||||
username: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
last_update: number;
|
||||
last_update_ago: number;
|
||||
is_recent: boolean;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface DeliverymanLocation {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
last_update: number;
|
||||
last_update_ago: number;
|
||||
is_recent: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Statistiques d'un livreur
|
||||
*/
|
||||
export interface DeliveryPersonStats {
|
||||
username: string;
|
||||
total_deliveries: number;
|
||||
completed_deliveries: number;
|
||||
cancelled_deliveries: number;
|
||||
pending_deliveries: number;
|
||||
in_progress_deliveries: number;
|
||||
average_delivery_time?: number; // en minutes
|
||||
success_rate?: number; // en pourcentage
|
||||
total_distance?: number; // en km
|
||||
current_queue_size: number;
|
||||
last_delivery_date?: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Historique des livraisons d'un livreur
|
||||
*/
|
||||
export interface DeliveryHistory {
|
||||
command_id: number;
|
||||
client: string;
|
||||
status: string;
|
||||
adresse: string;
|
||||
total_prix: number;
|
||||
assigned_at: string;
|
||||
completed_at?: string;
|
||||
delivery_time?: number; // en minutes
|
||||
distance?: number; // en km
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Position GPS d'un livreur
|
||||
*/
|
||||
export interface DeliveryPersonLocation {
|
||||
username: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
last_update: number;
|
||||
last_update_ago: number;
|
||||
is_recent: boolean;
|
||||
status: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Réponse position livreur pour une commande
|
||||
*/
|
||||
export interface DeliverymanLocationResponse {
|
||||
success: boolean;
|
||||
data?: {
|
||||
command_id: number;
|
||||
client: string;
|
||||
command_status: string;
|
||||
deliveryman: DeliverymanInfo;
|
||||
eta: CommandETA;
|
||||
};
|
||||
requested_by?: {
|
||||
username: string;
|
||||
role: string;
|
||||
};
|
||||
error?: string;
|
||||
message?: string;
|
||||
command_info?: {
|
||||
command_id: number;
|
||||
client: string;
|
||||
deliveryman?: string;
|
||||
status: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Liste des livreurs disponibles
|
||||
*/
|
||||
export interface DeliveryPersonsListResponse {
|
||||
success: boolean;
|
||||
livreurs: DeliveryPersonDetails[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 📦 INTERFACES LIVREURS - CABINE & ADMIN
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* ✅ Livreur avec détails complets (pour liste)
|
||||
*/
|
||||
export interface DeliveryPerson {
|
||||
id: number;
|
||||
username: string;
|
||||
nom?: string;
|
||||
prenom?: string;
|
||||
telephone?: string;
|
||||
status: "available" | "busy" | "offline";
|
||||
location: {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
last_update: string;
|
||||
is_recent: boolean;
|
||||
};
|
||||
stats: {
|
||||
total_deliveries: number;
|
||||
completed_today: number;
|
||||
queue_size: number;
|
||||
current_command: number | null;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Stats globales des livreurs
|
||||
*/
|
||||
export interface DeliveryPersonsStats {
|
||||
total: number;
|
||||
available: number;
|
||||
busy: number;
|
||||
offline: number;
|
||||
active_deliveries: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Réponse API getAllDeliveryPersonsWithDetails
|
||||
*/
|
||||
export interface AllDeliveryPersonsResponse {
|
||||
success: boolean;
|
||||
deliveryPersons: DeliveryPerson[];
|
||||
count: number;
|
||||
stats: DeliveryPersonsStats;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Liens de navigation GPS
|
||||
*/
|
||||
export interface MapLinks {
|
||||
google_maps: string;
|
||||
waze: string;
|
||||
apple_maps: string;
|
||||
openstreetmap: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Réponse API getDeliveryPersonMapLinks
|
||||
*/
|
||||
export interface MapLinksResponse {
|
||||
success: boolean;
|
||||
deliveryman?: string;
|
||||
location?: {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
last_update?: number;
|
||||
is_recent: boolean;
|
||||
};
|
||||
map_links?: MapLinks;
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface DeleteResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,727 @@
|
||||
// ============================================
|
||||
// api/api_livreur.ts - LIVREUR API HELPERS
|
||||
// ============================================
|
||||
// ✅ Fonctions helper pour le dashboard livreur
|
||||
// ✅ Utilise /api/v1/livreur/* endpoints
|
||||
|
||||
const API_URL = "/api/v1/livreur";
|
||||
|
||||
// ============================================
|
||||
// 🔐 TYPES - LIVREUR
|
||||
// ============================================
|
||||
|
||||
export interface DeliveryStatus {
|
||||
status: "available" | "busy" | "offline";
|
||||
current_command?: number;
|
||||
last_update?: number;
|
||||
}
|
||||
|
||||
export interface QueueInfo {
|
||||
queue_size: number;
|
||||
commands: any[];
|
||||
}
|
||||
|
||||
export interface DeliveryItem {
|
||||
id: number;
|
||||
status: string;
|
||||
adresse: string;
|
||||
total_prix: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
eta?: string;
|
||||
}
|
||||
|
||||
export interface ClientInfo {
|
||||
username: string;
|
||||
nom?: string;
|
||||
prenom?: string;
|
||||
telephone?: string;
|
||||
}
|
||||
|
||||
export interface DeliveryDetails {
|
||||
delivery: DeliveryItem;
|
||||
client_info: ClientInfo;
|
||||
}
|
||||
|
||||
export interface Alert {
|
||||
id: number;
|
||||
username: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 🔐 GESTION JWT
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* ✅ Récupérer le token d'authentification
|
||||
*/
|
||||
const getAuthToken = (): string | null => {
|
||||
return sessionStorage.getItem("admin_token");
|
||||
};
|
||||
|
||||
export const isDeliveryAuthenticated = (): boolean => {
|
||||
const token = sessionStorage.getItem("admin_token");
|
||||
return !!token;
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// 📊 STATUT DU LIVREUR
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* ✅ Récupérer le statut actuel du livreur
|
||||
* GET /api/v1/livreur/status
|
||||
*/
|
||||
export const getMyStatus = async (): Promise<{
|
||||
success: boolean;
|
||||
status?: DeliveryStatus;
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🔍 [GET_MY_STATUS] Appel API");
|
||||
|
||||
const response = await fetch(`${API_URL}/status`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [GET_MY_STATUS] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [GET_MY_STATUS] Réponse:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: data.status,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [GET_MY_STATUS] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ✅ Mettre à jour le statut du livreur
|
||||
* POST /api/v1/livreur/status
|
||||
*/
|
||||
export const updateMyStatus = async (
|
||||
status: "available" | "busy" | "offline",
|
||||
): Promise<{ success: boolean; message?: string; error?: string }> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("📝 [UPDATE_MY_STATUS] Appel API:", status);
|
||||
|
||||
const response = await fetch(`${API_URL}/update/status`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({ status }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [UPDATE_MY_STATUS] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [UPDATE_MY_STATUS] Réponse:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: data.message,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [UPDATE_MY_STATUS] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// 📦 QUEUE DU LIVREUR
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* ✅ Récupérer la queue de livraisons du livreur
|
||||
* GET /api/v1/livreur/queue
|
||||
*/
|
||||
export const getMyQueue = async (): Promise<{
|
||||
success: boolean;
|
||||
queue_info?: QueueInfo;
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🔍 [GET_MY_QUEUE] Appel API");
|
||||
|
||||
const response = await fetch(`${API_URL}/queue`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [GET_MY_QUEUE] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [GET_MY_QUEUE] Réponse:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
queue_info: data.queue_info,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [GET_MY_QUEUE] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// 🚚 LIVRAISONS
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* ✅ Récupérer toutes les livraisons du livreur
|
||||
* GET /api/v1/livreur/deliveries
|
||||
*/
|
||||
export const getMyDeliveries = async (): Promise<{
|
||||
success: boolean;
|
||||
deliveries?: DeliveryItem[];
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🔍 [GET_MY_DELIVERIES] Appel API");
|
||||
|
||||
const response = await fetch(`${API_URL}/deliveries`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [GET_MY_DELIVERIES] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [GET_MY_DELIVERIES] Réponse:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
deliveries: data.deliveries || [],
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [GET_MY_DELIVERIES] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ✅ Récupérer les détails d'une livraison spécifique
|
||||
* GET /api/v1/livreur/deliveries/:id
|
||||
*/
|
||||
export const getDeliveryDetails = async (
|
||||
deliveryId: number,
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
delivery?: DeliveryDetails;
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🔍 [GET_DELIVERY_DETAILS] Appel API:", deliveryId);
|
||||
|
||||
const response = await fetch(`${API_URL}/deliveries/${deliveryId}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [GET_DELIVERY_DETAILS] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [GET_DELIVERY_DETAILS] Réponse:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
delivery: {
|
||||
delivery: data.delivery,
|
||||
client_info: data.client_info,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [GET_DELIVERY_DETAILS] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ✅ Démarrer une livraison
|
||||
* POST /api/v1/livreur/deliveries/:id/start
|
||||
*/
|
||||
export const startDelivery = async (
|
||||
deliveryId: number,
|
||||
latitude: number,
|
||||
longitude: number,
|
||||
): Promise<{ success: boolean; message?: string; error?: string }> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🚀 [START_DELIVERY] Appel API:", deliveryId);
|
||||
|
||||
const response = await fetch(
|
||||
`${API_URL}/deliveries/${deliveryId}/start`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({ latitude, longitude }),
|
||||
},
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [START_DELIVERY] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [START_DELIVERY] Réponse:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: data.message,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [START_DELIVERY] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ✅ Mettre à jour le statut d'une livraison
|
||||
* PUT /api/v1/livreur/deliveries/:id/status
|
||||
*/
|
||||
export const updateDeliveryStatus = async (
|
||||
deliveryId: number,
|
||||
status: string,
|
||||
latitude: number,
|
||||
longitude: number,
|
||||
): Promise<{ success: boolean; message?: string; error?: string }> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(
|
||||
"📝 [UPDATE_DELIVERY_STATUS] Appel API:",
|
||||
deliveryId,
|
||||
status,
|
||||
);
|
||||
|
||||
const response = await fetch(
|
||||
`${API_URL}/deliveries/${deliveryId}/status`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({ status, latitude, longitude }),
|
||||
},
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [UPDATE_DELIVERY_STATUS] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [UPDATE_DELIVERY_STATUS] Réponse:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: data.message,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [UPDATE_DELIVERY_STATUS] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// 📍 POSITION GPS
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* ✅ Mettre à jour la position GPS du livreur
|
||||
* POST /api/v1/livreur/location/update
|
||||
*/
|
||||
export const updateMyLocation = async (
|
||||
latitude: number,
|
||||
longitude: number,
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
message?: string;
|
||||
status?: string;
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/location/update`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({ latitude, longitude }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [UPDATE_MY_LOCATION] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: data.message,
|
||||
status: data.status,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [UPDATE_MY_LOCATION] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ✅ Récupérer la position actuelle du livreur
|
||||
* GET /api/v1/livreur/location
|
||||
*/
|
||||
export const getMyLocation = async (): Promise<{
|
||||
success: boolean;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/location`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [GET_MY_LOCATION] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
latitude: data.latitude,
|
||||
longitude: data.longitude,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [GET_MY_LOCATION] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// 🚨 ALERTES POLICE
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* ✅ Déclencher une alerte police
|
||||
* POST /api/v1/livreur/alert
|
||||
*/
|
||||
export const triggerPoliceAlert = async (): Promise<{
|
||||
success: boolean;
|
||||
alert_id?: number;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🚨 [TRIGGER_POLICE_ALERT] Déclenchement alerte police");
|
||||
|
||||
const response = await fetch(`${API_URL}/alert`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [TRIGGER_POLICE_ALERT] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [TRIGGER_POLICE_ALERT] Alerte créée:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
alert_id: data.alert_id,
|
||||
message: data.message,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [TRIGGER_POLICE_ALERT] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ✅ Mettre fin à une alerte
|
||||
* DELETE /api/v1/livreur/alert/:id
|
||||
*/
|
||||
export const endAlert = async (
|
||||
alertId: number,
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🔚 [END_ALERT] Terminer alerte:", alertId);
|
||||
|
||||
const response = await fetch(`${API_URL}/alert/${alertId}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [END_ALERT] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [END_ALERT] Alerte terminée:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: data.message,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [END_ALERT] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ✅ Récupérer toutes mes alertes
|
||||
* GET /api/v1/livreur/alerts
|
||||
*/
|
||||
export const getMyAlerts = async (): Promise<{
|
||||
success: boolean;
|
||||
alerts?: Alert[];
|
||||
count?: number;
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🔍 [GET_MY_ALERTS] Récupération alertes");
|
||||
|
||||
const response = await fetch(`${API_URL}/alerts`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [GET_MY_ALERTS] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [GET_MY_ALERTS] Alertes récupérées:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
alerts: data.alerts || [],
|
||||
count: data.count || 0,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [GET_MY_ALERTS] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ✅ Récupérer les détails d'une alerte
|
||||
* GET /api/v1/livreur/alert/:id
|
||||
*/
|
||||
export const getAlertDetails = async (
|
||||
alertId: number,
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
alert?: Alert;
|
||||
error?: string;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
return { success: false, error: "Token non trouvé" };
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🔍 [GET_ALERT_DETAILS] Récupération alerte:", alertId);
|
||||
|
||||
const response = await fetch(`${API_URL}/alert/${alertId}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("❌ [GET_ALERT_DETAILS] Erreur API:", data);
|
||||
return { success: false, error: data.error };
|
||||
}
|
||||
|
||||
console.log("✅ [GET_ALERT_DETAILS] Alerte récupérée:", data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
alert: data.alert,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ [GET_ALERT_DETAILS] Erreur fetch:", error);
|
||||
return { success: false, error: "Erreur réseau" };
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// 🔄 EXPORT PAR DÉFAUT
|
||||
// ============================================
|
||||
|
||||
export default {
|
||||
// Statut
|
||||
getMyStatus,
|
||||
updateMyStatus,
|
||||
|
||||
// Queue
|
||||
getMyQueue,
|
||||
|
||||
// Livraisons
|
||||
getMyDeliveries,
|
||||
getDeliveryDetails,
|
||||
startDelivery,
|
||||
updateDeliveryStatus,
|
||||
|
||||
// Position GPS
|
||||
updateMyLocation,
|
||||
getMyLocation,
|
||||
|
||||
// Alertes Police
|
||||
triggerPoliceAlert,
|
||||
endAlert,
|
||||
getMyAlerts,
|
||||
getAlertDetails,
|
||||
};
|
||||
@@ -0,0 +1,761 @@
|
||||
// ============================================
|
||||
// api/api_TYPES.ts - TOUTES LES INTERFACES
|
||||
// ============================================
|
||||
// Interfaces complètes pour le frontend
|
||||
// À importer dans les composants
|
||||
|
||||
// ============================================
|
||||
// 🔐 AUTHENTIFICATION - TYPES
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Réponse générique de l'API
|
||||
*/
|
||||
export interface ApiResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
access_token?: string;
|
||||
token_type?: string;
|
||||
expires_in?: number;
|
||||
user?: UserResponse;
|
||||
[key: string]: any; // Pour les champs additionnels
|
||||
}
|
||||
|
||||
/**
|
||||
* Données utilisateur retournées après login/register
|
||||
*/
|
||||
export interface UserResponse {
|
||||
id: number;
|
||||
username: string;
|
||||
nom?: string;
|
||||
prenom?: string;
|
||||
telephone?: string;
|
||||
role?: string;
|
||||
session_id?: string;
|
||||
command?: number;
|
||||
point?: number;
|
||||
point_zipette?: number; // ✅ AJOUTER CETTE LIGNE
|
||||
amende?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requête de login
|
||||
*/
|
||||
export interface LoginRequest {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Réponse de login
|
||||
*/
|
||||
export interface LoginResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
access_token?: string;
|
||||
token_type?: string;
|
||||
expires_in?: number;
|
||||
user?: UserResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requête d'enregistrement client
|
||||
*/
|
||||
export interface RegisterRequest {
|
||||
username: string;
|
||||
password: string;
|
||||
nom: string;
|
||||
prenom: string;
|
||||
telephone: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative: RegisterData (utilisée dans Register.tsx)
|
||||
*/
|
||||
export interface RegisterData {
|
||||
username: string;
|
||||
password: string;
|
||||
nom: string;
|
||||
prenom: string;
|
||||
telephone: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Réponse d'enregistrement
|
||||
*/
|
||||
export interface RegisterResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
access_token?: string;
|
||||
token_type?: string;
|
||||
expires_in?: number;
|
||||
user?: UserResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requête d'enregistrement admin
|
||||
*/
|
||||
export interface RegisterAdminRequest {
|
||||
username: string;
|
||||
password: string;
|
||||
role: "admin" | "cabine" | "livreur";
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 🛒 PANIER - TYPES
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Item du panier côté frontend
|
||||
*/
|
||||
export interface CartItem {
|
||||
id: number;
|
||||
product_id: number;
|
||||
name_product: string;
|
||||
price: number;
|
||||
quantity: number;
|
||||
category: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Item du panier retourné par l'API
|
||||
*/
|
||||
export interface BasketItem {
|
||||
id: number;
|
||||
product_id: number;
|
||||
username: string;
|
||||
name_product?: string;
|
||||
product_name?: string;
|
||||
category: string;
|
||||
price: number;
|
||||
quantity: number;
|
||||
image?: string;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requête d'ajout au panier
|
||||
*/
|
||||
export interface AddToBasketRequest {
|
||||
username: string;
|
||||
name_product: string;
|
||||
category: string;
|
||||
quantity: number;
|
||||
price: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Réponse du panier
|
||||
*/
|
||||
export interface BasketResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
panier?: BasketItem[];
|
||||
data?: {
|
||||
panier?: BasketItem[];
|
||||
};
|
||||
count?: number;
|
||||
total?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requête de suppression du panier
|
||||
*/
|
||||
export interface RemoveFromBasketRequest {
|
||||
id: number;
|
||||
username: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requête de vidage du panier
|
||||
*/
|
||||
export interface ClearBasketRequest {
|
||||
username: string;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 📦 COMMANDES - TYPES
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Requête de checkout
|
||||
*/
|
||||
export interface CheckoutRequest {
|
||||
username: string;
|
||||
delivery_address: string;
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
phone?: string;
|
||||
payment_method?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data pour le checkout
|
||||
*/
|
||||
export interface CheckoutData {
|
||||
username?: string;
|
||||
delivery_address: string;
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
phone?: string;
|
||||
payment_method?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Item de commande
|
||||
*/
|
||||
export interface OrderItem {
|
||||
id: number;
|
||||
command_id: number;
|
||||
produit?: string;
|
||||
product_name?: string;
|
||||
name_product?: string;
|
||||
prix?: number;
|
||||
price?: number;
|
||||
quantite?: number;
|
||||
quantity?: number;
|
||||
category?: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Détails d'une commande
|
||||
*/
|
||||
export interface OrderDetail {
|
||||
id: number;
|
||||
username: string;
|
||||
status: string;
|
||||
delivery_address?: string;
|
||||
adresse?: string;
|
||||
created_at: string;
|
||||
updated_at?: string;
|
||||
total?: number;
|
||||
total_prix?: number;
|
||||
livreur_assign?: string;
|
||||
items?: OrderItem[];
|
||||
|
||||
// Infos client enrichies
|
||||
client_id?: number;
|
||||
client_prenom?: string;
|
||||
client_nom?: string;
|
||||
client_telephone?: string;
|
||||
|
||||
// Infos du formulaire checkout
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
phone?: string;
|
||||
|
||||
// Infos livreur
|
||||
livreur_username?: string;
|
||||
livreur_distance?: number;
|
||||
|
||||
// Métadonnées
|
||||
payment_method?: string;
|
||||
notes?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Réponse des commandes
|
||||
*/
|
||||
export interface OrdersResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
commands?: OrderDetail[];
|
||||
count?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Informations de livraison assignée
|
||||
*/
|
||||
export interface AssignedDelivery {
|
||||
username: string;
|
||||
distance_km: number;
|
||||
eta_minutes: number;
|
||||
last_update?: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Position dans la file d'attente
|
||||
*/
|
||||
export interface QueueInfo {
|
||||
position: number;
|
||||
status: string;
|
||||
estimated_wait: string;
|
||||
total_in_queue?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Réponse de checkout
|
||||
*/
|
||||
export interface CheckoutResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
command_id?: number;
|
||||
command?: {
|
||||
id: number;
|
||||
status: string;
|
||||
total?: number;
|
||||
livreur_assign?: string;
|
||||
created_at?: string;
|
||||
};
|
||||
delivery_address?: string;
|
||||
assigned_to?: AssignedDelivery;
|
||||
queue_info?: QueueInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requête d'approbation de livraison
|
||||
*/
|
||||
export interface ApproveDeliveryRequest {
|
||||
rating?: number;
|
||||
comment?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Réponse d'approbation
|
||||
*/
|
||||
export interface ApproveDeliveryResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
points_earned?: number;
|
||||
category?: string; // ✅ AJOUTER CETTE LIGNE
|
||||
points_info?: string; // ✅ AJOUTER CETTE LIGNE
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 📍 TRACKING & SUIVI - TYPES
|
||||
// ============================================
|
||||
export interface TrackingResponse {
|
||||
success: boolean;
|
||||
command_id: number;
|
||||
status: string;
|
||||
current_step: string;
|
||||
livreur?: string;
|
||||
livreur_username?: string;
|
||||
livreur_distance?: number;
|
||||
estimated_arrival?: string;
|
||||
eta_minutes?: number;
|
||||
location?: {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
};
|
||||
delivery_address?: string;
|
||||
incidents_detected?: number;
|
||||
updated_at?: number;
|
||||
created_at?: string;
|
||||
message?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 📦 PRODUITS - TYPES
|
||||
// ============================================
|
||||
export interface ProductPrice {
|
||||
quantity: number;
|
||||
price: number;
|
||||
}
|
||||
export interface Product {
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
category: string;
|
||||
stock: number;
|
||||
prices?: ProductPrice[];
|
||||
media?: Array<{
|
||||
// ✅ CHANGÉ
|
||||
url: string;
|
||||
type: string;
|
||||
id?: number;
|
||||
created_at?: string;
|
||||
}>;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface ProductsResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
data?: Product[];
|
||||
products?: Product[];
|
||||
count?: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Réponse produit unique
|
||||
*/
|
||||
export interface ProductResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
data?: Product;
|
||||
product?: Product;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 🔐 SESSION - TYPES
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Données de session côté frontend
|
||||
*/
|
||||
export interface SessionData {
|
||||
token: string;
|
||||
username: string;
|
||||
user_id?: number;
|
||||
session_id?: string;
|
||||
created_at?: number;
|
||||
expires_at?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT Payload (claims)
|
||||
*/
|
||||
export interface JWTPayload {
|
||||
client_id?: number;
|
||||
user_id?: number;
|
||||
username: string;
|
||||
role: string;
|
||||
session_id: string;
|
||||
iat: number;
|
||||
exp: number;
|
||||
iss: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 🎯 ERROR - TYPES
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Réponse d'erreur API
|
||||
*/
|
||||
export interface ErrorResponse {
|
||||
success: false;
|
||||
error: string;
|
||||
message?: string;
|
||||
details?: string;
|
||||
status_code?: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erreur de validation
|
||||
*/
|
||||
export interface ValidationError {
|
||||
field: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Réponse de validation échouée
|
||||
*/
|
||||
export interface ValidationErrorResponse {
|
||||
success: false;
|
||||
errors: ValidationError[];
|
||||
message?: string;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 📊 CONTEXTE PANIER - TYPES
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* État du contexte panier
|
||||
*/
|
||||
export interface CartContextState {
|
||||
cartItems: CartItem[];
|
||||
cartCount: number;
|
||||
cartTotal: number;
|
||||
loading: boolean;
|
||||
isAuthenticated: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions du contexte panier
|
||||
*/
|
||||
export interface CartContextActions {
|
||||
addToCart: (item: Omit<CartItem, "id">) => Promise<void>;
|
||||
removeFromCart: (id: number) => Promise<void>;
|
||||
updateQuantity: (id: number, quantity: number) => Promise<void>;
|
||||
clearCart: () => Promise<void>;
|
||||
refreshCart: () => Promise<void>;
|
||||
showToast: (
|
||||
message: string,
|
||||
type: "success" | "error" | "warning" | "info",
|
||||
) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toast notification
|
||||
*/
|
||||
export interface ToastMessage {
|
||||
id: string;
|
||||
message: string;
|
||||
type: "success" | "error" | "warning" | "info";
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 🔐 AUTHENTIFICATION UTILS - TYPES
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Résultat de validation du formulaire de login
|
||||
*/
|
||||
export interface LoginFormValidation {
|
||||
valid: boolean;
|
||||
errors: {
|
||||
username?: string;
|
||||
password?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Résultat de validation du formulaire d'enregistrement
|
||||
*/
|
||||
export interface RegisterFormValidation {
|
||||
valid: boolean;
|
||||
errors: {
|
||||
nom?: string;
|
||||
prenom?: string;
|
||||
telephone?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* État du formulaire de login
|
||||
*/
|
||||
export interface LoginFormState {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* État du formulaire d'enregistrement
|
||||
*/
|
||||
export interface RegisterFormState {
|
||||
nom: string;
|
||||
prenom: string;
|
||||
telephone: string;
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* État du formulaire de checkout
|
||||
*/
|
||||
export interface CheckoutFormState {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
address: string;
|
||||
phone: string;
|
||||
paymentMethod: string;
|
||||
}
|
||||
|
||||
export interface CompletedOrder {
|
||||
id: number;
|
||||
username: string;
|
||||
status: string;
|
||||
adresse: string;
|
||||
total_prix: number;
|
||||
livreur_assign?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface ClientStats {
|
||||
username: string;
|
||||
nom?: string;
|
||||
prenom?: string;
|
||||
telephone?: string;
|
||||
total_commands: number;
|
||||
points: number;
|
||||
points_zipette: number; // ✅ AJOUTER CETTE LIGNE
|
||||
penalties: number;
|
||||
}
|
||||
|
||||
export interface HistoryResponse {
|
||||
success: boolean;
|
||||
commands: CompletedOrder[];
|
||||
count: number;
|
||||
client_stats?: ClientStats;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface ETAResponse {
|
||||
success: boolean;
|
||||
command_id: number;
|
||||
eta_minutes: number;
|
||||
estimated_arrival: string;
|
||||
status: string;
|
||||
livreur_distance?: number;
|
||||
message?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 🚫 ANNULATION DE COMMANDES - TYPES
|
||||
// ============================================
|
||||
|
||||
export interface CancelCommandRequest {
|
||||
reason?: string;
|
||||
force?: boolean;
|
||||
}
|
||||
|
||||
export interface PenaltyDetails {
|
||||
points: number;
|
||||
total_violations: number;
|
||||
reason: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface PenaltyWarning {
|
||||
will_apply: boolean;
|
||||
penalty_amount: number;
|
||||
current_violations: number;
|
||||
message: string;
|
||||
scale: {
|
||||
"1st_cancel": string;
|
||||
"2nd_cancel": string;
|
||||
"3rd_cancel": string;
|
||||
"4th+_cancel": string;
|
||||
your_next: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CancelCommandResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
warning?: boolean;
|
||||
command_id?: number;
|
||||
penalty?: PenaltyDetails;
|
||||
penalty_warning?: PenaltyWarning;
|
||||
details?: {
|
||||
livreur?: string;
|
||||
status?: string;
|
||||
position_in_queue?: number;
|
||||
queue_info?: any;
|
||||
};
|
||||
action_required?: string;
|
||||
example?: any;
|
||||
new_status?: string;
|
||||
cancelled_by?: {
|
||||
username: string;
|
||||
role: string;
|
||||
};
|
||||
reason?: string;
|
||||
info?: string;
|
||||
}
|
||||
|
||||
export interface CancellationHistoryItem {
|
||||
command_id: number;
|
||||
cancelled_at: string;
|
||||
reason: string;
|
||||
penalty_applied: number;
|
||||
had_livreur: boolean;
|
||||
livreur_username?: string;
|
||||
}
|
||||
|
||||
export interface CancellationHistoryResponse {
|
||||
success: boolean;
|
||||
data?: {
|
||||
username: string;
|
||||
history: CancellationHistoryItem[];
|
||||
total_penalties: number;
|
||||
warning?: string;
|
||||
info?: string;
|
||||
};
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface GetOrderDetailsResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
order?: OrderDetailsData | null;
|
||||
}
|
||||
|
||||
export interface OrderDetailsData extends OrderDetail {
|
||||
products?: OrderProduct[];
|
||||
phone?: string;
|
||||
email?: string;
|
||||
payment_method?: string;
|
||||
delivery_time?: string;
|
||||
delivery_notes?: string;
|
||||
}
|
||||
|
||||
export interface OrderProduct {
|
||||
id: number;
|
||||
name_product: string;
|
||||
category: string;
|
||||
price: number;
|
||||
quantity: number;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
export interface PenaltyInfo {
|
||||
username: string;
|
||||
total_penalty: number;
|
||||
cancellations_count: number;
|
||||
has_penalties: boolean;
|
||||
points?: number; // ✅ AJOUTER CETTE LIGNE (points weed/hash)
|
||||
points_zipette?: number; // ✅ AJOUTER CETTE LIGNE (points zipette)
|
||||
cancellation_history?: {
|
||||
current_amende: number;
|
||||
next_penalty: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PenaltiesResponse {
|
||||
success: boolean;
|
||||
data?: PenaltyInfo;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface CheckoutCartData {
|
||||
username?: string;
|
||||
delivery_address: string;
|
||||
}
|
||||
|
||||
export interface CheckoutCartResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
command_id?: number;
|
||||
delivery_address?: string;
|
||||
command?: {
|
||||
id: number;
|
||||
status: string;
|
||||
total: number;
|
||||
livreur_assign?: string;
|
||||
created_at: string;
|
||||
};
|
||||
assigned_to?: {
|
||||
username: string;
|
||||
distance_km: number;
|
||||
eta_minutes: number;
|
||||
};
|
||||
queue_info?: {
|
||||
position: number;
|
||||
status: string;
|
||||
estimated_wait: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ConfirmReceptionResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
points_earned?: number;
|
||||
data?: {
|
||||
category?: string; // ✅ Catégorie de points ('zipette&co', 'weed&hash', etc.)
|
||||
points_earned?: number;
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user