Skip to content

Commit

Permalink
chore: checkout rework (#321)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmbanan666 authored Feb 24, 2025
1 parent 15d22f9 commit 59a7a54
Show file tree
Hide file tree
Showing 28 changed files with 461 additions and 465 deletions.
4 changes: 4 additions & 0 deletions apps/web-app/app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
:tooltip="{ delayDuration: 0 }"
class="min-h-dvh"
>
<NuxtLoadingIndicator :color="false" class="bg-(--ui-primary) h-[2px]" />
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
Expand All @@ -29,6 +30,9 @@ useHead({
const channel = useChannelStore()
await channel.update()
const checkout = useCheckoutStore()
await checkout.update()
if (!channel.isInitialized) {
await navigateTo('/welcome')
}
Expand Down
30 changes: 14 additions & 16 deletions apps/web-app/app/components/Cart/Button.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
<template>
<ClientOnly>
<div v-if="!isEmpty" class="block xl:hidden">
<UButton
variant="gradient"
size="lg"
class="items-center"
@click="isCartDrawerOpened = !isCartDrawerOpened"
>
<p>{{ $t('app.cart.title') }}</p>
<div class="rounded-full bg-white size-6 text-center">
{{ checkout?.lines?.length }}
</div>
</UButton>
</div>
</ClientOnly>
<div v-if="!checkout.isEmpty" class="block xl:hidden">
<UButton
variant="gradient"
size="lg"
class="items-center"
@click="isCartDrawerOpened = !isCartDrawerOpened"
>
<p>{{ $t('app.cart.title') }}</p>
<div class="pt-0.5 rounded-full bg-(--ui-bg-muted) size-6 text-center text-(--ui-primary)">
{{ checkout.lines.length }}
</div>
</UButton>
</div>
</template>

<script setup lang="ts">
const { isCartDrawerOpened } = useApp()
const { checkout, isEmpty } = useCheckout()
const checkout = useCheckoutStore()
</script>
40 changes: 19 additions & 21 deletions apps/web-app/app/components/Cart/DeliveryMethodSwitch.vue
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
<template>
<ClientOnly>
<div class="p-0 flex flex-row gap-0 justify-center bg-(--ui-bg-elevated) rounded-xl">
<UButton
v-if="channel.isDeliveryAvailable"
class="w-full justify-center"
:variant="checkout?.deliveryMethod === 'DELIVERY' ? 'gradient' : 'ghost'"
@click="update({ deliveryMethod: 'DELIVERY' })"
>
{{ $t('app.cart.delivery') }}
</UButton>
<UButton
v-if="channel.isPickupAvailable"
class="w-full justify-center"
:variant="checkout?.deliveryMethod === 'WAREHOUSE' ? 'gradient' : 'ghost'"
@click="update({ deliveryMethod: 'WAREHOUSE' })"
>
{{ $t('app.cart.pickup') }}
</UButton>
</div>
</ClientOnly>
<div class="p-0 flex flex-row gap-0 justify-center bg-(--ui-bg-elevated) rounded-xl">
<UButton
v-if="channel.isDeliveryAvailable"
class="w-full justify-center"
:variant="checkout.deliveryMethod === 'DELIVERY' ? 'gradient' : 'ghost'"
@click="checkout.change({ deliveryMethod: 'DELIVERY' })"
>
{{ $t('app.cart.delivery') }}
</UButton>
<UButton
v-if="channel.isPickupAvailable"
class="w-full justify-center"
:variant="checkout.deliveryMethod === 'WAREHOUSE' ? 'gradient' : 'ghost'"
@click="checkout.change({ deliveryMethod: 'WAREHOUSE' })"
>
{{ $t('app.cart.pickup') }}
</UButton>
</div>
</template>

<script setup lang="ts">
const channel = useChannelStore()
const { checkout, update } = useCheckout()
const checkout = useCheckoutStore()
</script>
4 changes: 2 additions & 2 deletions apps/web-app/app/components/Cart/Drawer.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<template>
<button
class="z-30 fixed left-0 right-0 -top-20 -bottom-20 appearance-none bg-neutral-700/50 opacity-0 data-[active=true]:opacity-100 translate-x-full data-[active=true]:-translate-x-0 transition-opacity"
class="z-50 fixed left-0 right-0 -top-20 -bottom-20 appearance-none bg-neutral-700/50 opacity-0 data-[active=true]:opacity-100 translate-x-full data-[active=true]:-translate-x-0 transition-opacity"
:data-active="isCartDrawerOpened"
aria-label="Close"
@click="isCartDrawerOpened = !isCartDrawerOpened"
/>
<div
class="z-30 fixed right-0 top-0 w-full max-w-sm ml-auto h-[100dvh] p-2 m-0 shadow-none rounded-2xl translate-x-full data-[active=true]:-translate-x-0 transition-transform"
class="z-50 fixed right-0 top-0 w-full max-w-sm ml-auto h-[100dvh] p-2 m-0 shadow-none rounded-2xl translate-x-full data-[active=true]:-translate-x-0 transition-transform"
:data-active="isCartDrawerOpened"
>
<Cart />
Expand Down
16 changes: 8 additions & 8 deletions apps/web-app/app/components/Cart/Line.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
<NuxtLink :to="productUrl">
<div class="max-w-[15rem] flex flex-row gap-2 flex-nowrap items-center cursor-pointer active:scale-95 lg:hover:scale-95 lg:active:scale-90 duration-200 group">
<div class="relative size-14 aspect-square">
<ProductImage :id="line?.productVariant.product.mediaId" size="xs" />
<ProductImage :id="product?.mediaId" size="xs" />
</div>

<div>
<p class="font-base text-xs leading-tight line-clamp-2">
{{ line?.productVariant.product.name }}
{{ product?.name }}
</p>
<div class="mt-1 flex flex-row gap-2 flex-nowrap">
<div class="text-sm font-medium tracking-tight">
{{ formatNumberToLocal(line?.productVariant.gross) }} <span class="text-xs">{{ channel.currencySign }}</span>
{{ formatNumberToLocal(productVariant?.gross) }} <span class="text-xs">{{ channel.currencySign }}</span>
</div>
<div class="text-sm text-(--ui-text-muted) font-light">
{{ variant?.weightValue }}{{ getWeightLocalizedUnit(variant?.weightUnit) }}
{{ productVariant?.weightValue }}{{ getWeightLocalizedUnit(productVariant?.weightUnit) }}
</div>
</div>
</div>
Expand All @@ -32,9 +32,9 @@ const { lineId } = defineProps<{
}>()
const channel = useChannelStore()
const { checkout } = useCheckout()
const line = computed(() => checkout.value?.lines?.find((l) => l.id === lineId))
const variant = computed(() => line.value?.productVariant)
const product = computed(() => line.value?.productVariant?.product)
const checkout = useCheckoutStore()
const line = computed(() => checkout.lines?.find((l) => l.id === lineId))
const productVariant = channel.getProductVariant(line.value?.productVariantId ?? '')
const product = channel.getProduct(productVariant.value?.productId ?? '')
const productUrl = computed(() => `/catalog/${product.value?.category?.slug}/${product.value?.slug}`)
</script>
8 changes: 4 additions & 4 deletions apps/web-app/app/components/Cart/LineCounter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<button
aria-label="Minus"
class="flex flex-row items-center p-1 rounded-xl lg:hover:scale-90 lg:hover:bg-(--ui-bg-muted) duration-200"
@click="changeLineQuantity(lineId, 'decrement')"
@click="checkout.changeLineQuantity(lineId, 'decrement')"
>
<Icon :name="icons.minus" class="size-5" />
</button>
Expand All @@ -15,7 +15,7 @@
<button
aria-label="Plus"
class="flex flex-row items-center p-1 rounded-xl lg:hover:scale-90 lg:hover:bg-(--ui-bg-muted) duration-200"
@click="changeLineQuantity(lineId, 'increment')"
@click="checkout.changeLineQuantity(lineId, 'increment')"
>
<Icon :name="icons.plus" class="size-5" />
</button>
Expand All @@ -28,6 +28,6 @@ const { lineId } = defineProps<{
}>()
const { icons } = useAppConfig()
const { checkout, changeLineQuantity } = useCheckout()
const line = computed(() => checkout.value?.lines?.find((l) => l.id === lineId))
const checkout = useCheckoutStore()
const line = computed(() => checkout.lines?.find((l) => l.id === lineId))
</script>
108 changes: 50 additions & 58 deletions apps/web-app/app/components/Cart/index.vue
Original file line number Diff line number Diff line change
@@ -1,78 +1,70 @@
<template>
<ClientOnly>
<div v-if="checkout" class="relative rounded-2xl border border-(--ui-border) px-4 py-4 h-full flex flex-col justify-between">
<div class="h-screen overflow-y-auto">
<div class="mb-48">
<div class="mb-4 flex flex-row justify-between items-center">
<h3 class="text-2xl font-medium">
{{ $t('app.cart.title') }}
</h3>
<div v-if="checkout.id" class="relative rounded-2xl bg-(--ui-bg) border border-(--ui-border) p-4 h-full flex flex-col justify-between">
<div class="h-screen overflow-y-auto">
<div class="mb-48">
<div class="mb-4 flex flex-row justify-between items-center">
<h3 class="text-2xl font-medium">
{{ $t('app.cart.title') }}
</h3>

<button
aria-label="Close"
class="block xl:hidden rounded-xl lg:hover:scale-90 hover:bg-neutral-100 duration-200"
@click="isCartDrawerOpened = !isCartDrawerOpened"
>
<Icon :name="icons.close" class="size-8" />
</button>
</div>

<div class="mt-2 mb-4">
<CartDeliveryMethodSwitch />
</div>
<button
aria-label="Close"
class="block xl:hidden rounded-xl lg:hover:scale-90 hover:bg-neutral-100 duration-200"
@click="isCartDrawerOpened = !isCartDrawerOpened"
>
<Icon :name="icons.close" class="size-8" />
</button>
</div>

<CartEmpty v-if="isEmpty" />
<div v-else>
<CartLine
v-for="line in checkout?.lines"
:key="line.id"
:line-id="line.id"
/>
</div>
<div class="mt-2 mb-4">
<CartDeliveryMethodSwitch />
</div>

<CartEmpty v-if="checkout.isEmpty" />
<template v-else>
<CartLine
v-for="line in checkout.lines"
:key="line.id"
:line-id="line.id"
/>
</template>
</div>
</div>

<div class="absolute bottom-0 left-0 right-0 rounded-2xl bg-(--ui-bg-muted)">
<button
class="relative m-4 flex flex-row gap-2 flex-wrap items-center active:scale-95 lg:hover:scale-95 lg:active:scale-90 duration-200"
@click="modal.open(ModalDeliveryInfo)"
<div class="absolute bottom-0 left-0 right-0 rounded-2xl bg-(--ui-bg-muted)">
<button
class="relative m-4 flex flex-row gap-2 flex-wrap items-center active:scale-95 lg:hover:scale-95 lg:active:scale-90 duration-200"
@click="modal.open(ModalDeliveryInfo)"
>
<Icon :name="icons.info" class="size-6 text-(--ui-text-dimmed)" />
<div class="text-left text-sm text-(--ui-text-muted)">
{{ $t('app.cart.conditions') }}
</div>
</button>

<div v-if="!checkout.isEmpty" class="my-4 mx-4">
<UButton
to="/checkout"
variant="gradient"
size="xl"
class="w-full justify-between items-center"
>
<Icon :name="icons.info" class="size-6 text-(--ui-text-dimmed)" />
<div class="text-left text-sm text-(--ui-text-muted)">
{{ $t('app.cart.conditions') }}
<p>{{ $t('app.cart.next-label') }}</p>
<div class="text-lg tracking-tight">
{{ formatNumberToLocal(checkout.totalPrice) }} <span class="text-base">{{ channel.currencySign }}</span>
</div>
</button>

<div v-if="!isEmpty" class="my-4 mx-4">
<UButton
to="/checkout"
variant="gradient"
size="xl"
class="w-full justify-between items-center"
>
<p>{{ $t('app.cart.next-label') }}</p>
<div class="text-lg tracking-tight">
{{ formatNumberToLocal(checkout?.totalPrice) }} <span class="text-base">{{ channel.currencySign }}</span>
</div>
</UButton>
</div>
</UButton>
</div>
</div>

<template #fallback>
<div class="relative h-full w-full flex flex-col justify-center items-center">
<Icon :name="icons.loader" class="w-16 h-16 text-neutral-300 animate-pulse" />
</div>
</template>
</ClientOnly>
</div>
</template>

<script setup lang="ts">
import { ModalDeliveryInfo } from '#components'
const { isCartDrawerOpened } = useApp()
const { icons } = useAppConfig()
const { checkout, isEmpty } = useCheckout()
const modal = useModal()
const channel = useChannelStore()
const checkout = useCheckoutStore()
</script>
25 changes: 9 additions & 16 deletions apps/web-app/app/components/Checkout/Line.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
<div class="flex flex-row gap-2 items-center justify-between">
<NuxtLink :to="productUrl" class="max-w-[16rem] flex flex-row gap-2 flex-nowrap items-center cursor-pointer active:scale-95 lg:hover:scale-95 lg:active:scale-90 duration-200 group">
<div class="relative size-12 md:size-14 aspect-square">
<ProductImage :id="variant?.product?.mediaId" size="xs" />
<ProductImage :id="product?.mediaId" size="xs" />
</div>

<div class="space-y-1">
<div class="font-medium text-(--ui-text) leading-tight line-clamp-2">
{{ variant?.product.name }}
{{ product?.name }}
</div>
<div class="flex flex-row gap-2 flex-nowrap items-center">
<p class="text-sm text-(--ui-text-muted) leading-tight">
{{ variant?.name }}
{{ productVariant?.name }}
</p>
<p class="text-sm text-(--ui-text-muted)">
{{ variant?.weightValue }}{{ getWeightLocalizedUnit(variant?.weightUnit) }}
{{ productVariant?.weightValue }}{{ getWeightLocalizedUnit(productVariant?.weightUnit) }}
</p>
</div>
</div>
Expand All @@ -37,21 +37,14 @@

<script setup lang="ts">
const { line, canBeChanged = true } = defineProps<{
line: Pick<CheckoutLine, 'id' | 'quantity'> & {
productVariant: Pick<ProductVariant, 'gross' | 'name'> & {
weightUnit: string
weightValue: number
product: Pick<Product, 'name' | 'slug' | 'mediaId'> & {
category: Pick<MenuCategory, 'slug'>
}
}
}
line: CheckoutLine
canBeChanged?: boolean
}>()
const channel = useChannelStore()
const totalAmount = computed(() => line ? formatNumberToLocal(line.productVariant?.gross * line.quantity) : 0)
const variant = computed(() => line?.productVariant)
const product = computed(() => line?.productVariant?.product)
const productVariant = channel.getProductVariant(line.productVariantId ?? '')
const product = channel.getProduct(productVariant.value?.productId ?? '')
const productUrl = computed(() => `/catalog/${product.value?.category?.slug}/${product.value?.slug}`)
const totalAmount = computed(() => formatNumberToLocal(productVariant.value?.gross ? productVariant.value?.gross * line.quantity : 0))
</script>
4 changes: 2 additions & 2 deletions apps/web-app/app/components/DeliveryInfoBlock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const { icons } = useAppConfig()
const { t } = useI18n()
const channel = useChannelStore()
const { checkout } = useCheckout()
const title = computed(() => checkout.value?.deliveryMethod === 'DELIVERY' ? t('app.cart.delivery') : t('app.cart.pickup'))
const checkout = useCheckoutStore()
const title = computed(() => checkout.deliveryMethod === 'DELIVERY' ? t('app.cart.delivery') : t('app.cart.pickup'))
const todayUntil = computed(() => channel.workingDay?.isActive ? `${channel.workingDay.closeHours.toString().padStart(2, '0')}:${channel.workingDay.closeMinutes.toString().padStart(2, '0')}` : undefined)
</script>
8 changes: 4 additions & 4 deletions apps/web-app/app/components/Form/UpdateMenuCategory.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ const channel = useChannelStore()
const category = channel.getMenuCategory(categoryId)
const state = ref<Partial<MenuCategoryUpdateSchema>>({
name: category?.name,
slug: category?.slug,
name: category.value?.name,
slug: category.value?.slug,
})
function resetState() {
state.value = {
name: category?.name,
slug: category?.slug,
name: category.value?.name,
slug: category.value?.slug,
}
}
Expand Down
Loading

0 comments on commit 59a7a54

Please sign in to comment.