feat: step-by-step quote flow like logistics project
All checks were successful
Build Docker Image / build (push) Successful in 5m11s
All checks were successful
Build Docker Image / build (push) Successful in 5m11s
New pages: /catalog/product → /catalog/destination → /catalog/quantity → /catalog/results Each step has fullscreen map + white bottom sheet card (rounded-t-3xl). Header capsule in quote mode now navigates between steps. i18n keys added for step titles (en/ru).
This commit is contained in:
@@ -42,15 +42,15 @@
|
||||
>
|
||||
{{ $t('catalog.modes.explore') }}
|
||||
</button>
|
||||
<button
|
||||
<NuxtLink
|
||||
:to="localePath('/catalog/product')"
|
||||
class="px-3 py-1 text-sm font-medium rounded-full transition-colors"
|
||||
:class="showActiveMode && catalogMode === 'quote' && !isClientArea
|
||||
:class="isQuoteStepPage
|
||||
? (useWhiteText ? 'bg-white/20 text-white' : 'bg-base-300 text-base-content')
|
||||
: (useWhiteText ? 'text-white/70 hover:text-white hover:bg-white/10' : 'text-base-content/70 hover:text-base-content hover:bg-base-200')"
|
||||
@click="$emit('set-catalog-mode', 'quote')"
|
||||
>
|
||||
{{ $t('catalog.modes.quote') }}
|
||||
</button>
|
||||
</NuxtLink>
|
||||
<!-- Role switcher: Я клиент + dropdown -->
|
||||
<div v-if="loggedIn" class="flex items-center">
|
||||
<NuxtLink
|
||||
@@ -139,49 +139,39 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Quote mode: Simple segmented input with search inside (white glass) -->
|
||||
<!-- Quote mode: Step-based capsule navigation (like logistics) -->
|
||||
<template v-else-if="catalogMode === 'quote'">
|
||||
<div class="flex items-center w-full rounded-full pill-glass overflow-hidden">
|
||||
<!-- Product segment -->
|
||||
<button
|
||||
class="flex-1 px-4 py-2 text-left hover:bg-base-200/50 rounded-l-full transition-colors min-w-0"
|
||||
@click="$emit('edit-token', 'product')"
|
||||
<NuxtLink
|
||||
:to="localePath('/catalog/product')"
|
||||
class="flex-1 px-4 py-2 text-left hover:bg-white/10 rounded-l-full transition-colors min-w-0"
|
||||
>
|
||||
<div class="text-xs text-base-content/60">{{ $t('catalog.filters.product') }}</div>
|
||||
<span class="text-[10px] font-bold uppercase tracking-wider opacity-60">{{ $t('catalog.filters.product') }}</span>
|
||||
<div class="font-medium truncate text-base-content">{{ productLabel || $t('catalog.quote.selectProduct') }}</div>
|
||||
</button>
|
||||
<div class="w-px h-8 bg-white/20 self-center" />
|
||||
</NuxtLink>
|
||||
<div class="w-px h-8 bg-base-300/40 self-center" />
|
||||
<!-- Hub segment -->
|
||||
<button
|
||||
class="flex-1 px-4 py-2 text-left hover:bg-base-200/50 transition-colors min-w-0"
|
||||
@click="$emit('edit-token', 'hub')"
|
||||
<NuxtLink
|
||||
:to="localePath('/catalog/destination')"
|
||||
class="flex-1 px-4 py-2 text-left hover:bg-white/10 transition-colors min-w-0"
|
||||
>
|
||||
<div class="text-xs text-base-content/60">{{ $t('catalog.filters.hub') }}</div>
|
||||
<span class="text-[10px] font-bold uppercase tracking-wider opacity-60">{{ $t('catalog.filters.hub') }}</span>
|
||||
<div class="font-medium truncate text-base-content">{{ hubLabel || $t('catalog.quote.selectHub') }}</div>
|
||||
</button>
|
||||
<div class="w-px h-8 bg-white/20 self-center" />
|
||||
<!-- Quantity segment (inline input) -->
|
||||
<div class="flex-1 px-4 py-2 min-w-0">
|
||||
<div class="text-xs text-base-content/60">{{ $t('catalog.filters.quantity') }}</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<input
|
||||
v-model="localQuantity"
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.1"
|
||||
placeholder="—"
|
||||
class="w-16 font-medium bg-transparent outline-none text-base-content [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
||||
@blur="$emit('update-quantity', localQuantity)"
|
||||
@keyup.enter="$emit('update-quantity', localQuantity)"
|
||||
/>
|
||||
<span v-if="localQuantity" class="text-base-content/60 text-sm">{{ $t('units.t') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Search button inside -->
|
||||
</NuxtLink>
|
||||
<div class="w-px h-8 bg-base-300/40 self-center" />
|
||||
<!-- Quantity segment -->
|
||||
<NuxtLink
|
||||
:to="localePath('/catalog/quantity')"
|
||||
class="flex-1 px-4 py-2 text-left hover:bg-white/10 transition-colors min-w-0"
|
||||
>
|
||||
<span class="text-[10px] font-bold uppercase tracking-wider opacity-60">{{ $t('catalog.filters.quantity') }}</span>
|
||||
<div class="font-medium truncate text-base-content">{{ quantity || '—' }} {{ quantity ? $t('units.t') : '' }}</div>
|
||||
</NuxtLink>
|
||||
<!-- Search button -->
|
||||
<button
|
||||
class="btn btn-primary btn-circle m-1"
|
||||
:disabled="!canSearch"
|
||||
@click="$emit('search')"
|
||||
@click="navigateToSearch"
|
||||
>
|
||||
<Icon name="lucide:search" size="18" />
|
||||
</button>
|
||||
@@ -449,6 +439,22 @@ const switchLocalePath = useSwitchLocalePath()
|
||||
const { t } = useI18n()
|
||||
const { chatOpen } = toRefs(props)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// Check if we're on a quote step page
|
||||
const isQuoteStepPage = computed(() => {
|
||||
const path = route.path
|
||||
return path.includes('/catalog/product') ||
|
||||
path.includes('/catalog/destination') ||
|
||||
path.includes('/catalog/quantity') ||
|
||||
path.includes('/catalog/results')
|
||||
})
|
||||
|
||||
// Navigate to search results (quote mode step flow)
|
||||
const navigateToSearch = () => {
|
||||
router.push(localePath('/catalog/product'))
|
||||
}
|
||||
|
||||
// Check if client area tab is active
|
||||
const isClientAreaTabActive = (path: string) => {
|
||||
const currentPath = route.path
|
||||
|
||||
Reference in New Issue
Block a user