chore: add ansible backend docker frontend-prep

This commit is contained in:
2026-01-21 13:05:13 +01:00
parent 5a280b6b01
commit 943fe4de7d
14930 changed files with 2341433 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+363
View File
@@ -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
+727
View File
@@ -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,
};
+761
View File
@@ -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;
};
}