Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: improve typing of sorting in facetGetters/category.vue #1080

Merged
merged 2 commits into from
May 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions packages/theme/composables/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,6 @@ export interface GroupedFacetInterface {
options: FacetInterface[];
}

export interface AgnosticSort {
options: FacetInterface[];
selected: string;
}

export interface AgnosticPagination {
currentPage?: number;
totalPages?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@
height="26px"
margin="0"
/>
<span
v-else
>{{ pagination.totalItems }}</span>
<span v-else>{{ pagination.totalItems }}</span>
<span class="navbar__label smartphone-only">&nbsp;{{ $t('Items') }}</span>
</div>

Expand Down Expand Up @@ -86,8 +84,9 @@ import {
} from '@storefront-ui/vue';
import SvgImage from '~/components/General/SvgImage.vue';
import { useUiHelpers, useUiState } from '~/composables';
import { AgnosticPagination, AgnosticSort } from '~/composables/types';
import { AgnosticPagination } from '~/composables/types';
import SkeletonLoader from '~/components/SkeletonLoader/index.vue';
import { SortingModel } from '~/modules/catalog/category/composables/useFacet/sortingOptions';

export default defineComponent({
components: {
Expand All @@ -98,7 +97,7 @@ export default defineComponent({
},
props: {
sortBy: {
type: Object as PropType<AgnosticSort>,
type: Object as PropType<SortingModel>,
required: true,
},
pagination: {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { Logger } from '~/helpers/logger';
import type { ComposableFunctionArgs } from '~/composables/types';
import type { GetProductSearchParams } from '~/modules/catalog/product/types';
import useApi from '~/composables/useApi';
import { SortingOptions } from '~/modules/catalog/category/composables/useFacet/SortingOptions';
import { PerPageOptions } from '~/modules/catalog/category/composables/useFacet/PerPageOptions';
import { sortingOptions } from '~/modules/catalog/category/composables/useFacet/sortingOptions';
import { perPageOptions } from '~/modules/catalog/category/composables/useFacet/perPageOptions';
import { createProductAttributeFilterInput } from '~/modules/catalog/category/composables/useFacet/input/createProductAttributeFilterInput';
import { createProductAttributeSortInput } from '~/modules/catalog/category/composables/useFacet/input/createProductAttributeSortInput';
import { Products } from '~/modules/GraphQL/types';
import GetFacetDataQuery from './getFacetData.gql';
import getFacetDataQuery from './getFacetData.gql';
import type {
UseFacetInterface, UseFacetErrors, UseFacetSearchResult, FacetSearchParams,
} from './useFacet';
Expand Down Expand Up @@ -43,15 +43,15 @@ export function useFacet(): UseFacetInterface {
currentPage: params.page,
};

const { products } = await query<{ products: Products }>(GetFacetDataQuery, productSearchParams);
const { products } = await query<{ products: Products }>(getFacetDataQuery, productSearchParams);

Logger.debug('[Result]:', { products });

result.value.data = {
items: products?.items ?? [],
total: products?.total_count,
availableSortingOptions: SortingOptions,
perPageOptions: PerPageOptions,
availableSortingOptions: sortingOptions,
perPageOptions,
itemsPerPage: pageSize,
};
error.value.search = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const perPageOptions = [10, 20, 50];
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
export interface SortingModel {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SortingModel as to avoid having "SortingOptions" and "SortingOption" interfaces with similar names

selected: string,
options: SortingOption[]
}

export interface SortingOption {
label: string,
value: SortingOptionsValuesEnum
}

export enum SortingOptionsValuesEnum {
DEFAULT = '',
NAME_ASC = 'name_ASC',
Expand All @@ -6,12 +16,7 @@ export enum SortingOptionsValuesEnum {
PRICE_DESC = 'price_DESC',
}

export interface SortingOptionsInterface {
label: string,
value: SortingOptionsValuesEnum
}

export const SortingOptions: SortingOptionsInterface[] = [
export const sortingOptions: SortingOption[] = [
{
label: 'Sort: Default',
value: SortingOptionsValuesEnum.DEFAULT,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { DeepReadonly, Ref } from '@nuxtjs/composition-api';
import type { ComposableFunctionArgs } from '~/composables/types';
import { ProductInterface } from '~/modules/GraphQL/types';
import { SortingOptionsInterface } from '~/modules/catalog/category/composables/useFacet/SortingOptions';
import type { ProductInterface } from '~/modules/GraphQL/types';
import type { SortingOption } from '~/modules/catalog/category/composables/useFacet/sortingOptions';

/**
* The {@link useFacet} search params data structure
Expand All @@ -24,7 +24,7 @@ export interface FacetSearchParams {
export interface SearchResultData {
items: ProductInterface[],
total: number,
availableSortingOptions: SortingOptionsInterface[],
availableSortingOptions: SortingOption[],
perPageOptions: number[],
itemsPerPage: number
}
Expand Down
99 changes: 42 additions & 57 deletions packages/theme/modules/catalog/category/getters/facetGetters.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,50 @@
import type {
AgnosticPagination,
AgnosticSort,
} from '~/composables/types';

import { ProductInterface } from '~/modules/GraphQL/types';
import { FacetSearchParams } from '~/modules/catalog/category/composables/useFacet';
import { PerPageOptions } from '~/modules/catalog/category/composables/useFacet/PerPageOptions';

export interface FacetSearchResult<S> {
data: S;
input: FacetSearchParams;
import { perPageOptions } from '~/modules/catalog/category/composables/useFacet/perPageOptions';
import type { ProductInterface } from '~/modules/GraphQL/types';
import type { AgnosticPagination } from '~/composables/types';
import type { SortingModel } from '~/modules/catalog/category/composables/useFacet/sortingOptions';
import type { UseFacetSearchResult } from '~/modules/catalog/category/composables/useFacet/useFacet';

export interface FacetsGetters {
getSortOptions: (searchData: UseFacetSearchResult) => SortingModel;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously the type here was AgnosticSort which turned out to be completely different at runtime. TypeScript didn't report an error since the searchData argument was any.

getProducts: (searchData: UseFacetSearchResult) => ProductInterface[];
getPagination: (searchData: UseFacetSearchResult) => AgnosticPagination;
}

export interface FacetsGetters<SEARCH_DATA, RESULTS = any> {
getSortOptions: (searchData: FacetSearchResult<SEARCH_DATA>) => AgnosticSort;
getProducts: (searchData: FacetSearchResult<SEARCH_DATA>) => RESULTS;
getPagination: (searchData: FacetSearchResult<SEARCH_DATA>) => AgnosticPagination;
[getterName: string]: (element: any, options?: any) => unknown;
}
const facetGetters: FacetsGetters = {
getSortOptions(searchData) {
if (!searchData || !searchData.data || !searchData.data.availableSortingOptions) {
return {
options: [],
selected: '',
} as SortingModel;
}

const getSortOptions = (searchData): AgnosticSort => {
if (!searchData || !searchData.data || !searchData.data.availableSortingOptions) {
return {
options: [],
selected: '',
} as AgnosticSort;
}
options: searchData.data.availableSortingOptions,
selected: searchData.input.sort,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if there will be no sort param?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CategoryNavbar will not show any sort option. This will only happen if someone puts a sort id that doesn't exist into the url.

};
},
getProducts(searchData) {
if (!searchData || !searchData.data || !searchData.data.items) {
return [];
}
return searchData.data.items;
},
getPagination(searchData) {
const totalPages = (searchData?.data) ? (
Number.isNaN(Math.ceil(searchData.data.total / searchData.input.itemsPerPage))
? 1
: Math.ceil(searchData.data.total / searchData.input.itemsPerPage)
) : 1;

return {
options: searchData.data.availableSortingOptions,
selected: searchData.input.sort,
};
};

const getProducts = (searchData): ProductInterface[] => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I inlined the methods into the exported asserted interface since I didn't want to duplicate the typedefs

if (!searchData || !searchData.data || !searchData.data.items) {
return [];
}
return searchData.data.items;
};

const getPagination = (searchData): AgnosticPagination => {
const totalPages = (searchData?.data) ? (
Number.isNaN(Math.ceil(searchData.data.total / searchData.input.itemsPerPage))
? 1
: Math.ceil(searchData.data.total / searchData.input.itemsPerPage)
) : 1;

return {
currentPage: (searchData?.input?.page > totalPages ? 1 : searchData?.input?.page) || 1,
totalPages,
totalItems: (searchData?.data?.total) ? searchData.data.total : 0,
itemsPerPage: searchData?.input?.itemsPerPage || 10,
pageOptions: PerPageOptions,
};
};

const facetGetters: FacetsGetters<any, any> = {
getSortOptions,
getProducts,
getPagination,
return {
currentPage: (searchData?.input?.page > totalPages ? 1 : searchData?.input?.page) || 1,
totalPages,
totalItems: (searchData?.data?.total) ? searchData.data.total : 0,
itemsPerPage: searchData?.input?.itemsPerPage || 10,
pageOptions: perPageOptions,
};
},
};

export default facetGetters;
27 changes: 14 additions & 13 deletions packages/theme/modules/catalog/pages/category.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,24 +111,28 @@ import {
defineComponent, onMounted, ref, ssrRef, useFetch,
} from '@nuxtjs/composition-api';
import { CacheTagPrefix, useCache } from '@vue-storefront/cache';
import { facetGetters } from '~/getters';
import {
useFacet,
useUiHelpers,
useUiState,
} from '~/composables';
import useWishlist from '~/modules/wishlist/composables/useWishlist';
import { AgnosticPagination } from '~/composables/types';
import { Product } from '~/modules/catalog/product/types';
import { useUrlResolver } from '~/composables/useUrlResolver';

import { useAddToCart } from '~/helpers/cart/addToCart';
import { useCategoryContent } from '~/modules/catalog/category/components/cms/useCategoryContent';
import { useUrlResolver } from '~/composables/useUrlResolver';
import { useWishlist } from '~/modules/wishlist/composables/useWishlist';
import { usePrice } from '~/modules/catalog/pricing/usePrice';
import CategoryNavbar from '~/modules/catalog/category/components/navbar/CategoryNavbar.vue';
import type { EntityUrl } from '~/modules/GraphQL/types';
import { useCategoryContent } from '~/modules/catalog/category/components/cms/useCategoryContent';
import { useTraverseCategory } from '~/modules/catalog/category/helpers/useTraverseCategory';
import facetGetters from '~/modules/catalog/category/getters/facetGetters';

import CategoryNavbar from '~/modules/catalog/category/components/navbar/CategoryNavbar.vue';
import CategoryBreadcrumbs from '~/modules/catalog/category/components/breadcrumbs/CategoryBreadcrumbs.vue';

import type { EntityUrl, ProductInterface } from '~/modules/GraphQL/types';
import type { SortingModel } from '~/modules/catalog/category/composables/useFacet/sortingOptions';
import type { AgnosticPagination } from '~/composables/types';
import type { Product } from '~/modules/catalog/product/types';

export default defineComponent({
name: 'CategoryPage',
components: {
Expand All @@ -152,8 +156,8 @@ export default defineComponent({
const cmsContent = ref('');
const isShowCms = ref(false);
const isShowProducts = ref(false);
const products = ssrRef<Product[]>([]);
const sortBy = ref({});
const products = ssrRef<ProductInterface[]>([]);
const sortBy = ref<SortingModel>({ selected: '', options: [] });
const pagination = ref<AgnosticPagination>({});

const productContainerElement = ref<HTMLElement | null>(null);
Expand Down Expand Up @@ -181,7 +185,6 @@ export default defineComponent({
};

const searchCategoryProduct = async (categoryId: number) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
await search({
...uiHelpers.getFacetsFromURL(),
categoryId,
Expand Down Expand Up @@ -209,13 +212,11 @@ export default defineComponent({
pagination.value = facetGetters.getPagination(result.value);

const tags = [{ prefix: CacheTagPrefix.View, value: 'category' }];
// eslint-disable-next-line no-underscore-dangle
const productTags = products.value.map((product) => ({
prefix: CacheTagPrefix.Product,
value: product.uid,
}));

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
addTags([...tags, ...productTags]);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export default defineComponent({
const context = useContext();
const router = useRouter();
const userAddresses = ref([]);
const userAddresses = ref<CustomerAddress[]>([]);
const { load, remove } = useAddresses();
const { fetch } = useFetch(async () => {
const addressesData = await load();
Expand Down