Files
fabric_trade_user/src/views/cart/components/MobileCartPage.vue
T
mohmdsdgandCursor 7acd225fad Move settlement after invoice and wire real notification inbox.
Submit orders without choosing payment first, route cash/check flows under /orders/:id, show status-based next actions, and connect the header bell to unread notifications.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-09 12:00:18 +03:30

261 lines
6.3 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import BaseButton from '@/components/ui/BaseButton.vue'
import EmptyState from '@/components/ui/EmptyState.vue'
import IconTrash from '@/components/icons/IconTrash.vue'
import IconChevronBack from '@/components/icons/IconChevronBack.vue'
import { formatMeterage, formatNumber } from '@/utils/format'
import type { CartItem } from '@/types'
defineProps<{
items: CartItem[]
companyName: string
totalMeterage: number
maxMeterage: number
remainingCapacity: number
isEmpty: boolean
submitting?: boolean
}>()
const emit = defineEmits<{
back: []
remove: [id: string]
checkout: []
selectCompany: []
}>()
</script>
<template>
<div class="cart-mobile-page">
<header class="cart-mobile-page__nav">
<button type="button" class="nav-btn" aria-label="بازگشت" @click="emit('back')">
<IconChevronBack :size="20" />
</button>
<h1 class="cart-mobile-page__title">سبد خرید</h1>
<button type="button" class="nav-btn nav-btn--ghost" aria-hidden="true" tabindex="-1">
<IconChevronBack :size="18" class="nav-btn__flip" />
</button>
</header>
<div v-if="!isEmpty" class="cart-mobile-page__body">
<p class="cart-mobile-page__company">
{{ companyName ? `شرکت‌ها: ${companyName}` : 'سبد خرید مشترک' }}
</p>
<div class="cart-mobile-page__scroll">
<div class="cart-mobile-table">
<div class="cart-mobile-table__head">
<span>محصول</span>
<span>متراژ (متر)</span>
<span>حذف</span>
</div>
<div v-for="item in items" :key="item.id" class="cart-mobile-table__row">
<div class="col-product">
<strong>{{ item.productName }}</strong>
<span>کد: {{ item.productCode }}</span>
<span v-if="item.companyName" class="col-product__company">{{ item.companyName }}</span>
</div>
<div class="col-meterage">{{ formatNumber(item.meterage) }}</div>
<div class="col-delete">
<button type="button" aria-label="حذف" @click="emit('remove', item.id)">
<IconTrash :size="20" />
</button>
</div>
</div>
</div>
</div>
<div class="cart-mobile-page__footer">
<div class="cart-mobile-summary">
<div class="cart-mobile-summary__row">
<span>جمع متراژ</span>
<strong>{{ formatMeterage(totalMeterage) }}</strong>
</div>
<div class="cart-mobile-summary__row">
<span>حداکثر مجاز</span>
<strong>{{ formatMeterage(maxMeterage) }}</strong>
</div>
<div class="cart-mobile-summary__row">
<span>باقی مانده</span>
<strong>{{ formatMeterage(remainingCapacity) }}</strong>
</div>
</div>
<p class="cart-mobile-page__hint">
پس از ثبت، مدیریت سفارش را قیمت‌گذاری می‌کند و فاکتور برای انتخاب روش تسویه به شما اعلام
می‌شود.
</p>
<BaseButton block :loading="submitting" @click="emit('checkout')">ثبت سفارش</BaseButton>
</div>
</div>
<EmptyState v-else variant="cart" message="برای شروع سفارش، یک شرکت انتخاب کنید">
<BaseButton @click="emit('selectCompany')">انتخاب شرکت</BaseButton>
</EmptyState>
</div>
</template>
<style scoped>
.cart-mobile-page {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
width: 100%;
background: var(--color-bg);
color: var(--color-text);
padding: 12px 0 0;
overflow: hidden;
}
.cart-mobile-page__nav {
display: grid;
grid-template-columns: 40px 1fr 40px;
align-items: center;
margin-bottom: 12px;
}
.cart-mobile-page__hint {
margin: 0 0 10px;
font-size: 0.75rem;
line-height: 1.6;
color: var(--color-text-muted);
}
.cart-mobile-page__title {
margin: 0;
font-size: 1.0625rem;
font-weight: 700;
text-align: center;
color: var(--color-text);
}
.nav-btn {
width: 40px;
height: 40px;
border: none;
background: none;
color: var(--color-text);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.nav-btn--ghost {
visibility: hidden;
}
.nav-btn__flip {
transform: scaleX(-1);
}
.cart-mobile-page__body {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.cart-mobile-page__company {
margin: 0 0 16px;
font-size: 0.875rem;
color: var(--color-text-muted);
}
.cart-mobile-page__scroll {
flex: 1;
min-height: 0;
overflow-y: auto;
}
.cart-mobile-table {
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
overflow: hidden;
background: var(--color-elevated);
}
.cart-mobile-table__head,
.cart-mobile-table__row {
display: grid;
grid-template-columns: 1fr 88px 52px;
gap: 8px;
padding: 10px 12px;
align-items: center;
}
.cart-mobile-table__head {
background: var(--color-summary-bg);
font-size: 0.75rem;
font-weight: 600;
color: var(--color-text-muted);
}
.cart-mobile-table__row {
border-top: 1px solid var(--color-border);
color: var(--color-text);
}
.col-product strong {
display: block;
font-size: 0.875rem;
}
.col-product span {
display: block;
font-size: 0.75rem;
color: var(--color-text-muted);
}
.col-product__company {
margin-top: 2px;
color: var(--color-primary) !important;
font-weight: 600;
}
.col-meterage {
text-align: center;
font-weight: 700;
}
.col-delete {
display: flex;
justify-content: center;
}
.col-delete button {
border: none;
background: none;
cursor: pointer;
color: var(--color-text-muted);
}
.cart-mobile-page__footer {
flex-shrink: 0;
margin: 0;
padding: 12px 0 calc(12px + env(safe-area-inset-bottom, 0));
border-top: 1px solid var(--color-border);
background: var(--color-bg);
}
.cart-mobile-summary {
margin-bottom: 12px;
padding: 14px 16px;
background: var(--color-elevated);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
color: var(--color-text);
box-shadow: var(--shadow-sm);
}
.cart-mobile-summary__row {
display: flex;
justify-content: space-between;
padding: 8px 0;
font-size: 0.875rem;
}
.cart-mobile-summary__row:not(:last-child) {
border-bottom: 1px solid var(--color-border);
}
</style>