import apiClient from "./client"; import type { AuthResponse, ClientResponse, CommandResponse, Product, DeliveryPerson, DeliveryPersonsStats, Alert, } from "./types"; const V2 = "http://5.181.0.112/api/v2"; const CABINE_URL = "http://5.181.0.112/api/v1/cabine"; // ============================================ // AUTH // ============================================ export const loginAdmin = async ( username: string, password: string, ): Promise => { try { const { data } = await apiClient.post(`${V2}/admin/auth/login`, { username, password, }); if (!data.access_token) { return { success: false, message: "Token non reçu du serveur" }; } return { success: true, message: "Connexion réussie", access_token: data.access_token, token_type: data.token_type, expires_in: data.expires_in, user: data.user, }; } catch (error: any) { return { success: false, message: error.response?.data?.error || error.message || "Erreur de connexion", }; } }; export const logoutAdmin = async (): Promise => { try { await apiClient.post(`${V2}/admin/auth/logout`); } catch { /* ignore */ } }; // ============================================ // CLIENTS // ============================================ export const getAllClients = async (): Promise => { const { data } = await apiClient.get(`${V2}/admin/protected/all/clients`); return data.clients || []; }; export const getAllUsers = async () => { const { data } = await apiClient.get(`${V2}/admin/protected/all/users`); return data.users || []; }; export const updateClientByAdmin = async ( clientId: number, updates: Record, ) => { const { data } = await apiClient.put( `${V2}/admin/protected/clients/${clientId}`, updates, ); return { success: true, message: data.message, client: data.client }; }; export const updateUserByAdmin = async ( userId: number, updates: Record, ) => { const { data } = await apiClient.put( `${V2}/admin/protected/users/${userId}`, updates, ); return { success: true, message: data.message, user: data.user }; }; // ============================================ // COMMANDES // ============================================ export const getAllCommands = async (status?: string, username?: string) => { let url = `${V2}/admin/protected/orders`; const params: string[] = []; if (status) params.push(`status=${status}`); if (username) params.push(`username=${username}`); if (params.length) url += `?${params.join("&")}`; const { data } = await apiClient.get(url); return { success: true, commands: data.commands || [], count: data.count || 0, }; }; export const getCommandByID = async (commandId: number) => { const { data } = await apiClient.get( `${V2}/admin/protected/orders/${commandId}`, ); return { success: true, command: data.command }; }; export const getCommandItems = async (commandId: number) => { const { data } = await apiClient.get( `${V2}/admin/protected/orders/${commandId}/items`, ); return { success: true, items: data.items || [], count: data.count || 0, command_info: data.command_info, client_info: data.client_info, }; }; export const deleteCommand = async (commandId: number) => { const { data } = await apiClient.delete( `${V2}/admin/protected/orders/${commandId}`, ); return { success: true, message: data.message }; }; export const deleteCommandItem = async (commandId: number, itemId: number) => { const { data } = await apiClient.delete( `${V2}/admin/protected/orders/${commandId}/items/${itemId}`, ); return { success: true, message: data.message }; }; export const updateCommandStatus = async ( commandId: number, newStatus: string, ) => { const { data } = await apiClient.put( `${V2}/admin/protected/orders/${commandId}/status`, { status: newStatus }, ); return { success: true, message: data.message }; }; export const updateCommandAddress = async ( commandId: number, newAddress: string, ) => { const { data } = await apiClient.put( `${V2}/admin/protected/orders/${commandId}/address`, { delivery_address: newAddress }, ); return { success: true, message: data.message }; }; export const validateCommand = async (commandId: number) => { const { data } = await apiClient.post( `${V2}/admin/protected/orders/${commandId}/force-validate`, ); 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`, ); return { success: true, message: data.message, client_username: data.client_username, }; }; export const confirmReceptionAdmin = async (commandId: number) => { const { data } = await apiClient.post( `${V2}/admin/protected/orders/${commandId}/confirm-reception`, ); return { success: true, message: data.message, points_earned: data.points_earned, client_username: data.client_username, }; }; // ============================================ // LIVREURS // ============================================ export const getAvailableDeliveryPersons = async () => { const { data } = await apiClient.get( `${V2}/admin/protected/delivery-persons`, ); return { success: true, livreurs: data.livreurs || [], count: data.count || 0, }; }; export const assignDeliveryPerson = async ( commandId: number, deliveryUsername: string, ) => { const { data } = await apiClient.post( `${V2}/admin/protected/delivery-persons/${deliveryUsername}/assign/${commandId}`, ); return { success: true, message: data.message }; }; export const getDeliveryPersonDetails = async (username: string) => { const { data } = await apiClient.get( `${V2}/admin/protected/delivery-persons/${username}`, ); return data.deliveryman || data; }; const parseStatus = (status: any): "available" | "busy" | "offline" => { if (!status) return "offline"; if (status === "available" || status === "busy" || status === "offline") return status; if (typeof status === "string" && status.startsWith("{")) { try { const obj = JSON.parse(status); if ( obj.status === "available" || obj.status === "busy" || obj.status === "offline" ) return obj.status; } catch { /* ignore */ } } return "offline"; }; export const getAllDeliveryPersonsWithDetails = async (): Promise<{ success: boolean; deliveryPersons: DeliveryPerson[]; count: number; stats: DeliveryPersonsStats; }> => { try { const { data } = await apiClient.get( `${V2}/admin/protected/delivery-persons`, ); const livreurs = data.livreurs || []; const enriched = await Promise.all( livreurs.map(async (l: any): Promise => { try { const details = await getDeliveryPersonDetails(l.username); const parsedStatus = parseStatus(details.status); const hasLoc = details.location?.latitude && details.location?.longitude; return { id: l.id, username: l.username, status: parsedStatus, location: { latitude: hasLoc ? details.location.latitude : 0, longitude: hasLoc ? details.location.longitude : 0, last_update: details.location?.last_update ? new Date( details.location.last_update * 1000, ).toISOString() : new Date().toISOString(), is_recent: details.location?.is_recent || false, }, stats: { total_deliveries: details.total_deliveries || 0, completed_today: details.completed_deliveries || 0, queue_size: details.queue_size || 0, current_command: details.current_command || null, }, }; } catch { return { id: l.id, username: l.username, status: "offline", location: { latitude: 0, longitude: 0, last_update: new Date().toISOString(), is_recent: false, }, stats: { total_deliveries: 0, completed_today: 0, queue_size: 0, current_command: null, }, }; } }), ); const stats: DeliveryPersonsStats = { total: enriched.length, available: enriched.filter((d) => d.status === "available").length, busy: enriched.filter((d) => d.status === "busy").length, offline: enriched.filter((d) => d.status === "offline").length, active_deliveries: enriched.filter( (d) => d.stats.current_command !== null, ).length, }; return { success: true, deliveryPersons: enriched, count: enriched.length, stats, }; } catch { return { success: false, deliveryPersons: [], count: 0, stats: { total: 0, available: 0, busy: 0, offline: 0, active_deliveries: 0, }, }; } }; export const getDeliverymanLocationForCommand = async (commandId: number) => { try { const { data } = await apiClient.get( `${V2}/admin/protected/commands/${commandId}/deliveryman/location`, ); return { success: true, data: data.data }; } catch (error: any) { return { success: false, error: error.response?.data?.error || "Erreur", }; } }; // ============================================ // PRODUITS // ============================================ export const getAllProductsAdmin = async (): Promise<{ success: boolean; data: Product[]; count: number; }> => { try { const { data } = await apiClient.get(`${V2}/admin/protected/products`); return { success: true, data: data.data || [], count: data.count || 0 }; } catch { return { success: false, data: [], count: 0 }; } }; export const createProductAdmin = async (formData: FormData) => { const { data } = await apiClient.post( `${V2}/admin/protected/products`, formData, { headers: { "Content-Type": "multipart/form-data" }, timeout: 120000, }, ); return { success: true, data: data.data, message: data.message }; }; export const updateProductAdmin = async ( productId: number, updates: Record, ) => { const { data } = await apiClient.put( `${V2}/admin/protected/products/${productId}`, updates, ); return { success: true, data: data.data, message: data.message }; }; export const deleteProductAdmin = async (productId: number) => { const { data } = await apiClient.delete( `${V2}/admin/protected/products/${productId}`, ); return { success: true, message: data.message }; }; // ============================================ // CREATION UTILISATEURS / CLIENTS // ============================================ export const createClientByAdmin = async (data: { username: string; password: string; nom: string; prenom: string; telephone: string; }) => { const { data: res } = await apiClient.post( `https://uber-stup.club/api/v1/auth/register`, data, ); return { success: true, message: res.message || "Client créé", user: res.user, }; }; export const createUserByAdmin = async (data: { username: string; password: string; role: string; }) => { const { data: res } = await apiClient.post( `${V2}/admin/auth/register`, data, ); return { success: true, message: res.message || "Utilisateur créé", user: res.user, }; }; // ============================================ // SUPPRESSION UTILISATEURS / CLIENTS // ============================================ export const deleteUserAdmin = async (userId: number) => { const { data } = await apiClient.delete( `${V2}/admin/protected/users/${userId}`, ); return { success: true, message: data.message }; }; export const deleteClientAdmin = async (clientId: number) => { const { data } = await apiClient.delete( `${V2}/admin/protected/clients/${clientId}`, ); return { success: true, message: data.message }; }; // ============================================ // PARRAINAGE ADMIN // ============================================ export const creditClientReferral = async ( username: string, amount: number, ): Promise<{ success: boolean; balance?: number; message?: string }> => { try { const { data } = await apiClient.post( `${V2}/admin/protected/client/${username}/referral/credit`, { amount }, ); return { success: true, balance: data.balance, message: data.message }; } catch (error: any) { return { success: false, message: error.response?.data?.error || "Erreur crédit parrainage", }; } }; export const getClientReferralAdmin = async ( username: string, ): Promise<{ success: boolean; balance?: number; message?: string }> => { try { const { data } = await apiClient.get( `${V2}/admin/protected/client/${username}/referral`, ); return { success: true, balance: data.balance }; } catch (error: any) { return { success: false, message: error.response?.data?.error || "Erreur récupération", }; } }; // ============================================ // ALERTES // ============================================ export const getAdminAlerts = async (): Promise<{ success: boolean; alerts: Alert[]; count: number; }> => { try { const { data } = await apiClient.get(`${CABINE_URL}/alerts`); return { success: true, alerts: data.alerts || [], count: data.count || 0, }; } catch { return { success: false, alerts: [], count: 0 }; } }; // ============================================ // MEDIAS PRODUITS // ============================================ export const uploadProductMediaAdmin = async ( productId: number, fileUri: string, fileName: string, fileType: string, mediaType: "image" | "video", ) => { const fd = new FormData(); fd.append("file", { uri: fileUri, name: fileName, type: fileType } as any); fd.append("type", mediaType); const { data } = await apiClient.post( `${V2}/admin/protected/products/${productId}/media`, fd, { headers: { "Content-Type": "multipart/form-data" }, timeout: 120000 }, ); return { success: true, media: data.media, message: data.message }; }; export const deleteProductMediaAdmin = async ( productId: number, mediaId: number, ) => { const { data } = await apiClient.delete( `${V2}/admin/protected/products/${productId}/media/${mediaId}`, ); return { success: true, message: data.message }; }; // ============================================ // ADDRESSES // ============================================ export const addAddress = async ( invalidAddress: string, correctAddress: string, ): Promise<{ success: boolean; message: string }> => { const { data } = await apiClient.post(`${V2}/admin/protected/add/address`, { invalid_address: invalidAddress, correct_address: correctAddress, }); return { success: true, message: data.message }; }; export const deleteAddress = async ( invalidAddress: string, correctAddress: string, ): Promise<{ success: boolean; message: string }> => { const { data } = await apiClient.delete( `${V2}/admin/protected/delete/address`, { data: { invalid_address: invalidAddress, correct_address: correctAddress, }, }, ); return { success: true, message: data.message }; }; export const getAllAddresses = async (): Promise< { invalid_address: string; correct_address: string }[] > => { const { data } = await apiClient.get(`${V2}/admin/protected/addresses`); return (data.addresses ?? []).map((a: any) => ({ invalid_address: a.invalid_address ?? a.InvalidAddress ?? "", correct_address: a.correct_address ?? a.CorrectAddress ?? "", })); }; // ============================================ // STATS HELPERS // ============================================ export const getCommandCountByStatus = async ( status: string, ): Promise => { try { const result = await getAllCommands(status); return result.commands.length; } catch { return 0; } }; // ============================================ // CATÉGORIES // ============================================ const V1_PUBLIC = "http://5.181.0.112/api/v1"; export interface Category { id: number; name: string; color: string; is_coming_soon: boolean; created_at: string; } export const getCategories = async (): Promise => { try { const { data } = await apiClient.get(`${V1_PUBLIC}/categories`); return data.categories || []; } catch { return []; } }; export const createCategoryAdmin = async ( name: string, color: string, isComingSoon: boolean = false, ): Promise<{ success: boolean; category?: Category; error?: string }> => { try { const { data } = await apiClient.post( `${V2}/admin/protected/categories`, { name, color, is_coming_soon: isComingSoon }, ); return { success: true, category: data.category }; } catch (error: any) { return { success: false, error: error.response?.data?.error || "Erreur", }; } }; export const updateCategoryAdmin = async ( id: number, name: string, color: string, isComingSoon: boolean = false, ): Promise<{ success: boolean; category?: Category; error?: string }> => { try { const { data } = await apiClient.put( `${V2}/admin/protected/categories/${id}`, { name, color, is_coming_soon: isComingSoon }, ); return { success: true, category: data.category }; } catch (error: any) { return { success: false, error: error.response?.data?.error || "Erreur", }; } }; export const deleteCategoryAdmin = async ( id: number, ): Promise<{ success: boolean; error?: string }> => { try { await apiClient.delete(`${V2}/admin/protected/categories/${id}`); return { success: true }; } catch (error: any) { return { success: false, error: error.response?.data?.error || "Erreur", }; } }; // ============================================ // PARAMÈTRES GLOBAUX // ============================================ export interface PointsTier { min: number; max: number; // 0 = illimité points: number; } export interface PostalZone { name: string; min_amount: number; codes: string[]; } export interface DaySchedule { enabled: boolean; open_time: string; // "09:00" close_time: string; // "20:00" } export interface DeliverySchedule { monday: DaySchedule; tuesday: DaySchedule; wednesday: DaySchedule; thursday: DaySchedule; friday: DaySchedule; saturday: DaySchedule; sunday: DaySchedule; } export const DEFAULT_POSTAL_ZONES: PostalZone[] = [ { name: "Zone 30€", min_amount: 30, codes: ["44000", "44100", "44200", "44300"] }, { name: "Zone 50€", min_amount: 50, codes: ["44400", "44880", "44120", "44230", "44115", "44980", "44470", "44240", "44700", "44800", "44340", "44620", "44830"] }, { name: "Zone 100€", min_amount: 100, codes: ["44860", "44220", "44118", "44710", "44690", "44119"] }, ]; export const DEFAULT_DAY: DaySchedule = { enabled: true, open_time: "09:00", close_time: "20:00" }; export const DEFAULT_DELIVERY_SCHEDULE: DeliverySchedule = { monday: { ...DEFAULT_DAY }, tuesday: { ...DEFAULT_DAY }, wednesday: { ...DEFAULT_DAY }, thursday: { ...DEFAULT_DAY }, friday: { ...DEFAULT_DAY }, saturday: { ...DEFAULT_DAY }, sunday: { ...DEFAULT_DAY }, }; export interface AppSettings { penalties_enabled: boolean; show_amende_score: boolean; points_enabled: boolean; points_categories_weed: string[]; points_categories_zipette: string[]; points_categories_total: string[]; points_separated: boolean; points_weed_tiers: PointsTier[]; points_zipette_tiers: PointsTier[]; points_total_tiers: PointsTier[]; referral_enabled: boolean; delivery_schedule: DeliverySchedule; postal_zones: PostalZone[]; } export const getSettings = async (): Promise<{ success: boolean; settings?: AppSettings; error?: string; }> => { try { const { data } = await apiClient.get(`${V2}/admin/protected/settings`); return { success: true, settings: data.settings }; } catch (error: any) { return { success: false, error: error.response?.data?.error || "Erreur", }; } }; export const registerAdminPushToken = async ( pushToken: string, ): Promise => { try { await apiClient.post(`${V2}/admin/protected/push-token`, { push_token: pushToken, }); } catch { /* ignore */ } }; export const unregisterAdminPushToken = async (): Promise => { try { await apiClient.delete(`${V2}/admin/protected/push-token`); } catch { /* ignore */ } }; export interface AppNotification { command_id: number; type: string; message: string; created_at: string; read: boolean; } export const getAdminNotifications = async (): Promise<{ notifications: AppNotification[]; unread_count: number; }> => { const { data } = await apiClient.get(`${V2}/admin/protected/notifications`); return data; }; export const markAdminNotificationsRead = async (): Promise => { await apiClient.post(`${V2}/admin/protected/notifications/read`); }; export const updateSettings = async ( settings: AppSettings, ): Promise<{ success: boolean; settings?: AppSettings; error?: string }> => { try { const { data } = await apiClient.put( `${V2}/admin/protected/settings`, settings, ); return { success: true, settings: data.settings }; } catch (error: any) { return { success: false, error: error.response?.data?.error || "Erreur", }; } };