Allow multi-company carts to submit as one checkout creating one order per company.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,6 +15,7 @@ export function useCartPage() {
|
||||
const items = computed(() => cartStore.activeCart?.items ?? [])
|
||||
const isEmpty = computed(() => items.value.length === 0)
|
||||
const companyName = computed(() => cartStore.companyNamesLabel || cartStore.activeCart?.companyName || '')
|
||||
const companySummaries = computed(() => cartStore.companySummaries)
|
||||
|
||||
async function removeItem(itemId: string) {
|
||||
const item = items.value.find((entry) => entry.id === itemId)
|
||||
@@ -40,17 +41,25 @@ export function useCartPage() {
|
||||
submitting.value = true
|
||||
submitError.value = ''
|
||||
try {
|
||||
// همگامسازی سبد با سرور قبل از ثبت تا productId/companyId کهنه نباشد
|
||||
await cartStore.hydrate()
|
||||
if (!cartStore.activeCart?.items.length) {
|
||||
submitError.value = 'سبد خرید خالی است یا با سرور همگام نشد.'
|
||||
return
|
||||
}
|
||||
const order = await orderStore.submitOrder(cartStore.activeCart)
|
||||
const created = await orderStore.submitOrder(cartStore.activeCart)
|
||||
await cartStore.hydrate()
|
||||
router.replace(`/orders/${order.id}/success`)
|
||||
if (created.length === 1) {
|
||||
router.replace(`/orders/${created[0]!.id}/success`)
|
||||
return
|
||||
}
|
||||
// چند شرکت → چند سفارش؛ به لیست سفارشها برو
|
||||
router.replace({
|
||||
path: '/orders',
|
||||
query: { submitted: String(created.length) },
|
||||
})
|
||||
} catch (e) {
|
||||
submitError.value = e instanceof Error ? e.message : 'ثبت سفارش ناموفق بود.'
|
||||
await cartStore.hydrate()
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
@@ -90,6 +99,7 @@ export function useCartPage() {
|
||||
items,
|
||||
isEmpty,
|
||||
companyName,
|
||||
companySummaries,
|
||||
showFullDialog,
|
||||
submitting,
|
||||
submitError,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { computed, ref, watch, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useOrderStore } from '@/stores/order'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useCatalogStore } from '@/stores/catalog'
|
||||
@@ -12,22 +12,43 @@ import {
|
||||
matchesMobileOrderTab,
|
||||
type DesktopOrderFilterId,
|
||||
} from '@/utils/orderStatusGroups'
|
||||
import { toPersianDigits } from '@/utils/format'
|
||||
|
||||
const DESKTOP_PAGE_SIZE = 5
|
||||
const MOBILE_PAGE_SIZE = 5
|
||||
|
||||
export function useOrderList() {
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const orderStore = useOrderStore()
|
||||
const authStore = useAuthStore()
|
||||
const catalogStore = useCatalogStore()
|
||||
const currentPage = ref(1)
|
||||
const mobilePage = ref(1)
|
||||
const submitSuccessMessage = ref('')
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([orderStore.hydrate(), catalogStore.loadCompanies()])
|
||||
})
|
||||
|
||||
watch(
|
||||
() => route.query.submitted,
|
||||
(submitted) => {
|
||||
const count = Number(submitted)
|
||||
if (!Number.isFinite(count) || count < 1) {
|
||||
submitSuccessMessage.value = ''
|
||||
return
|
||||
}
|
||||
submitSuccessMessage.value =
|
||||
count === 1
|
||||
? 'پیشسفارش با موفقیت ثبت شد.'
|
||||
: `${toPersianDigits(String(count))} پیشسفارش (برای شرکتهای مختلف) ثبت شد.`
|
||||
const { submitted: _submitted, ...rest } = route.query
|
||||
void router.replace({ query: rest })
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
const tab = computed({
|
||||
get: () => (router.currentRoute.value.query.tab as string) ?? 'all',
|
||||
set: (v: string) => router.replace({ query: { ...router.currentRoute.value.query, tab: v } }),
|
||||
@@ -202,6 +223,7 @@ export function useOrderList() {
|
||||
mobilePage,
|
||||
companySlug,
|
||||
iconVariant,
|
||||
submitSuccessMessage,
|
||||
goToOrder,
|
||||
setPage,
|
||||
setMobilePage,
|
||||
|
||||
+53
-12
@@ -45,30 +45,70 @@ export const useCartStore = defineStore('cart', () => {
|
||||
|
||||
const itemCount = computed(() => activeCart.value?.items.length ?? 0)
|
||||
|
||||
const catalogStore = useCatalogStore()
|
||||
|
||||
const companyNamesLabel = computed(() => {
|
||||
if (!activeCart.value?.items.length) return ''
|
||||
return uniqueCompanyNames(activeCart.value.items)
|
||||
})
|
||||
|
||||
const catalogStore = useCatalogStore()
|
||||
const companySummaries = computed(() => {
|
||||
const cart = activeCart.value
|
||||
if (!cart?.items.length) return [] as {
|
||||
companyId: string
|
||||
companyName: string
|
||||
meterage: number
|
||||
maxMeterage: number
|
||||
remaining: number
|
||||
}[]
|
||||
|
||||
const byCompany = new Map<string, { companyName: string; meterage: number }>()
|
||||
for (const item of cart.items) {
|
||||
const current = byCompany.get(item.companyId)
|
||||
if (current) {
|
||||
current.meterage += item.meterage
|
||||
} else {
|
||||
byCompany.set(item.companyId, {
|
||||
companyName: item.companyName || 'شرکت',
|
||||
meterage: item.meterage,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return [...byCompany.entries()].map(([companyId, info]) => {
|
||||
const max =
|
||||
catalogStore.getCompany(companyId)?.maxMeteragePerInvoice ?? DEFAULT_MAX_METERAGE
|
||||
return {
|
||||
companyId,
|
||||
companyName: info.companyName,
|
||||
meterage: info.meterage,
|
||||
maxMeterage: max,
|
||||
remaining: Math.max(0, max - info.meterage),
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
/** سقف نمایشی: مجموع سقف شرکتهای داخل سبد (هر شرکت جداگانه محدود میشود). */
|
||||
const maxMeterage = computed(() => {
|
||||
if (!activeCart.value?.items.length) {
|
||||
if (!companySummaries.value.length) {
|
||||
const selected = selectedCompanyId.value
|
||||
? catalogStore.getCompany(selectedCompanyId.value)
|
||||
: null
|
||||
return selected?.maxMeteragePerInvoice ?? DEFAULT_MAX_METERAGE
|
||||
}
|
||||
|
||||
const companyIds = [...new Set(activeCart.value.items.map((item) => item.companyId))]
|
||||
return companyIds.reduce((sum, id) => {
|
||||
const company = catalogStore.getCompany(id)
|
||||
return sum + (company?.maxMeteragePerInvoice ?? DEFAULT_MAX_METERAGE)
|
||||
}, 0)
|
||||
return companySummaries.value.reduce((sum, row) => sum + row.maxMeterage, 0)
|
||||
})
|
||||
|
||||
const remainingCapacity = computed(() => Math.max(0, maxMeterage.value - totalMeterage.value))
|
||||
const isFull = computed(() => totalMeterage.value >= maxMeterage.value)
|
||||
const remainingCapacity = computed(() =>
|
||||
companySummaries.value.length
|
||||
? companySummaries.value.reduce((sum, row) => sum + row.remaining, 0)
|
||||
: Math.max(0, maxMeterage.value - totalMeterage.value),
|
||||
)
|
||||
|
||||
/** وقتی حداقل یک شرکت به سقف خودش رسیده باشد. */
|
||||
const isFull = computed(() =>
|
||||
companySummaries.value.some((row) => row.meterage >= row.maxMeterage),
|
||||
)
|
||||
|
||||
function applyServerCart(serverCart: ApiCart) {
|
||||
const cart: Cart = {
|
||||
@@ -178,8 +218,8 @@ export const useCartStore = defineStore('cart', () => {
|
||||
|
||||
replaceActiveCart({
|
||||
id: cart.id || 'local',
|
||||
companyId: company.id,
|
||||
companyName: company.name,
|
||||
companyId: items[0]?.companyId || company.id,
|
||||
companyName: uniqueCompanyNames(items) || company.name,
|
||||
items,
|
||||
notes: cart.notes,
|
||||
})
|
||||
@@ -349,6 +389,7 @@ export const useCartStore = defineStore('cart', () => {
|
||||
totalMeterage,
|
||||
itemCount,
|
||||
companyNamesLabel,
|
||||
companySummaries,
|
||||
maxMeterage,
|
||||
remainingCapacity,
|
||||
isFull,
|
||||
|
||||
+35
-27
@@ -117,8 +117,9 @@ export const useOrderStore = defineStore('order', () => {
|
||||
/**
|
||||
* سفارش بدون روش تسویه ثبت میشود؛ مشتری بعد از قیمتگذاری مدیریت
|
||||
* روش تسویه را انتخاب میکند.
|
||||
* سبد چندشرکتی: برای هر شرکت یک سفارش جدا ساخته میشود.
|
||||
*/
|
||||
async function submitOrder(cart: Cart): Promise<Order> {
|
||||
async function submitOrder(cart: Cart): Promise<Order[]> {
|
||||
if (!cart.items.length) {
|
||||
throw new Error('سبد خرید خالی است.')
|
||||
}
|
||||
@@ -126,43 +127,50 @@ export const useOrderStore = defineStore('order', () => {
|
||||
throw new Error('سبد خرید با سرور همگام نیست. لطفاً دوباره محصولات را به سبد اضافه کنید.')
|
||||
}
|
||||
|
||||
// شرکت را از خود آیتمها بگیر؛ هدر سبد گاهی با شرکت واقعی آیتمها ناسازگار است.
|
||||
const companyIds = [
|
||||
...new Set(cart.items.map((item) => item.companyId).filter(Boolean)),
|
||||
]
|
||||
if (!companyIds.length) {
|
||||
throw new Error('شرکت سبد مشخص نیست. سبد را خالی کنید و دوباره اضافه کنید.')
|
||||
}
|
||||
if (companyIds.length > 1) {
|
||||
throw new Error(
|
||||
'سبد شامل چند شرکت است. فعلاً فقط اقلام یک شرکت را نگه دارید و ثبت کنید.',
|
||||
)
|
||||
}
|
||||
|
||||
const companyId = companyIds[0]!
|
||||
const itemsForOrder = cart.items.filter((item) => item.companyId === companyId)
|
||||
|
||||
const body = {
|
||||
companyId,
|
||||
notes: cart.notes,
|
||||
items: itemsForOrder.map((item) => ({
|
||||
productId: item.productId,
|
||||
meterage: Number(item.meterage),
|
||||
notes: item.notes,
|
||||
})),
|
||||
}
|
||||
|
||||
const createdOrders: Order[] = []
|
||||
try {
|
||||
const order = await apiRequest<Order>('/orders', {
|
||||
method: 'POST',
|
||||
body,
|
||||
})
|
||||
orders.value.unshift(order)
|
||||
clearCheckDraft()
|
||||
return order
|
||||
for (const companyId of companyIds) {
|
||||
const itemsForOrder = cart.items.filter((item) => item.companyId === companyId)
|
||||
if (!itemsForOrder.length) continue
|
||||
|
||||
const order = await apiRequest<Order>('/orders', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
companyId,
|
||||
notes: cart.notes,
|
||||
items: itemsForOrder.map((item) => ({
|
||||
productId: item.productId,
|
||||
meterage: Number(item.meterage),
|
||||
notes: item.notes,
|
||||
})),
|
||||
},
|
||||
})
|
||||
orders.value.unshift(order)
|
||||
createdOrders.push(order)
|
||||
}
|
||||
} catch (e) {
|
||||
if (createdOrders.length) {
|
||||
// بخشی ثبت شده؛ سفارشهای موفق را نگه میداریم و خطا را با توضیح برمیگردانیم
|
||||
clearCheckDraft()
|
||||
const names = createdOrders.map((o) => o.orderNumber).join('، ')
|
||||
throw new Error(
|
||||
e instanceof ApiError
|
||||
? `${e.message} (سفارشهای ثبتشده: ${names})`
|
||||
: `ثبت بخشی از سفارشها ناموفق بود. ثبتشده: ${names}`,
|
||||
)
|
||||
}
|
||||
throw new Error(e instanceof ApiError ? e.message : 'ثبت سفارش ناموفق بود.')
|
||||
}
|
||||
|
||||
clearCheckDraft()
|
||||
return createdOrders
|
||||
}
|
||||
|
||||
/** انتخاب روش تسویه پس از صدور فاکتور. */
|
||||
|
||||
+62
-34
@@ -25,6 +25,7 @@ const {
|
||||
mobilePage,
|
||||
companySlug,
|
||||
iconVariant,
|
||||
submitSuccessMessage,
|
||||
goToOrder,
|
||||
setPage,
|
||||
setMobilePage,
|
||||
@@ -49,39 +50,66 @@ const desktopFilterTabs: { id: DesktopOrderFilterId; label: string }[] = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MobileOrdersPage
|
||||
class="mobile-only"
|
||||
:tab="tab"
|
||||
:tabs="mobileTabs"
|
||||
:orders="paginatedOrdersMobile"
|
||||
:total-count="filteredOrdersMobile.length"
|
||||
:current-page="mobilePage"
|
||||
:total-pages="mobileTotalPages"
|
||||
:pagination-range="mobilePaginationRange"
|
||||
:visible-pages="mobileVisiblePages"
|
||||
:company-slug="companySlug"
|
||||
:icon-variant="iconVariant"
|
||||
@update:tab="tab = $event"
|
||||
@select="goToOrder"
|
||||
@back="router.push('/')"
|
||||
@set-page="setMobilePage"
|
||||
/>
|
||||
<div class="orders-view">
|
||||
<p v-if="submitSuccessMessage" class="orders-view__success" role="status">
|
||||
{{ submitSuccessMessage }}
|
||||
</p>
|
||||
|
||||
<DesktopOrdersPage
|
||||
class="desktop-only"
|
||||
:stats="stats"
|
||||
:desktop-filter="desktopFilter"
|
||||
:desktop-filter-tabs="desktopFilterTabs"
|
||||
:filtered-orders="filteredOrdersDesktop"
|
||||
:paginated-orders="paginatedOrders"
|
||||
:pagination-range="paginationRange"
|
||||
:visible-pages="visiblePages"
|
||||
:current-page="currentPage"
|
||||
:total-pages="totalPages"
|
||||
@view-stat-filter="viewStatFilter"
|
||||
@set-desktop-filter="setDesktopFilter"
|
||||
@select="goToOrder"
|
||||
@set-page="setPage"
|
||||
@new-order="router.push('/')"
|
||||
/>
|
||||
<MobileOrdersPage
|
||||
class="mobile-only"
|
||||
:tab="tab"
|
||||
:tabs="mobileTabs"
|
||||
:orders="paginatedOrdersMobile"
|
||||
:total-count="filteredOrdersMobile.length"
|
||||
:current-page="mobilePage"
|
||||
:total-pages="mobileTotalPages"
|
||||
:pagination-range="mobilePaginationRange"
|
||||
:visible-pages="mobileVisiblePages"
|
||||
:company-slug="companySlug"
|
||||
:icon-variant="iconVariant"
|
||||
@update:tab="tab = $event"
|
||||
@select="goToOrder"
|
||||
@back="router.push('/')"
|
||||
@set-page="setMobilePage"
|
||||
/>
|
||||
|
||||
<DesktopOrdersPage
|
||||
class="desktop-only"
|
||||
:stats="stats"
|
||||
:desktop-filter="desktopFilter"
|
||||
:desktop-filter-tabs="desktopFilterTabs"
|
||||
:filtered-orders="filteredOrdersDesktop"
|
||||
:paginated-orders="paginatedOrders"
|
||||
:pagination-range="paginationRange"
|
||||
:visible-pages="visiblePages"
|
||||
:current-page="currentPage"
|
||||
:total-pages="totalPages"
|
||||
@view-stat-filter="viewStatFilter"
|
||||
@set-desktop-filter="setDesktopFilter"
|
||||
@select="goToOrder"
|
||||
@set-page="setPage"
|
||||
@new-order="router.push('/')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.orders-view {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.orders-view__success {
|
||||
margin: 0 var(--page-padding) 12px;
|
||||
padding: 12px 14px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-success-soft);
|
||||
border: 1px solid color-mix(in srgb, var(--color-success) 35%, transparent);
|
||||
color: var(--color-success);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,6 +13,7 @@ const {
|
||||
items,
|
||||
isEmpty,
|
||||
companyName,
|
||||
companySummaries,
|
||||
showFullDialog,
|
||||
submitting,
|
||||
submitError,
|
||||
@@ -40,6 +41,7 @@ function goToOrdering() {
|
||||
class="mobile-only"
|
||||
:items="items"
|
||||
:company-name="companyName"
|
||||
:company-summaries="companySummaries"
|
||||
:total-meterage="cartStore.totalMeterage"
|
||||
:max-meterage="cartStore.maxMeterage"
|
||||
:remaining-capacity="cartStore.remainingCapacity"
|
||||
@@ -55,6 +57,7 @@ function goToOrdering() {
|
||||
class="desktop-only"
|
||||
:items="items"
|
||||
:company-name="companyName"
|
||||
:company-summaries="companySummaries"
|
||||
:total-meterage="cartStore.totalMeterage"
|
||||
:max-meterage="cartStore.maxMeterage"
|
||||
:remaining-capacity="cartStore.remainingCapacity"
|
||||
@@ -70,7 +73,7 @@ function goToOrdering() {
|
||||
<div class="dialog card">
|
||||
<h3>سقف متراژ تکمیل شد</h3>
|
||||
<p class="text-sm">
|
||||
سقف متراژ این فاکتور تکمیل شده است. آیا مایلید ادامه محصولات را در فاکتور جدید ثبت کنید؟
|
||||
سقف متراژ حداقل یک شرکت در سبد پر شده است. میتوانید همین پیشسفارشها را ثبت کنید یا سبد را خالی کرده و فاکتور جدید بسازید.
|
||||
</p>
|
||||
<div class="dialog-actions">
|
||||
<BaseButton variant="outline" :loading="submitting" @click="proceedAnyway">
|
||||
|
||||
@@ -16,6 +16,13 @@ import type { CartItem } from '@/types'
|
||||
defineProps<{
|
||||
items: CartItem[]
|
||||
companyName: string
|
||||
companySummaries?: {
|
||||
companyId: string
|
||||
companyName: string
|
||||
meterage: number
|
||||
maxMeterage: number
|
||||
remaining: number
|
||||
}[]
|
||||
totalMeterage: number
|
||||
maxMeterage: number
|
||||
remainingCapacity: number
|
||||
@@ -156,6 +163,17 @@ const quickLinks = [
|
||||
</span>
|
||||
<strong>{{ formatMeterage(totalMeterage) }}</strong>
|
||||
</div>
|
||||
<div
|
||||
v-for="row in companySummaries ?? []"
|
||||
:key="row.companyId"
|
||||
class="cart-summary-card__row cart-summary-card__row--sub"
|
||||
>
|
||||
<span class="cart-summary-card__row-label">{{ row.companyName }}</span>
|
||||
<strong>
|
||||
{{ formatMeterage(row.meterage) }}
|
||||
<span class="cart-summary-card__cap">/ {{ formatMeterage(row.maxMeterage) }}</span>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="cart-summary-card__row cart-summary-card__row--hint">
|
||||
<span class="cart-summary-card__row-label">
|
||||
<IconOrders :size="16" />
|
||||
@@ -176,7 +194,7 @@ const quickLinks = [
|
||||
{{ submitting ? 'در حال ثبت…' : 'ثبت پیشسفارش' }}
|
||||
</button>
|
||||
<p class="cart-summary-card__note">
|
||||
قیمتگذاری توسط مدیریت انجام میشود؛ پس از صدور فاکتور روش تسویه را انتخاب میکنید.
|
||||
اقلام همه شرکتها در یک سبد هستند؛ با ثبت، برای هر شرکت یک پیشسفارش جدا ساخته میشود.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -483,6 +501,17 @@ const quickLinks = [
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.cart-summary-card__row--sub {
|
||||
padding-block: 6px;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.cart-summary-card__cap {
|
||||
font-weight: 500;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.cart-summary-card__row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,13 @@ import type { CartItem } from '@/types'
|
||||
defineProps<{
|
||||
items: CartItem[]
|
||||
companyName: string
|
||||
companySummaries?: {
|
||||
companyId: string
|
||||
companyName: string
|
||||
meterage: number
|
||||
maxMeterage: number
|
||||
remaining: number
|
||||
}[]
|
||||
totalMeterage: number
|
||||
maxMeterage: number
|
||||
remainingCapacity: number
|
||||
@@ -67,10 +74,23 @@ const emit = defineEmits<{
|
||||
<div class="cart-mobile-page__footer">
|
||||
<div class="cart-mobile-summary">
|
||||
<div class="cart-mobile-summary__row">
|
||||
<span>جمع متراژ</span>
|
||||
<span>جمع متراژ کل</span>
|
||||
<strong>{{ formatMeterage(totalMeterage) }}</strong>
|
||||
</div>
|
||||
<div class="cart-mobile-summary__row">
|
||||
<template v-if="companySummaries?.length">
|
||||
<div
|
||||
v-for="row in companySummaries"
|
||||
:key="row.companyId"
|
||||
class="cart-mobile-summary__row cart-mobile-summary__row--sub"
|
||||
>
|
||||
<span>{{ row.companyName }}</span>
|
||||
<strong>
|
||||
{{ formatMeterage(row.meterage) }}
|
||||
<span class="cart-mobile-summary__cap">/ {{ formatMeterage(row.maxMeterage) }}</span>
|
||||
</strong>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="cart-mobile-summary__row">
|
||||
<span>حداکثر مجاز</span>
|
||||
<strong>{{ formatMeterage(maxMeterage) }}</strong>
|
||||
</div>
|
||||
@@ -80,8 +100,7 @@ const emit = defineEmits<{
|
||||
</div>
|
||||
</div>
|
||||
<p class="cart-mobile-page__hint">
|
||||
پس از ثبت، مدیریت سفارش را قیمتگذاری میکند و فاکتور برای انتخاب روش تسویه به شما اعلام
|
||||
میشود.
|
||||
پس از ثبت، برای هر شرکت یک پیشسفارش جداگانه ساخته میشود و مدیریت قیمتگذاری میکند.
|
||||
</p>
|
||||
<BaseButton block :loading="submitting" @click="emit('checkout')">ثبت پیشسفارش</BaseButton>
|
||||
</div>
|
||||
@@ -250,10 +269,22 @@ const emit = defineEmits<{
|
||||
.cart-mobile-summary__row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 8px 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.cart-mobile-summary__row--sub {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.cart-mobile-summary__cap {
|
||||
font-weight: 500;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.cart-mobile-summary__row:not(:last-child) {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user