Parcourir la source

fix(resources): use RESOURCES_BASE_URL to bypass /api for uploads

unknown il y a 3 jours
Parent
commit
62a132ca09
4 fichiers modifiés avec 18 ajouts et 17 suppressions
  1. 1 0
      src/lib/api.ts
  2. 9 9
      src/pages/Admin.vue
  3. 5 5
      src/pages/Orders.vue
  4. 3 3
      src/pages/Portfolio.vue

+ 1 - 0
src/lib/api.ts

@@ -1,6 +1,7 @@
 import i18n from "../i18n";
 
 export const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
+export const RESOURCES_BASE_URL = API_BASE_URL.replace(/\/api$/, '');
 
 const getErrorMessage = async (response: Response, defaultMsg: string) => {
   try {

+ 9 - 9
src/pages/Admin.vue

@@ -188,10 +188,10 @@
                     <div v-if="f.id" class="relative group/file bg-background/30 border border-border/50 rounded-2xl overflow-hidden hover:border-primary/30 transition-all flex h-20">
                     <!-- Preview -->
                     <div class="w-20 bg-muted/20 flex items-center justify-center border-r border-border/50 overflow-hidden">
-                       <img v-if="f.preview_path" :src="`${API_BASE_URL}/${f.preview_path}`" class="w-full h-full object-contain p-1" />
+                       <img v-if="f.preview_path" :src="`${RESOURCES_BASE_URL}/${f.preview_path}`" class="w-full h-full object-contain p-1" />
                        <FileBox v-else class="w-6 h-6 text-muted-foreground/30" />
                        <div class="absolute inset-0 bg-primary/20 opacity-0 group-hover/file:opacity-100 transition-opacity flex items-center justify-center">
-                         <a :href="`${API_BASE_URL}/${f.file_path}`" target="_blank" class="bg-card w-8 h-8 rounded-full flex items-center justify-center shadow-lg"><Download class="w-4 h-4 text-primary" /></a>
+                         <a :href="`${RESOURCES_BASE_URL}/${f.file_path}`" target="_blank" class="bg-card w-8 h-8 rounded-full flex items-center justify-center shadow-lg"><Download class="w-4 h-4 text-primary" /></a>
                        </div>
                     </div>
                     <!-- Info -->
@@ -225,13 +225,13 @@
                 </div>
                 <div class="flex flex-wrap gap-2">
                   <div v-for="(p, i) in order.photos" :key="i" class="relative group/img overflow-hidden rounded-lg border border-border/50 w-12 h-12 bg-background/50">
-                    <img :src="`${API_BASE_URL}/${p.file_path}`" class="w-full h-full object-cover" />
+                    <img :src="`${RESOURCES_BASE_URL}/${p.file_path}`" class="w-full h-full object-cover" />
                     <button @click="handleTogglePhotoPublic(p.id, p.is_public, order.allow_portfolio)"
                       :class="`absolute top-0 right-0 p-0.5 rounded-bl-md bg-black/60 z-10 transition-colors ${p.is_public ? 'text-blue-400 hover:text-blue-300' : 'text-gray-400 hover:text-white'}`">
                       <Eye v-if="p.is_public" class="w-2.5 h-2.5" /><EyeOff v-else class="w-2.5 h-2.5" />
                     </button>
                     <div class="absolute inset-0 flex items-center justify-center bg-black/40 opacity-0 group-hover/img:opacity-100 transition-opacity gap-2">
-                       <a :href="`${API_BASE_URL}/${p.file_path}`" target="_blank" class="w-7 h-7 bg-white/10 hover:bg-white/20 rounded-full flex items-center justify-center transition-colors">
+                       <a :href="`${RESOURCES_BASE_URL}/${p.file_path}`" target="_blank" class="w-7 h-7 bg-white/10 hover:bg-white/20 rounded-full flex items-center justify-center transition-colors">
                           <ExternalLink class="w-3.5 h-3.5 text-white" />
                        </a>
                        <button @click="handleDeletePhoto(p.id)" class="w-7 h-7 bg-rose-500/20 hover:bg-rose-500/40 rounded-full flex items-center justify-center transition-colors">
@@ -269,12 +269,12 @@
                 </div>
                 <div class="text-2xl font-display font-bold">{{ (order.total_price || 0) }} <span class="text-xs">EUR</span></div>
                 
-                <a v-if="order.proforma_path" :href="`${API_BASE_URL}/${order.proforma_path}`" target="_blank"
+                <a v-if="order.proforma_path" :href="`${RESOURCES_BASE_URL}/${order.proforma_path}`" target="_blank"
                    class="mt-4 w-full flex items-center justify-center gap-2 py-2 rounded-xl bg-orange-500/10 hover:bg-orange-500/20 text-orange-600 border border-orange-500/20 font-bold transition-all text-sm">
                   <FileText class="w-4 h-4" /> {{ t("admin.actions.printProforma") }}
                 </a>
 
-                <a v-if="order.invoice_path" :href="`${API_BASE_URL}/${order.invoice_path}`" target="_blank"
+                <a v-if="order.invoice_path" :href="`${RESOURCES_BASE_URL}/${order.invoice_path}`" target="_blank"
                    class="mt-2 w-full flex items-center justify-center gap-2 py-2 rounded-xl bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-600 border border-emerald-500/20 font-bold transition-all text-sm">
                   <FileText class="w-4 h-4" /> {{ t("admin.actions.printInvoice") }}
                 </a>
@@ -515,7 +515,7 @@
       <!-- PORTFOLIO -->
       <div v-else-if="activeTab === 'portfolio'" class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4">
         <div v-for="pi in portfolioItems" :key="pi.id" class="group relative aspect-square bg-card/40 border border-border/50 rounded-2xl overflow-hidden hover:border-primary/30 transition-all">
-           <img :src="`${API_BASE_URL}/${pi.file_path}`" class="w-full h-full object-cover" />
+           <img :src="`${RESOURCES_BASE_URL}/${pi.file_path}`" class="w-full h-full object-cover" />
            
            <!-- Status Overlay -->
            <div class="absolute top-2 left-2 flex gap-1">
@@ -534,7 +534,7 @@
                     :title="pi.is_public ? t('admin.actions.makePrivate') : t('admin.actions.makePublic')">
                     <Eye v-if="pi.is_public" class="w-4 h-4" /><EyeOff v-else class="w-4 h-4" />
                  </button>
-                 <a :href="`${API_BASE_URL}/${pi.file_path}`" target="_blank" class="p-2 bg-white/10 text-white hover:bg-white/20 rounded-xl transition-all">
+                 <a :href="`${RESOURCES_BASE_URL}/${pi.file_path}`" target="_blank" class="p-2 bg-white/10 text-white hover:bg-white/20 rounded-xl transition-all">
                     <ExternalLink class="w-4 h-4" />
                  </a>
                  <button @click="handleDeletePhoto(pi.id)" class="p-2 bg-rose-500/20 text-rose-500 hover:bg-rose-500 hover:text-white rounded-xl transition-all">
@@ -925,7 +925,7 @@ import {
   adminGetOrders, adminUpdateOrder, adminGetMaterials, adminCreateMaterial, adminUpdateMaterial, adminDeleteMaterial, 
   adminGetServices, adminCreateService, adminUpdateService, adminDeleteService, adminUploadOrderPhoto, 
   adminUpdatePhotoStatus, adminDeletePhoto, adminGetAllPhotos, adminAttachFile, adminDeleteFile, adminDeleteOrder, getBlogPosts, adminCreatePost, adminUpdatePost, adminDeletePost, adminUpdateUser, adminGetUsers, adminCreateUser, adminGetAuditLogs,
-  adminGetOrderItems, adminUpdateOrderItems, API_BASE_URL
+  adminGetOrderItems, adminUpdateOrderItems, API_BASE_URL, RESOURCES_BASE_URL
 } from "@/lib/api";
 
 const { t, locale } = useI18n();

+ 5 - 5
src/pages/Orders.vue

@@ -136,10 +136,10 @@
                   <div v-if="file.id" 
                     class="bg-background/40 border border-border/50 rounded-2xl overflow-hidden group/file hover:border-primary/30 transition-all flex flex-col h-full">
                     <div class="aspect-square bg-muted/20 flex items-center justify-center p-2 relative overflow-hidden">
-                      <img v-if="file.preview_path" :src="`${API_BASE_URL}/${file.preview_path}`" class="w-full h-full object-contain" />
+                      <img v-if="file.preview_path" :src="`${RESOURCES_BASE_URL}/${file.preview_path}`" class="w-full h-full object-contain" />
                       <FileBox v-else class="w-8 h-8 text-muted-foreground/20" />
                       <div class="absolute inset-0 bg-primary/20 opacity-0 group-hover/file:opacity-100 transition-opacity flex items-center justify-center">
-                         <a :href="`${API_BASE_URL}/${file.file_path}`" target="_blank" class="bg-card w-8 h-8 rounded-full flex items-center justify-center shadow-lg"><Download class="w-4 h-4 text-primary" /></a>
+                         <a :href="`${RESOURCES_BASE_URL}/${file.file_path}`" target="_blank" class="bg-card w-8 h-8 rounded-full flex items-center justify-center shadow-lg"><Download class="w-4 h-4 text-primary" /></a>
                       </div>
                     </div>
                     <div class="p-3">
@@ -165,8 +165,8 @@
               <div class="flex flex-wrap gap-3">
                 <div v-for="photo in order.photos" :key="photo.id"
                   class="group/photo relative w-20 h-20 rounded-xl overflow-hidden border border-border/50 bg-background/50">
-                  <img :src="`${API_BASE_URL}/${photo.file_path}`" class="w-full h-full object-cover" alt="Print Progress" />
-                  <a :href="`${API_BASE_URL}/${photo.file_path}`" target="_blank"
+                  <img :src="`${RESOURCES_BASE_URL}/${photo.file_path}`" class="w-full h-full object-cover" alt="Print Progress" />
+                  <a :href="`${RESOURCES_BASE_URL}/${photo.file_path}`" target="_blank"
                     class="absolute inset-0 bg-black/40 flex items-center justify-center opacity-0 group-hover/photo:opacity-100 transition-opacity">
                     <ExternalLink class="w-4 h-4 text-white" />
                   </a>
@@ -206,7 +206,7 @@ import Header from "@/components/Header.vue";
 import Footer from "@/components/Footer.vue";
 import OrderChat from "@/components/OrderChat.vue";
 import OrderTracker from "@/components/OrderTracker.vue";
-import { getMyOrders, API_BASE_URL } from "@/lib/api";
+import { getMyOrders, API_BASE_URL, RESOURCES_BASE_URL } from "@/lib/api";
 import { useAuthStore } from "@/stores/auth";
 import { toast } from "vue-sonner";
 

+ 3 - 3
src/pages/Portfolio.vue

@@ -29,9 +29,9 @@
           :initial="{ opacity: 0, y: 20 }"
           :enter="{ opacity: 1, y: 0, transition: { delay: idx * 50 } }"
           class="group relative aspect-square overflow-hidden rounded-3xl border border-border/50 bg-card/40 backdrop-blur-sm cursor-pointer hover:border-primary/50 transition-all duration-500"
-          @click="selectedImage = `${API_BASE_URL}${item.file_path.startsWith('/') ? '' : '/'}${item.file_path}`"
+          @click="selectedImage = `${RESOURCES_BASE_URL}${item.file_path.startsWith('/') ? '' : '/'}${item.file_path}`"
         >
-          <img :src="`${API_BASE_URL}${item.file_path.startsWith('/') ? '' : '/'}${item.file_path}`" :alt="item.material_name"
+          <img :src="`${RESOURCES_BASE_URL}${item.file_path.startsWith('/') ? '' : '/'}${item.file_path}`" :alt="item.material_name"
             class="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110" />
           <div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-all duration-500 flex flex-col justify-end p-6">
             <span class="text-[10px] font-bold uppercase tracking-widest text-primary mb-1">{{ item.material_name }}</span>
@@ -82,7 +82,7 @@ import { useI18n } from "vue-i18n";
 import { Sparkles, Loader2, Camera, ExternalLink, RefreshCw, Image as ImageIcon } from "lucide-vue-next";
 import Header from "@/components/Header.vue";
 import Footer from "@/components/Footer.vue";
-import { getPortfolio, API_BASE_URL } from "@/lib/api";
+import { getPortfolio, API_BASE_URL, RESOURCES_BASE_URL } from "@/lib/api";
 
 const { t } = useI18n();
 const items = ref<any[]>([]);