Skip to content

Commit

Permalink
refactor: cart page (#416)
Browse files Browse the repository at this point in the history
* feat: refactor cart and checkout

* refactor: cart page

Co-authored-by: Artem Makarov <[email protected]>
  • Loading branch information
Andrew-Orlov and artmakarov authored Jan 16, 2023
1 parent 54029de commit b6300a5
Show file tree
Hide file tree
Showing 38 changed files with 838 additions and 873 deletions.
20 changes: 3 additions & 17 deletions client-app/pages/account/addresses.vue
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@
</template>

<script setup lang="ts">
import { useUser, useUserAddresses } from "@/shared/account";
import { useUserAddresses } from "@/shared/account";
import { computed, ComputedRef, onMounted, Ref, ref } from "vue";
import { clone } from "lodash";
import { MemberAddressType } from "@/xapi/types";
Expand All @@ -237,18 +237,15 @@ import { useI18n } from "vue-i18n";
const { t } = useI18n();
const breakpoints = useBreakpoints(breakpointsTailwind);
const { user } = useUser();
const { countries, loadCountries } = useCountries();
const {
loading: addressesLoading,
addresses,
sort,
fetchAddresses,
setDefaultAddress,
removeAddresses,
defaultShippingAddress,
addOrUpdateAddresses,
} = useUserAddresses({ user });
} = useUserAddresses();
usePageHead({
title: t("pages.account.addresses.meta.title"),
Expand Down Expand Up @@ -319,7 +316,7 @@ function closeEditMode() {
editingMode.value = false;
}
function itemActionsBuilder(inputObject: MemberAddressType) {
function itemActionsBuilder() {
const actions: SlidingActionsItem[] = [
{
icon: "fas fa-pencil-alt",
Expand All @@ -340,17 +337,6 @@ function itemActionsBuilder(inputObject: MemberAddressType) {
},
];
if (defaultShippingAddress.value && inputObject.id !== defaultShippingAddress.value.id) {
actions.push({
icon: "fas fa-check",
title: t("pages.account.addresses.make_default_button"),
classes: "bg-[color:var(--color-primary)]",
clickHandler(address: MemberAddressType) {
setDefaultAddress(address);
},
});
}
return actions;
}
Expand Down
2 changes: 1 addition & 1 deletion client-app/pages/account/checkout-defaults.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ usePageHead({
title: t("pages.account.checkout_defaults.meta.title"),
});
const savedCheckoutDefaults = ref<CheckoutDefaults>(getUserCheckoutDefaults() ?? {});
const savedCheckoutDefaults = ref<CheckoutDefaults>(getUserCheckoutDefaults());
const localCheckoutDefaults = ref<CheckoutDefaults>(clone(savedCheckoutDefaults.value));
const shippingMethods = computed<ShippingMethodType[]>(() => cart.value.availableShippingMethods ?? []);
Expand Down
33 changes: 14 additions & 19 deletions client-app/pages/account/edit-quote.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@
<QuoteLineItems :items="quote.items!" @remove:item="onRemoveItem" />
</VcSectionWidget>

<VcSectionWidget
:title="$t('pages.account.quote_details.shipping_address')"
icon="truck"
>
<VcSectionWidget :title="$t('pages.account.quote_details.shipping_address')" icon="truck">
<h4 class="text-md leading-5 font-bold">
{{ $t("pages.account.quote_details.shipping_address") }}
</h4>
Expand Down Expand Up @@ -72,10 +69,7 @@
</VcSectionWidget>

<!-- Quote billing address -->
<VcSectionWidget
:title="$t('pages.account.quote_details.billing_address')"
icon="cash"
>
<VcSectionWidget :title="$t('pages.account.quote_details.billing_address')" icon="cash">
<h4 class="text-md font-bold leading-5">
{{ $t("pages.account.quote_details.billing_address") }}
</h4>
Expand Down Expand Up @@ -152,9 +146,9 @@ import { computedEager } from "@vueuse/core";
import { cloneDeep, isEqual, remove, every } from "lodash";
import { MemberAddressType, QuoteAddressType, QuoteItemType, QuoteType } from "@/xapi";
import { AddressType, convertToType } from "@/core";
import { useUser, useUserAddresses, useUserQuote, QuoteLineItems } from "@/shared/account";
import { useUserAddresses, useUserQuote, QuoteLineItems } from "@/shared/account";
import { usePopup } from "@/shared/popup";
import { AddOrUpdateAddressDialog, SelectAddressDialog } from "@/shared/checkout";
import { AddOrUpdateAddressModal, SelectAddressModal } from "@/shared/checkout";
import { usePageHead } from "@/core/composables";
import { asyncForEach } from "@/core/utilities";
Expand All @@ -166,9 +160,8 @@ const props = defineProps({
const router = useRouter();
const { t } = useI18n();
const { user } = useUser();
const { openPopup, closePopup } = usePopup();
const { addresses, fetchAddresses, addOrUpdateAddresses } = useUserAddresses({ user });
const { addresses, fetchAddresses, addOrUpdateAddresses } = useUserAddresses();
const {
fetching,
quote,
Expand Down Expand Up @@ -227,16 +220,16 @@ function setBillingAddressEqualsShippingAddress(): void {
function openAddressSelectionDialog(addressType: AddressType.Billing | AddressType.Shipping): void {
openPopup({
component: SelectAddressDialog,
component: SelectAddressModal,
props: {
addresses: addresses.value,
currentAddress: convertToType<MemberAddressType>(
addressType === AddressType.Billing ? billingAddress.value : shippingAddress.value
),
onResult(selectedAddress: MemberAddressType): void {
const quoteAddress = convertToType<QuoteAddressType>(selectedAddress);
quoteAddress.addressType = addressType;
const quoteAddress = convertToType<QuoteAddressType>({ ...selectedAddress, addressType });
setQuoteAddress(quoteAddress);
closePopup();
},
Expand All @@ -255,16 +248,18 @@ function openAddOrUpdateAddressDialog(
currentAddress?: QuoteAddressType
): void {
openPopup({
component: AddOrUpdateAddressDialog,
component: AddOrUpdateAddressModal,
props: {
address: currentAddress,
async onResult(updatedAddress: MemberAddressType): Promise<void> {
const quoteAddress = convertToType<QuoteAddressType>(updatedAddress);
quoteAddress.addressType = addressType;
const quoteAddress = convertToType<QuoteAddressType>({ ...updatedAddress, addressType });
setQuoteAddress(quoteAddress);
await addOrUpdateAddresses([updatedAddress], user.value!.memberId);
closePopup();
// Save address in account
await addOrUpdateAddresses([{ ...updatedAddress, addressType: AddressType.BillingAndShipping }]);
},
},
});
Expand Down
54 changes: 21 additions & 33 deletions client-app/pages/account/order-details.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,19 @@
v-if="$cfg.line_items_group_by_vendor_enabled"
class="bg-white lg:mb-6 lg:rounded -mx-5 md:mx-0 lg:shadow-md-x lg:pt-5 lg:px-7"
>
<template v-for="(item, vendorId) in groupedOrderItems" :key="vendorId">
<template v-for="(group, vendorId) in orderItemsGroupedByVendor" :key="vendorId">
<div
v-if="item.items.length"
v-if="group.items.length"
class="bg-white shadow-light-lg mb-4 px-7 pt-4 lg:mb-0 lg:pb-5 lg:px-0 lg:pt-0 lg:rounded lg:shadow-none"
>
<!-- Vendor -->
<div class="pb-3 font-bold text-15">
<span class="mr-1">{{ $t("pages.account.order_details.vendor_label") }}:</span>
<Vendor v-if="item.vendor" :vendor="item.vendor" class="inline-flex flex-row items-end gap-x-3" />
<Vendor v-if="group.vendor" :vendor="group.vendor" class="inline-flex flex-row items-end gap-x-3" />
<span v-else class="text-gray-400" v-t="`pages.account.order_details.empty_vendor_label`" />
</div>

<OrderLineItems :items="item.items" class="lg:rounded" />
<OrderLineItems :items="group.items" class="lg:rounded" />
</div>
</template>
</div>
Expand Down Expand Up @@ -225,16 +225,16 @@
</template>

<script setup lang="ts">
import { computed, inject, ref, watchEffect } from "vue";
import { computed, ref, watchEffect } from "vue";
import { useI18n } from "vue-i18n";
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core";
import { configInjectionKey, usePageHead } from "@/core";
import { usePageHead } from "@/core";
import { InputNewBulkItemType, OrderLineItemType, Vendor as VendorType } from "@/xapi";
import { AcceptedGifts, OrderSummary } from "@/shared/checkout";
import { BackButtonInHeader } from "@/shared/layout";
import { useUserOrder, OrderLineItems } from "@/shared/account";
import { usePopup } from "@/shared/popup";
import { AddBulkItemsToCartResultsPopup, getItemsForAddBulkItemsToCartResultsPopup, useCart } from "@/shared/cart";
import { AddBulkItemsToCartResultsModal, getItemsForAddBulkItemsToCartResultsPopup, useCart } from "@/shared/cart";
import { Vendor } from "@/shared/catalog";
type TGroupItem = { items: OrderLineItemType[]; vendor?: VendorType };
Expand All @@ -247,8 +247,6 @@ const props = defineProps({
},
});
const config = inject(configInjectionKey);
const breakpoints = useBreakpoints(breakpointsTailwind);
const { order, deliveryAddress, billingAddress, fetchOrder, clearOrder } = useUserOrder();
const { addBulkItemsToCart } = useCart();
Expand All @@ -259,9 +257,6 @@ usePageHead({
title: computed(() => t("pages.account.order_details.meta.title", [order.value?.number])),
});
const groupIdWithoutVendor = "none";
const groupItemsByVendor = !!config?.line_items_group_by_vendor_enabled;
const isMobile = breakpoints.smaller("lg");
const loadingAddItemsToCart = ref(false);
Expand All @@ -275,27 +270,16 @@ const breadcrumbs = computed<IBreadcrumbs[]>(() => [
const showPaymentButton = computed<boolean>(() => !!order.value && order.value.status === "New");
const showReorderButton = computed<boolean>(() => !!order.value && order.value.status === "Completed");
const giftItems = computed(() => order.value?.items?.filter((item) => item.isGift));
const giftItems = computed<OrderLineItemType[]>(() => (order.value?.items || []).filter((item) => item.isGift));
const orderItems = computed<OrderLineItemType[]>(() => (order.value?.items || []).filter((item) => !item.isGift));
const orderItems = computed<OrderLineItemType[]>(() => {
if (groupItemsByVendor || !order.value) {
return [];
}
return order.value.items.filter((item) => !item.isGift);
});
const groupedOrderItems = computed<TGroupedItems>(() => {
// NOTE: The group without a vendor should be last to be displayed.
const orderItemsGroupedByVendor = computed<TGroupItem[]>(() => {
// NOTE: The group without the vendor should be displayed last.
const groupWithoutVendor: TGroupItem = { items: [] };
const map: TGroupedItems = {};
if (!groupItemsByVendor) {
return map;
}
order.value?.items.forEach((item) => {
const vendor = item.product!.vendor;
orderItems.value.forEach((item) => {
const vendor = item.product?.vendor;
if (vendor) {
const vendorId = vendor.id;
Expand All @@ -307,10 +291,14 @@ const groupedOrderItems = computed<TGroupedItems>(() => {
}
});
// Add a group without a vendor to the end of the iteration object.
map[groupIdWithoutVendor] = groupWithoutVendor;
const result = Object.values(map)
// Sort by Vendor
.sort((a, b) => a.vendor!.name.localeCompare(b.vendor!.name));
// Add the group without the vendor to the end.
result.push(groupWithoutVendor);
return map;
return result;
});
async function reorderItems() {
Expand All @@ -322,7 +310,7 @@ async function reorderItems() {
const resultItems = await addBulkItemsToCart(inputBulkItems);
openPopup({
component: AddBulkItemsToCartResultsPopup,
component: AddBulkItemsToCartResultsModal,
props: {
items: getItemsForAddBulkItemsToCartResultsPopup(items, resultItems),
},
Expand Down
6 changes: 3 additions & 3 deletions client-app/pages/account/order-payment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@
<script setup lang="ts">
import { computed, ref, watchEffect } from "vue";
import { InputOrderAddressType, OrderPaymentMethodType, PaymentInType } from "@/xapi/types";
import { AddOrUpdateAddressDialog, OrderSummary, PaymentMethodDialog } from "@/shared/checkout";
import { AddOrUpdateAddressModal, OrderSummary, SelectPaymentMethodModal } from "@/shared/checkout";
import {
PaymentProcessingAuthorizeNet,
PaymentMethod,
Expand Down Expand Up @@ -297,7 +297,7 @@ function tryAgain() {
function showEditAddressDialog() {
openPopup({
component: AddOrUpdateAddressDialog,
component: AddOrUpdateAddressModal,
props: {
address: payment.value?.billingAddress,
async onResult(address: InputOrderAddressType) {
Expand All @@ -320,7 +320,7 @@ function showEditAddressDialog() {
function showChangePaymentMethodDialog(): void {
openPopup({
component: PaymentMethodDialog,
component: SelectPaymentMethodModal,
props: {
currentMethodCode: payment.value?.gatewayCode,
availableMethods: order.value?.availablePaymentMethods,
Expand Down
10 changes: 5 additions & 5 deletions client-app/pages/account/orders.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@

<!-- Page Toolbar -->
<PageToolbarBlock
:stick="isVisibleStickyMobileHeader"
:stick="stickyMobileHeaderIsVisible"
class="flex flex-row lg:flex-row-reverse items-center py-3.5 -my-3.5 gap-x-2 lg:gap-x-5"
shadow
>
Expand Down Expand Up @@ -330,14 +330,12 @@ usePageHead({
});
const isMobile = breakpoints.smaller("lg");
const localKeyword = ref("");
const filtersVisible = ref(false);
const filtersButtonElement = shallowRef<HTMLElement | null>(null);
const filtersDropdownElement = shallowRef<HTMLElement | null>(null);
const stickyMobileHeaderAnchor = shallowRef<HTMLElement | null>(null);
const stickyMobileHeaderAnchorIsVisible = useElementVisibility(stickyMobileHeaderAnchor, { direction: "top" });
const columns = ref<ITableColumn[]>([
{
id: "number",
Expand Down Expand Up @@ -371,7 +369,9 @@ const columns = ref<ITableColumn[]>([
},
]);
const isVisibleStickyMobileHeader = computed<boolean>(() => !stickyMobileHeaderAnchorIsVisible.value && isMobile.value);
const stickyMobileHeaderAnchor = shallowRef<HTMLElement | null>(null);
const stickyMobileHeaderAnchorIsVisible = useElementVisibility(stickyMobileHeaderAnchor, { direction: "top" });
const stickyMobileHeaderIsVisible = computed<boolean>(() => !stickyMobileHeaderAnchorIsVisible.value && isMobile.value);
async function changePage(newPage: number) {
page.value = newPage;
Expand Down
17 changes: 7 additions & 10 deletions client-app/pages/account/quotes.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<!-- Page toolbar -->
<PageToolbarBlock
:stick="isVisibleStickyMobileHeader"
:stick="stickyMobileHeaderIsVisible"
class="flex flex-row lg:flex-row-reverse items-center py-3.5 -my-3.5 gap-x-2 lg:gap-x-5"
shadow
>
Expand Down Expand Up @@ -155,33 +155,30 @@
</template>

<script setup lang="ts">
import { ref, shallowRef, watch } from "vue";
import { computed, ref, shallowRef, watch } from "vue";
import { useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { PageToolbarBlock, useUserQuotes } from "@/shared/account";
import { QuoteType } from "@/xapi/types";
import { computedEager, useBreakpoints, breakpointsTailwind } from "@vueuse/core";
import { useBreakpoints, breakpointsTailwind } from "@vueuse/core";
import { useElementVisibility, useRouteQueryParam, usePageHead } from "@/core/composables";
import { getSortingExpression, ISortInfo, QueryParamName, getSortInfoFromStringExpression } from "@/core";
const { t } = useI18n();
const router = useRouter();
const breakpoints = useBreakpoints(breakpointsTailwind);
usePageHead({
title: t("pages.account.quotes.title"),
});
const { quotes, fetching, itemsPerPage, pages, page, keyword, sort, fetchQuotes } = useUserQuotes();
const stickyMobileHeaderAnchor = shallowRef<HTMLElement | null>(null);
const breakpoints = useBreakpoints(breakpointsTailwind);
const stickyMobileHeaderAnchorIsVisible = useElementVisibility(stickyMobileHeaderAnchor, { direction: "top" });
const isMobile = breakpoints.smaller("lg");
const isVisibleStickyMobileHeader = computedEager<boolean>(
() => !stickyMobileHeaderAnchorIsVisible.value && isMobile.value
);
const stickyMobileHeaderAnchor = shallowRef<HTMLElement | null>(null);
const stickyMobileHeaderAnchorIsVisible = useElementVisibility(stickyMobileHeaderAnchor, { direction: "top" });
const stickyMobileHeaderIsVisible = computed<boolean>(() => !stickyMobileHeaderAnchorIsVisible.value && isMobile.value);
const sortQueryParam = useRouteQueryParam<string>(QueryParamName.Sort, {
defaultValue: "createdDate:desc",
Expand Down
Loading

0 comments on commit b6300a5

Please sign in to comment.