Compare commits
No commits in common. "55103d3778666e4234d23a98efb21058c4b1d1a3" and "436f537166f9be3471038934a3b19d7d16fc33ae" have entirely different histories.
55103d3778
...
436f537166
@ -1,81 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="delivery__search">
|
|
||||||
<UInput
|
|
||||||
v-model="searchTerm"
|
|
||||||
size="xl"
|
|
||||||
class="w-full"
|
|
||||||
placeholder="Выберите пункт выдачи"
|
|
||||||
:ui="{ trailing: 'pe-1' }"
|
|
||||||
>
|
|
||||||
<template v-if="searchTerm?.length" #trailing>
|
|
||||||
<UButton
|
|
||||||
color="neutral"
|
|
||||||
variant="link"
|
|
||||||
size="sm"
|
|
||||||
icon="i-lucide-circle-x"
|
|
||||||
aria-label="Clear input"
|
|
||||||
@click="searchTerm = ''"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</UInput>
|
|
||||||
|
|
||||||
<div class="pickup-point-card__items">
|
|
||||||
<div
|
|
||||||
v-for="pickupPoint in filteredPoints"
|
|
||||||
:key="pickupPoint.id"
|
|
||||||
class="pickup-point-card"
|
|
||||||
@click="checkoutPickupPoint = pickupPoint"
|
|
||||||
>
|
|
||||||
<div class="pickup-point-card__content">
|
|
||||||
<h3>Yandex</h3>
|
|
||||||
<p>{{ `${pickupPoint?.address?.street} ${pickupPoint?.address?.house}` }}</p>
|
|
||||||
<h3>с day month бесплатно</h3>
|
|
||||||
</div>
|
|
||||||
<Icon class="pickup-point-card__action" name="lucide:chevron-right" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { PickupPoint } from '~/server/shared/types/yandex_pvz'
|
|
||||||
import { useCheckout } from '~/composables/useCheckout'
|
|
||||||
|
|
||||||
defineProps<{ filteredPoints: PickupPoint[] }>()
|
|
||||||
|
|
||||||
const { checkoutPickupPoint } = useCheckout()
|
|
||||||
const searchTerm = ref('')
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.pickup-point-card {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
padding: 20px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 16px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&__items {
|
|
||||||
height: calc(100dvh - 54px - 40px - 24px);
|
|
||||||
overflow-y: auto;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__action {
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -37,35 +37,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</YandexMapClusterer>
|
</YandexMapClusterer>
|
||||||
|
|
||||||
<YandexMapControls :settings="{ position: 'bottom left', orientation: 'vertical' }">
|
|
||||||
<YandexMapControl>
|
|
||||||
<div
|
|
||||||
class="control"
|
|
||||||
>
|
|
||||||
<UCheckbox
|
|
||||||
v-model="isFitting"
|
|
||||||
size="xl"
|
|
||||||
label="с примеркой"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</YandexMapControl>
|
|
||||||
</YandexMapControls>
|
|
||||||
|
|
||||||
<YandexMapControls :settings="{ position: 'bottom right', orientation: 'vertical' }">
|
|
||||||
<YandexMapControl>
|
|
||||||
<UTabs v-model="activeTab" :content="false" :items="tabs">
|
|
||||||
<template #map>
|
|
||||||
{{ activeTab === '0' ? 'Карта' : activeTab === '1' ? 'Список' : 'Другое' }}
|
|
||||||
</template>
|
|
||||||
</UTabs>
|
|
||||||
</YandexMapControl>
|
|
||||||
</YandexMapControls>
|
|
||||||
</YandexMap>
|
</YandexMap>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TabsItem } from '@nuxt/ui'
|
|
||||||
import type { LngLatBounds, YMap } from '@yandex/ymaps3-types'
|
import type { LngLatBounds, YMap } from '@yandex/ymaps3-types'
|
||||||
import type { YMapLocationRequest } from '@yandex/ymaps3-types/imperative/YMap'
|
import type { YMapLocationRequest } from '@yandex/ymaps3-types/imperative/YMap'
|
||||||
import type { YMapClusterer } from '@yandex/ymaps3-types/packages/clusterer'
|
import type { YMapClusterer } from '@yandex/ymaps3-types/packages/clusterer'
|
||||||
@ -75,8 +50,6 @@ import { computed, shallowRef } from 'vue'
|
|||||||
import {
|
import {
|
||||||
YandexMap,
|
YandexMap,
|
||||||
YandexMapClusterer,
|
YandexMapClusterer,
|
||||||
YandexMapControl,
|
|
||||||
YandexMapControls,
|
|
||||||
YandexMapDefaultFeaturesLayer,
|
YandexMapDefaultFeaturesLayer,
|
||||||
YandexMapDefaultSchemeLayer,
|
YandexMapDefaultSchemeLayer,
|
||||||
YandexMapMarker,
|
YandexMapMarker,
|
||||||
@ -84,9 +57,8 @@ import {
|
|||||||
|
|
||||||
const props = defineProps<{ modelValue: PickupPoint, pickupPoints: PickupPoint[] }>()
|
const props = defineProps<{ modelValue: PickupPoint, pickupPoints: PickupPoint[] }>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
defineEmits<{
|
||||||
(e: 'update:modelValue', value: PickupPoint | undefined): void
|
(e: 'update:modelValue', value: PickupPoint | undefined): void
|
||||||
(e: 'activeTab', value: string): void
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { coords } = useGeolocation()
|
const { coords } = useGeolocation()
|
||||||
@ -94,25 +66,6 @@ const clusterer = shallowRef<YMapClusterer | null>(null)
|
|||||||
const trueBounds = ref<LngLatBounds>([[0, 0], [0, 0]])
|
const trueBounds = ref<LngLatBounds>([[0, 0], [0, 0]])
|
||||||
const map = shallowRef<null | YMap>(null)
|
const map = shallowRef<null | YMap>(null)
|
||||||
|
|
||||||
const isFitting = ref(false)
|
|
||||||
const activeTab = ref('map')
|
|
||||||
const tabs = computed<TabsItem[]>(() =>
|
|
||||||
[
|
|
||||||
{
|
|
||||||
value: 'map',
|
|
||||||
label: activeTab.value === 'map' ? 'Карта' : '',
|
|
||||||
icon: 'lucide:map-pin',
|
|
||||||
slot: 'map' as const,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'list',
|
|
||||||
label: activeTab.value === 'list' ? 'Список' : '',
|
|
||||||
icon: 'i-lucide-list',
|
|
||||||
slot: 'list' as const,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
const hasCoords = computed(() => coords.value?.latitude !== Infinity && coords.value?.longitude !== Infinity)
|
const hasCoords = computed(() => coords.value?.latitude !== Infinity && coords.value?.longitude !== Infinity)
|
||||||
|
|
||||||
const location = ref<YMapLocationRequest>({
|
const location = ref<YMapLocationRequest>({
|
||||||
@ -136,10 +89,6 @@ watch(() => props.modelValue, (newPickupPoint) => {
|
|||||||
duration: 500,
|
duration: 500,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => activeTab.value, (newActiveTab) => {
|
|
||||||
emit('activeTab', newActiveTab)
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -207,10 +156,4 @@ watch(() => activeTab.value, (newActiveTab) => {
|
|||||||
background-color: #1e293b;
|
background-color: #1e293b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.control {
|
|
||||||
background: var(--ui-bg-elevated);
|
|
||||||
padding: 8px 18px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import type { PickupPoint } from '~/server/shared/types/yandex_pvz'
|
import type { PickupPoint } from '~/server/shared/types/yandex_pvz'
|
||||||
import { createSharedComposable, useMediaQuery, useStorage } from '@vueuse/core'
|
import { createSharedComposable, useStorage } from '@vueuse/core'
|
||||||
|
|
||||||
export const useCheckout = createSharedComposable(() => {
|
export const useCheckout = createSharedComposable(() => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const isMobile = useMediaQuery('(max-width: 1280px)')
|
|
||||||
|
|
||||||
const checkoutPickupPoint = useStorage<PickupPoint | undefined>(
|
const checkoutPickupPoint = useStorage<PickupPoint | undefined>(
|
||||||
'checkout-pickupPoint',
|
'checkout-pickupPoint',
|
||||||
@ -33,15 +32,15 @@ export const useCheckout = createSharedComposable(() => {
|
|||||||
const checkoutSteps = [
|
const checkoutSteps = [
|
||||||
{
|
{
|
||||||
step: 1,
|
step: 1,
|
||||||
title: isMobile.value ? 'mobileDelivery' : 'delivery',
|
title: 'delivery',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
step: 2,
|
step: 2,
|
||||||
title: isMobile.value ? 'mobileContacts' : 'contacts',
|
title: 'contacts',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
step: 3,
|
step: 3,
|
||||||
title: isMobile.value ? 'mobileSummary' : 'summary',
|
title: 'summary',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ export const useCheckout = createSharedComposable(() => {
|
|||||||
= ref(checkoutSteps.find(value => value.title === route.path.split('/').pop()) || checkoutSteps[0])
|
= ref(checkoutSteps.find(value => value.title === route.path.split('/').pop()) || checkoutSteps[0])
|
||||||
|
|
||||||
function previewStep() {
|
function previewStep() {
|
||||||
if (isPickupPointSelected.value && !isMobile.value) {
|
if (isPickupPointSelected.value) {
|
||||||
setCheckoutPickupPoint(undefined)
|
setCheckoutPickupPoint(undefined)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,10 +11,7 @@
|
|||||||
},
|
},
|
||||||
"checkoutSteps": {
|
"checkoutSteps": {
|
||||||
"delivery": "Выберите адрес получения заказа",
|
"delivery": "Выберите адрес получения заказа",
|
||||||
"mobileDelivery": "доставка",
|
|
||||||
"contacts": "Введите данные получателя",
|
"contacts": "Введите данные получателя",
|
||||||
"mobileContacts": "контакты",
|
"summary": "Подтвердите заказ"
|
||||||
"summary": "Подтвердите заказ",
|
|
||||||
"mobileSummary": "заказ"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,58 +1,66 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="coords" class="delivery">
|
<div v-if="coords" class="delivery">
|
||||||
<!-- Desktop -->
|
<div class="delivery__sidebar">
|
||||||
<div v-if="!isMobile" class="delivery__sidebar">
|
|
||||||
<DeliveryInfo v-if="isPickupPointSelected" />
|
<DeliveryInfo v-if="isPickupPointSelected" />
|
||||||
|
|
||||||
<DeliverySearch v-else :filtered-points="filteredPoints" />
|
<div v-else class="delivery__search">
|
||||||
|
<UInput
|
||||||
|
v-model="searchTerm"
|
||||||
|
size="xl"
|
||||||
|
class="w-full"
|
||||||
|
placeholder="Выберите пункт выдачи"
|
||||||
|
:ui="{ trailing: 'pe-1' }"
|
||||||
|
>
|
||||||
|
<template v-if="searchTerm?.length" #trailing>
|
||||||
|
<UButton
|
||||||
|
color="neutral"
|
||||||
|
variant="link"
|
||||||
|
size="sm"
|
||||||
|
icon="i-lucide-circle-x"
|
||||||
|
aria-label="Clear input"
|
||||||
|
@click="searchTerm = ''"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</UInput>
|
||||||
|
|
||||||
|
<div class="delivery__items">
|
||||||
|
<div
|
||||||
|
v-for="pickupPoint in filteredPoints"
|
||||||
|
:key="pickupPoint.id"
|
||||||
|
class="pickup-point-card"
|
||||||
|
@click="checkoutPickupPoint = pickupPoint"
|
||||||
|
>
|
||||||
|
<div class="pickup-point-card__content">
|
||||||
|
<h3>Yandex</h3>
|
||||||
|
<p>{{ `${pickupPoint?.address?.street} ${pickupPoint?.address?.house}` }}</p>
|
||||||
|
<h3>с day month бесплатно</h3>
|
||||||
|
</div>
|
||||||
|
<Icon class="pickup-point-card__action" name="lucide:chevron-right" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mobile -->
|
|
||||||
<UDrawer
|
|
||||||
v-if="isMobile"
|
|
||||||
v-model:open="open"
|
|
||||||
fixed
|
|
||||||
:ui="{
|
|
||||||
content: 'fixed bg-default ring ring-default flex focus:outline-none overflow-hidden',
|
|
||||||
container: 'w-full flex flex-col gap-4 p-4 overflow-hidden',
|
|
||||||
body: 'flex-1 overflow-y-auto',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<template #content>
|
|
||||||
<div class="px-4 pb-4">
|
|
||||||
<DeliveryInfo v-if="isPickupPointSelected" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</UDrawer>
|
|
||||||
|
|
||||||
activeTab
|
|
||||||
{{ activeTab }}
|
|
||||||
<!-- Desktop Mobile -->
|
|
||||||
<PvzMap
|
<PvzMap
|
||||||
v-model="checkoutPickupPoint"
|
v-model="checkoutPickupPoint"
|
||||||
:pickup-points="filteredPoints"
|
:pickup-points="filteredPoints"
|
||||||
@active-tab="value => activeTab = value"
|
@update:model-value="setCheckoutPickupPoint(checkoutPickupPoint)"
|
||||||
@update:model-value="updatePoint()"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { PickupPoint, YandexPvzResponse } from '~/server/shared/types/yandex_pvz'
|
import type { PickupPoint, YandexPvzResponse } from '~/server/shared/types/yandex_pvz'
|
||||||
import { useGeolocation, useMediaQuery } from '@vueuse/core'
|
import { useGeolocation } from '@vueuse/core'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import DeliveryInfo from '~/components/DeliveryInfo.vue'
|
import DeliveryInfo from '~/components/DeliveryInfo.vue'
|
||||||
import DeliverySearch from '~/components/DeliverySearch.vue'
|
|
||||||
import PvzMap from '~/components/PvzMap.vue'
|
import PvzMap from '~/components/PvzMap.vue'
|
||||||
import { useCheckout } from '~/composables/useCheckout'
|
import { useCheckout } from '~/composables/useCheckout'
|
||||||
|
|
||||||
const { setCheckoutPickupPoint, isPickupPointSelected, checkoutPickupPoint } = useCheckout()
|
const { setCheckoutPickupPoint, isPickupPointSelected, checkoutPickupPoint } = useCheckout()
|
||||||
const { coords } = useGeolocation()
|
const { coords } = useGeolocation()
|
||||||
const open = ref(false)
|
|
||||||
const isMobile = useMediaQuery('(max-width: 1280px)')
|
|
||||||
const yandexPvz = ref<YandexPvzResponse>()
|
const yandexPvz = ref<YandexPvzResponse>()
|
||||||
const searchTerm = ref('')
|
const searchTerm = ref('')
|
||||||
const activeTab = ref()
|
|
||||||
|
|
||||||
const waitForCoords = () =>
|
const waitForCoords = () =>
|
||||||
new Promise<void>((resolve) => {
|
new Promise<void>((resolve) => {
|
||||||
@ -103,11 +111,6 @@ const filteredPoints = computed<PickupPoint[]>(() => {
|
|||||||
) || []
|
) || []
|
||||||
})
|
})
|
||||||
|
|
||||||
function updatePoint() {
|
|
||||||
setCheckoutPickupPoint(checkoutPickupPoint.value)
|
|
||||||
open.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'checkout',
|
layout: 'checkout',
|
||||||
})
|
})
|
||||||
@ -127,5 +130,36 @@ definePageMeta({
|
|||||||
width: 410px;
|
width: 410px;
|
||||||
padding-inline: 24px;
|
padding-inline: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__items {
|
||||||
|
height: calc(100dvh - 54px - 40px - 24px);
|
||||||
|
overflow-y: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pickup-point-card {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__action {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user