chore: fix
This commit is contained in:
@@ -130,7 +130,6 @@ func (d *Database) GetAllClients() ([]*models.Client, error) {
|
||||
func (d *Database) UpdateClient(client *models.Client) error {
|
||||
result := d.GDB.Model(&models.Client{}).Where("id = ?", client.ID).Updates(map[string]any{
|
||||
"username": client.Username,
|
||||
"password": client.Password,
|
||||
"nom": client.Nom,
|
||||
"prenom": client.Prenom,
|
||||
"telephone": client.Telephone,
|
||||
|
||||
@@ -1047,7 +1047,8 @@ func DeleteCommandItem(c *gin.Context) {
|
||||
func UpdateCommandStatusAdmin(c *gin.Context) {
|
||||
database := c.MustGet("database").(*db.Database)
|
||||
|
||||
if c.GetString("role") != "admin" {
|
||||
role := c.GetString("role")
|
||||
if role != "admin" && role != "cabine" {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Accès refusé"})
|
||||
return
|
||||
}
|
||||
@@ -1068,7 +1069,7 @@ func UpdateCommandStatusAdmin(c *gin.Context) {
|
||||
|
||||
allowed := map[string]bool{
|
||||
"pending": true, "assigned": true, "en_route": true,
|
||||
"livre": true, "approved": true, "cancelled": true,
|
||||
"arrived": true, "livre": true, "approved": true, "cancelled": true,
|
||||
}
|
||||
if !allowed[req.Status] {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Statut invalide: " + req.Status})
|
||||
@@ -1080,7 +1081,7 @@ func UpdateCommandStatusAdmin(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("✅ [STATUS_ADMIN] Cmd %d → %s", commandID, req.Status)
|
||||
log.Printf("✅ [STATUS_ADMIN] Cmd %d → %s (par %s)", commandID, req.Status, role)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"message": "Statut mis à jour",
|
||||
|
||||
@@ -345,18 +345,28 @@ func UpdateDeliveryStatus(c *gin.Context) {
|
||||
var clientMsg string
|
||||
switch req.Status {
|
||||
case "en_route":
|
||||
if etaMinutes > 0 {
|
||||
notifETA := etaMinutes
|
||||
if notifETA == 0 {
|
||||
if etaData, err := database.GetCommandETA(commandID); err == nil {
|
||||
if v, ok := etaData["total_eta_minutes"]; ok {
|
||||
if n, err2 := strconv.Atoi(v); err2 == nil && n > 0 {
|
||||
notifETA = n
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if notifETA > 0 {
|
||||
var etaStr string
|
||||
if etaMinutes >= 60 {
|
||||
h := etaMinutes / 60
|
||||
m := etaMinutes % 60
|
||||
if notifETA >= 60 {
|
||||
h := notifETA / 60
|
||||
m := notifETA % 60
|
||||
if m > 0 {
|
||||
etaStr = fmt.Sprintf("%dh%02d", h, m)
|
||||
} else {
|
||||
etaStr = fmt.Sprintf("%dh", h)
|
||||
}
|
||||
} else {
|
||||
etaStr = fmt.Sprintf("%d min", etaMinutes)
|
||||
etaStr = fmt.Sprintf("%d min", notifETA)
|
||||
}
|
||||
clientMsg = fmt.Sprintf("Un livreur vient de prendre en charge ta commande #%d, il est en route (~%s)", database.GetClientOrderID(commandID), etaStr)
|
||||
} else {
|
||||
|
||||
@@ -236,7 +236,8 @@ func UpdateClientByAdmin(c *gin.Context) {
|
||||
log.Printf("✏️ [UPDATE_CLIENT_ADMIN] Username modifié: %s", req.Username)
|
||||
}
|
||||
|
||||
// Mise à jour du mot de passe
|
||||
// Mise à jour du mot de passe (opération séparée pour garantir l'écriture)
|
||||
var newHashedPassword string
|
||||
if req.Password != "" {
|
||||
if len(req.Password) < 8 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Le mot de passe doit contenir au moins 8 caractères"})
|
||||
@@ -248,7 +249,7 @@ func UpdateClientByAdmin(c *gin.Context) {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur traitement mot de passe"})
|
||||
return
|
||||
}
|
||||
client.Password = string(hashed)
|
||||
newHashedPassword = string(hashed)
|
||||
hasChanges = true
|
||||
log.Printf("✏️ [UPDATE_CLIENT_ADMIN] Mot de passe modifié")
|
||||
}
|
||||
@@ -323,13 +324,23 @@ func UpdateClientByAdmin(c *gin.Context) {
|
||||
log.Printf("📊 [UPDATE_CLIENT_ADMIN] État avant save - Command: %d, Amende: %.2f",
|
||||
client.Command, client.Amende)
|
||||
|
||||
// Sauvegarder les modifications
|
||||
// Sauvegarder les modifications de profil (hors mot de passe)
|
||||
if err := database.UpdateClient(client); err != nil {
|
||||
log.Printf("❌ [UPDATE_CLIENT_ADMIN] Erreur mise à jour: %v", err)
|
||||
log.Printf("❌ [UPDATE_CLIENT_ADMIN] Erreur mise à jour profil: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur lors de la mise à jour"})
|
||||
return
|
||||
}
|
||||
|
||||
// Mettre à jour le mot de passe séparément si demandé
|
||||
if newHashedPassword != "" {
|
||||
if err := database.UpdateClientPasswordAndClearFlag(clientID, newHashedPassword); err != nil {
|
||||
log.Printf("❌ [UPDATE_CLIENT_ADMIN] Erreur mise à jour mot de passe: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur lors de la mise à jour du mot de passe"})
|
||||
return
|
||||
}
|
||||
log.Printf("✅ [UPDATE_CLIENT_ADMIN] Mot de passe mis à jour pour client ID=%d", clientID)
|
||||
}
|
||||
|
||||
log.Printf("✅ [UPDATE_CLIENT_ADMIN] Client mis à jour par admin: %s (ID=%d)", client.Username, client.ID)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
|
||||
@@ -352,7 +352,14 @@ func StartDelivery(c *gin.Context) {
|
||||
if clientUsername, _ := command["username"].(string); clientUsername != "" {
|
||||
var msg string
|
||||
etaMinutes := 0
|
||||
if req.Latitude != 0 && req.Longitude != 0 {
|
||||
if etaData, err := database.GetCommandETA(commandID); err == nil {
|
||||
if v, ok := etaData["total_eta_minutes"]; ok {
|
||||
if n, err2 := strconv.Atoi(v); err2 == nil && n > 0 {
|
||||
etaMinutes = n
|
||||
}
|
||||
}
|
||||
}
|
||||
if etaMinutes == 0 && req.Latitude != 0 && req.Longitude != 0 {
|
||||
destLat, _ := command["dest_latitude"].(float64)
|
||||
destLon, _ := command["dest_longitude"].(float64)
|
||||
if destLat != 0 && destLon != 0 {
|
||||
|
||||
@@ -302,6 +302,7 @@ func SetupRoutes(router *gin.Engine, database *db.Database, geoService *services
|
||||
cabineGroupV1.POST("/commands/:id/confirm-reception", handlers.StaffApproveDelivery)
|
||||
cabineGroupV1.POST("/commands/:id/assign", handlers.AssignDeliveryPerson)
|
||||
cabineGroupV1.POST("/commands/:id/notify-client", handlers.NotifyClientToDescend)
|
||||
cabineGroupV1.PUT("/commands/:id/status", handlers.UpdateCommandStatusAdmin)
|
||||
cabineGroupV1.PUT("/items/:item_id/status", handlers.UpdateItemStatus)
|
||||
cabineGroupV1.GET("/commands/:id/deliveryman/location", handlers.GetDeliverymanLocationForCommand)
|
||||
cabineGroupV1.GET("/all/deliveryman", handlers.GetAllDeliveryMen)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// Surchargé par le ConfigMap Helm en production
|
||||
window.__APP_CONFIG__ = {
|
||||
apiUrl: "",
|
||||
};
|
||||
@@ -7,10 +7,6 @@ html, body, #root {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Ne pas forcer de backgroundColor global pour permettre à login d'avoir son propre style */
|
||||
body, html {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
#root {
|
||||
width: 100%;
|
||||
|
||||
@@ -2010,7 +2010,10 @@ export const updateMyProfile = async (fields: {
|
||||
// 🤖 TELEGRAM
|
||||
// ============================================
|
||||
|
||||
export const getTelegramStatus = async (): Promise<{ linked: boolean; enabled: boolean }> => {
|
||||
export const getTelegramStatus = async (): Promise<{
|
||||
linked: boolean;
|
||||
enabled: boolean;
|
||||
}> => {
|
||||
const token = getAuthToken();
|
||||
if (!token) return { linked: false, enabled: false };
|
||||
try {
|
||||
@@ -2048,5 +2051,7 @@ export const unlinkTelegram = async (): Promise<void> => {
|
||||
method: "DELETE",
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
} catch { /* silencieux */ }
|
||||
} catch {
|
||||
/* silencieux */
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,12 +16,38 @@
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
/* Empêcher le zoom sur les inputs pour iOS */
|
||||
font-size: 16px;
|
||||
|
||||
--bg: #09090b;
|
||||
--surface: #111115;
|
||||
--surface-2: #1c1c22;
|
||||
--border: rgba(255, 255, 255, 0.07);
|
||||
--primary: #8b5cf6;
|
||||
--primary-soft: rgba(139, 92, 246, 0.12);
|
||||
--primary-glow: rgba(139, 92, 246, 0.25);
|
||||
--cyan: #22d3ee;
|
||||
--cyan-soft: rgba(34, 211, 238, 0.1);
|
||||
--red: #ef4444;
|
||||
--text: #f4f4f5;
|
||||
--text-muted: #71717a;
|
||||
--radius: 10px;
|
||||
--transition: 0.22s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
color-scheme: light;
|
||||
--bg: #f4f4f8;
|
||||
--surface: #ffffff;
|
||||
--surface-2: #ebebf2;
|
||||
--border: rgba(0, 0, 0, 0.08);
|
||||
--primary: #7c3aed;
|
||||
--primary-soft: rgba(124, 58, 237, 0.08);
|
||||
--primary-glow: rgba(124, 58, 237, 0.18);
|
||||
--cyan: #0891b2;
|
||||
--cyan-soft: rgba(8, 145, 178, 0.1);
|
||||
--red: #dc2626;
|
||||
--text: #18181b;
|
||||
--text-muted: #52525b;
|
||||
}
|
||||
|
||||
html, body {
|
||||
|
||||
@@ -122,10 +122,11 @@ function Checkout() {
|
||||
if (savedAddress) setAddress(savedAddress);
|
||||
if (savedPhone) setPhone(savedPhone);
|
||||
|
||||
// Pré-remplir nom depuis le backend
|
||||
// Pré-remplir nom/prénom depuis le backend
|
||||
getMyProfile().then((res) => {
|
||||
if (res.success && res.client) {
|
||||
if (res.client.nom) setLastName(res.client.nom);
|
||||
if (res.client.prenom) setFirstName(res.client.prenom);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
|
||||
const DEV_API_TARGET = "http://localhost:8080";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
build: {
|
||||
@@ -9,11 +11,11 @@ export default defineConfig({
|
||||
server: {
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: "https://5.181.0.112.nip.io",
|
||||
target: DEV_API_TARGET,
|
||||
changeOrigin: true,
|
||||
},
|
||||
"/uploads": {
|
||||
target: "https://5.181.0.112.nip.io",
|
||||
target: DEV_API_TARGET,
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user