From 72cc6000f1041dc7dbe6fb23a27ef8627021bdb1 Mon Sep 17 00:00:00 2001 From: safavimohadeseh78 Date: Sat, 8 Aug 2026 11:50:18 +0200 Subject: [PATCH] Improve auth, checkout, and API client for real backend. Wire OTP and cart/catalog to the API with Vite proxy, fix resend/register name persistence, harden order submit errors, and polish OTP and cart footer UI. Co-authored-by: Cursor --- .env.development | 4 + .env.example | 4 + src/assets/styles/main.css | 2 +- src/components/ui/CartMeterageFooter.vue | 83 ++-- src/composables/useProductOrdering.ts | 14 +- src/services/authService.ts | 168 +++++++- src/services/http.ts | 66 ++- src/stores/auth.ts | 41 +- src/stores/cart.ts | 94 ++++- src/stores/catalog.ts | 131 ++++-- src/stores/order.ts | 10 +- src/utils/constants.ts | 2 +- src/utils/pendingRegister.ts | 32 ++ src/views/auth/OtpView.vue | 84 ++-- src/views/auth/RegisterView.vue | 10 +- src/views/checkout/CashSettlementView.vue | 38 +- src/views/checkout/CheckListView.vue | 9 +- .../products/components/MobileProductPage.vue | 2 +- vite.config.ts | 9 + yarn.lock | 391 +++++++++++++++--- 20 files changed, 1023 insertions(+), 171 deletions(-) create mode 100644 .env.development create mode 100644 src/utils/pendingRegister.ts diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..97c8b06 --- /dev/null +++ b/.env.development @@ -0,0 +1,4 @@ +# Same-origin in dev (Vite proxies to the real API — avoids CORS) +VITE_API_BASE_URL=/server/api +# Set true only for offline local OTP (code 1234) +VITE_USE_MOCK_AUTH=false diff --git a/.env.example b/.env.example index e07617f..e1a994a 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,5 @@ VITE_API_BASE_URL=https://parche.montech.ir/server/api + +# For local Vite (optional): use /server/api with the proxy in vite.config.ts +# VITE_API_BASE_URL=/server/api + diff --git a/src/assets/styles/main.css b/src/assets/styles/main.css index a0ca911..6f4d776 100644 --- a/src/assets/styles/main.css +++ b/src/assets/styles/main.css @@ -303,7 +303,7 @@ input[type='number'] { .sticky-footer { position: fixed; - bottom: var(--nav-height); + bottom: calc(var(--nav-height) + 12px); inset-inline: 0; width: 100%; max-width: 100%; diff --git a/src/components/ui/CartMeterageFooter.vue b/src/components/ui/CartMeterageFooter.vue index 8110769..26d04e1 100644 --- a/src/components/ui/CartMeterageFooter.vue +++ b/src/components/ui/CartMeterageFooter.vue @@ -1,5 +1,5 @@ diff --git a/src/views/auth/RegisterView.vue b/src/views/auth/RegisterView.vue index 1708046..01e9359 100644 --- a/src/views/auth/RegisterView.vue +++ b/src/views/auth/RegisterView.vue @@ -14,6 +14,7 @@ import { hasFieldErrors, type FieldErrors, } from '@/utils/formErrors' +import { setPendingRegister } from '@/utils/pendingRegister' const router = useRouter() const auth = useAuthStore() @@ -52,10 +53,15 @@ async function submit() { return } - const result = await auth.requestOtp(normalized, { - isRegister: true, + const names = { firstName: firstName.value.trim(), lastName: lastName.value.trim(), + } + setPendingRegister(names) + + const result = await auth.requestOtp(normalized, { + isRegister: true, + ...names, }) if (result.success) { router.push({ name: 'otp', query: { phone: normalized, mode: 'register' } }) diff --git a/src/views/checkout/CashSettlementView.vue b/src/views/checkout/CashSettlementView.vue index a952d2e..6c97faf 100644 --- a/src/views/checkout/CashSettlementView.vue +++ b/src/views/checkout/CashSettlementView.vue @@ -7,6 +7,7 @@ import { useAuthStore } from '@/stores/auth' import { useCatalogStore } from '@/stores/catalog' import PageHeader from '@/components/layout/PageHeader.vue' import BaseButton from '@/components/ui/BaseButton.vue' +import FormErrorBanner from '@/components/ui/FormErrorBanner.vue' import IconSuccessCircle from '@/components/icons/IconSuccessCircle.vue' import { toPersianDigits } from '@/utils/format' import type { BankAccount, Order } from '@/types' @@ -18,6 +19,8 @@ const authStore = useAuthStore() const catalogStore = useCatalogStore() const bankAccounts = ref([]) const submitting = ref(false) +const formError = ref('') +const createdOrder = ref(null) const companyId = computed(() => { const firstItem = cartStore.activeCart?.items[0] @@ -39,7 +42,7 @@ onMounted(async () => { const expiryMessage = computed(() => { const hour = catalogStore.getCompany(companyId.value)?.cashInvoiceValidUntilHour ?? 17 const time = toPersianDigits(String(hour).padStart(2, '0')) - return `این فاکتور تا ساعت ${time}:۰۰ امروز معتبر است.` + return `پس از ثبت، فاکتور تا ساعت ${time}:۰۰ امروز معتبر است.` }) const accountsSectionTitle = computed(() => { @@ -59,14 +62,17 @@ function formatIban(value: string) { } async function createOrder(): Promise { + if (createdOrder.value) return createdOrder.value if (!authStore.user || !cartStore.activeCart || submitting.value) return null + formError.value = '' submitting.value = true try { const order = await orderStore.submitOrder(authStore.user.id, cartStore.activeCart, 'cash') + createdOrder.value = order await cartStore.hydrate() return order } catch (e) { - alert(e instanceof Error ? e.message : 'ثبت سفارش ناموفق بود.') + formError.value = e instanceof Error ? e.message : 'ثبت سفارش ناموفق بود.' return null } finally { submitting.value = false @@ -97,9 +103,13 @@ async function registerReceipt() { />
+ +
-

فاکتور شما ثبت شد.

+

+ {{ createdOrder ? 'فاکتور شما ثبت شد.' : 'آماده ثبت فاکتور نقدی' }} +

{{ expiryMessage }}

@@ -128,8 +138,12 @@ async function registerReceipt() {
@@ -142,9 +156,13 @@ async function registerReceipt() {
-

فاکتور شما ثبت شد.

+

+ {{ createdOrder ? 'فاکتور شما ثبت شد.' : 'آماده ثبت فاکتور نقدی' }} +

+ +

{{ accountsSectionTitle }}

@@ -166,8 +184,12 @@ async function registerReceipt() {
- مشاهده سفارش - ثبت رسید پرداخت + + ثبت و مشاهده سفارش + + + ثبت سفارش و رسید پرداخت +
diff --git a/src/views/checkout/CheckListView.vue b/src/views/checkout/CheckListView.vue index 033a702..8868115 100644 --- a/src/views/checkout/CheckListView.vue +++ b/src/views/checkout/CheckListView.vue @@ -1,10 +1,11 @@ @@ -127,6 +130,8 @@ async function submitOrder() {