Ver código fonte

feat: embed order creation form directly into user orders page

unknown 2 meses atrás
pai
commit
189491dff9
2 arquivos alterados com 32 adições e 9 exclusões
  1. 15 6
      src/components/ModelUploadSection.vue
  2. 17 3
      src/pages/Orders.vue

+ 15 - 6
src/components/ModelUploadSection.vue

@@ -1,9 +1,9 @@
 <template>
-  <section id="upload" class="py-12 sm:py-20 bg-white relative">
-    <div class="absolute inset-0 bg-gradient-glow opacity-50" />
-
-    <div class="container mx-auto px-4 relative z-10">
-      <div class="text-center mb-10 sm:mb-12">
+  <section :id="embedded ? undefined : 'upload'" :class="[embedded ? '' : 'py-12 sm:py-20 bg-white relative']">
+    <div v-if="!embedded" class="absolute inset-0 bg-gradient-glow opacity-50" />
+    
+    <div :class="[embedded ? '' : 'container mx-auto px-4 relative z-10']">
+      <div v-if="!embedded" class="text-center mb-10 sm:mb-12">
         <span class="text-primary font-display text-xs font-bold tracking-[0.2em] uppercase">{{ t("upload.badge") }}</span>
         <h2 class="font-display text-3xl sm:text-4xl lg:text-5xl font-extrabold mt-4 mb-4 tracking-tight">
           {{ t("upload.title") }} <span class="text-primary">{{ t("upload.titleGradient") }}</span>
@@ -11,7 +11,7 @@
         <p class="text-foreground/60 max-w-xl mx-auto text-base font-medium">{{ t("upload.description") }}</p>
       </div>
 
-      <div class="max-w-3xl mx-auto space-y-6 sm:space-y-8">
+      <div :class="[embedded ? '' : 'max-w-3xl mx-auto space-y-6 sm:space-y-8']">
         <!-- Contact -->
         <div class="grid sm:grid-cols-2 gap-6">
           <div class="space-y-1.5">
@@ -308,6 +308,14 @@
 </template>
 
 <script setup lang="ts">
+const props = defineProps<{
+  embedded?: boolean;
+}>();
+
+const emit = defineEmits<{
+  (e: 'success'): void;
+}>();
+
 import { ref, computed, watch, onMounted } from "vue";
 import { useI18n } from "vue-i18n";
 import { toast } from "vue-sonner";
@@ -493,6 +501,7 @@ async function handleSubmit() {
     allowPortfolio.value = false;
     agreeToNuances.value = false;
     notes.value = "";
+    emit('success');
   } catch (err: any) {
     toast.error(err.message || t("upload.error"));
   } finally {

+ 17 - 3
src/pages/Orders.vue

@@ -14,13 +14,20 @@
               </h1>
               <p class="text-muted-foreground mt-2">{{ t("orders.titleSubtitle") }}</p>
             </div>
-            <Button @click="router.push('/#upload')" class="bg-primary hover:bg-primary/90 text-primary-foreground px-6 py-2.5 rounded-xl font-bold shadow-lg shadow-primary/20 flex items-center gap-2 group shrink-0">
-              <Plus class="w-4 h-4 group-hover:rotate-90 transition-transform" />
-              {{ t("orders.newOrder") }}
+            <Button @click="showNewOrderForm = !showNewOrderForm" :variant="showNewOrderForm ? 'outline' : 'hero'" class="px-6 py-2.5 rounded-xl font-bold shadow-lg flex items-center gap-2 group shrink-0">
+              <component :is="showNewOrderForm ? X : Plus" class="w-4 h-4 transition-transform group-hover:scale-110" />
+              {{ showNewOrderForm ? t("common.cancel") : t("orders.newOrder") }}
             </Button>
           </div>
         </div>
 
+        <div v-if="showNewOrderForm" 
+          v-motion :initial="{ opacity: 0, height: 0 }" :enter="{ opacity: 1, height: 'auto' }"
+          class="mb-12 bg-card/40 backdrop-blur-xl border border-primary/20 rounded-3xl p-6 sm:p-10 relative overflow-hidden">
+          <div class="absolute top-0 right-0 w-64 h-64 bg-primary/5 rounded-full blur-3xl -mr-32 -mt-32" />
+          <ModelUploadSection embedded @success="onOrderSuccess" />
+        </div>
+
         <div v-if="isLoading" class="flex flex-col items-center justify-center py-20 gap-4">
           <Loader2 class="w-10 h-10 animate-spin text-primary" />
           <p class="text-muted-foreground animate-pulse">{{ t("orders.loading") }}</p>
@@ -222,6 +229,7 @@ import Footer from "@/components/Footer.vue";
 import OrderChat from "@/components/OrderChat.vue";
 import OrderTracker from "@/components/OrderTracker.vue";
 import OrderReviewForm from "@/components/OrderReviewForm.vue";
+import ModelUploadSection from "@/components/ModelUploadSection.vue";
 import { getMyOrders, API_BASE_URL, RESOURCES_BASE_URL } from "@/lib/api";
 import { useAuthStore } from "@/stores/auth";
 import { toast } from "vue-sonner";
@@ -235,6 +243,7 @@ const totalOrders = ref(0);
 const currentPage = ref(1);
 const pageSize = 10;
 const isLoading = ref(true);
+const showNewOrderForm = ref(false);
 const openChatId = ref<number | null>(route.query.chat ? parseInt(route.query.chat.toString()) : null);
 
 async function toggleChat(orderId: number) {
@@ -261,6 +270,11 @@ watch(openChatId, (newId) => {
   }
 });
 
+function onOrderSuccess() {
+  showNewOrderForm.value = false;
+  fetchOrders();
+}
+
 // StatusBadge component defined inline
 const StatusBadge = defineComponent({
   props: { status: String },