Skip to content

Commit 787fc18

Browse files
feat(VCST-3865): cart pickup locations facet search (#1998)
## Description Facet full-text search features added to the pickup locations map and list popups Version with Google map enabled (desktop and mobile layouts): <img width="1065" height="957" alt="image" src="https://github.com/user-attachments/assets/77bf23b5-3476-4ae5-8621-dde024ffaab2" /> <img width="1058" height="952" alt="image" src="https://github.com/user-attachments/assets/15b7045f-d129-4e4b-bcd5-d41737145570" /> <img width="430" height="950" alt="image" src="https://github.com/user-attachments/assets/643302f1-0ca5-43fb-8851-3b1ad29a9aed" /> Version with Google map disabled (desktop and mobile layouts): <img width="878" height="623" alt="image" src="https://github.com/user-attachments/assets/068fcb20-aec6-44ec-bb9b-ee4ca27d699c" /> <img width="878" height="412" alt="image" src="https://github.com/user-attachments/assets/693e28a7-59ce-4108-a7e9-fa7b8df09912" /> <img width="436" height="965" alt="image" src="https://github.com/user-attachments/assets/a0060f45-a2fd-449b-a543-98ba6a0d263b" /> ## References ### Jira-link: https://virtocommerce.atlassian.net/browse/VCST-3865 ### Artifact URL: https://vc3prerelease.blob.core.windows.net/packages/vc-theme-b2b-vue-2.35.0-pr-1998-90f1-90f1ef88.zip --------- Co-authored-by: Elena Mutykova <[email protected]>
1 parent 44d25dc commit 787fc18

File tree

28 files changed

+666
-145
lines changed

28 files changed

+666
-145
lines changed

client-app/core/api/graphql/cart/queries/getCartPickupLocations/getCartPickupLocationsQuery.graphql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,22 @@ query GetCartPickupLocations(
33
$cultureName: String!
44
$cartId: String!
55
$keyword: String
6+
$filter: String
67
$first: Int
78
$after: String
89
$sort: String
10+
$facet: String
911
) {
1012
cartPickupLocations(
1113
storeId: $storeId
1214
cultureName: $cultureName
1315
cartId: $cartId
1416
keyword: $keyword
17+
filter: $filter
1518
first: $first
1619
after: $after
1720
sort: $sort
21+
facet: $facet
1822
) {
1923
totalCount
2024
items {
@@ -40,5 +44,13 @@ query GetCartPickupLocations(
4044
phone
4145
}
4246
}
47+
term_facets {
48+
name
49+
terms {
50+
term
51+
label
52+
count
53+
}
54+
}
4355
}
4456
}

client-app/core/api/graphql/cart/queries/getCartPickupLocations/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { globals } from "@/core/globals";
22
import { graphqlClient } from "../../../client";
33
import getCartPickupLocationsQueryDocument from "./getCartPickupLocationsQuery.graphql";
4-
import type { Query, QueryCartPickupLocationsArgs, ProductPickupLocationConnection } from "@/core/api/graphql/types";
4+
import type { Query, QueryCartPickupLocationsArgs, CartPickupLocationConnection } from "@/core/api/graphql/types";
55

66
export async function getCartPickupLocations(
77
payload: Omit<QueryCartPickupLocationsArgs, "storeId" | "cultureName">,
8-
): Promise<ProductPickupLocationConnection> {
8+
): Promise<CartPickupLocationConnection> {
99
const { storeId, cultureName } = globals;
1010

1111
const { data } = await graphqlClient.query<

client-app/core/api/graphql/types.ts

Lines changed: 25 additions & 3 deletions
Large diffs are not rendered by default.

client-app/core/types/facet.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,24 @@ export type FacetItemType = {
2020
max?: number;
2121
};
2222
};
23+
24+
export type FacetFilterType = {
25+
filterType: string;
26+
isGenerated: boolean;
27+
label?: string;
28+
name: string;
29+
rangeValues?: FacetFilterRangeValueType[];
30+
termValues?: FacetFilterTermValueType[];
31+
};
32+
33+
export type FacetFilterRangeValueType = {
34+
includeLowerBound: boolean;
35+
includeUpperBound: boolean;
36+
lower?: string;
37+
upper?: string;
38+
};
39+
40+
export type FacetFilterTermValueType = {
41+
label?: string;
42+
value: string;
43+
};
Lines changed: 119 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,116 @@
1-
import { ref } from "vue";
1+
import { createSharedComposable } from "@vueuse/core";
2+
import { computed, ref } from "vue";
3+
import { useI18n } from "vue-i18n";
24
import { getCartPickupLocations } from "@/core/api/graphql/cart";
3-
import { Logger } from "@/core/utilities";
5+
import { Logger, termFacetToCommonFacet } from "@/core/utilities";
46
import type { ProductPickupLocation, QueryCartPickupLocationsArgs } from "@/core/api/graphql/types";
7+
import type { FacetFilterType, FacetItemType } from "@/core/types";
8+
9+
export const COUNTRY_NAME_FACET = "address_countryname";
10+
export const REGION_NAME_FACET = "address_regionname";
11+
export const CITY_FACET = "address_city";
12+
13+
export function _useCartPickupLocations() {
14+
const { t } = useI18n();
515

6-
export function useCartPickupLocations() {
716
const pickupLocationsLoading = ref(false);
817

918
const pickupLocations = ref<ProductPickupLocation[]>([]);
1019

11-
async function fetchPickupLocations(payload: Omit<QueryCartPickupLocationsArgs, "storeId" | "cultureName">) {
20+
const filterOptionsCountries = ref<FacetItemType>();
21+
const filterOptionsRegions = ref<FacetItemType>();
22+
const filterOptionsCities = ref<FacetItemType>();
23+
24+
const filterCountries = ref<FacetFilterType>();
25+
const filterRegions = ref<FacetFilterType>();
26+
const filterCities = ref<FacetFilterType>();
27+
const filterKeyword = ref<string>("");
28+
29+
const filterSelectsAreEmpty = computed(
30+
() =>
31+
!(
32+
filterCountries.value?.termValues?.length ||
33+
filterRegions.value?.termValues?.length ||
34+
filterCities.value?.termValues?.length
35+
),
36+
);
37+
38+
const filterIsApplied = ref(false);
39+
40+
function buildFilter(): string | undefined {
41+
const resultItems = [];
42+
43+
if (filterCities.value?.termValues?.length) {
44+
resultItems.push(`${CITY_FACET}:"${filterCities.value.termValues.map((x) => x.value).join('","')}"`);
45+
}
46+
47+
if (filterRegions.value?.termValues?.length) {
48+
resultItems.push(`${REGION_NAME_FACET}:"${filterRegions.value.termValues.map((x) => x.value).join('","')}"`);
49+
}
50+
51+
if (filterCountries.value?.termValues?.length) {
52+
resultItems.push(`${COUNTRY_NAME_FACET}:"${filterCountries.value.termValues.map((x) => x.value).join('","')}"`);
53+
}
54+
55+
return resultItems.join(" ");
56+
}
57+
58+
function clearFilter() {
59+
filterCountries.value = undefined;
60+
filterRegions.value = undefined;
61+
filterCities.value = undefined;
62+
filterKeyword.value = "";
63+
}
64+
65+
async function fetchPickupLocations(
66+
payload: Omit<QueryCartPickupLocationsArgs, "storeId" | "cultureName" | "facet">,
67+
) {
1268
pickupLocationsLoading.value = true;
1369
try {
14-
const data = await getCartPickupLocations(payload);
70+
const data = await getCartPickupLocations({
71+
facet: `${COUNTRY_NAME_FACET} ${REGION_NAME_FACET} ${CITY_FACET}`,
72+
...payload,
73+
});
1574
pickupLocations.value = data.items ?? [];
75+
76+
const termFacetCounties = data.term_facets?.find((f) => f.name === COUNTRY_NAME_FACET);
77+
if (termFacetCounties) {
78+
filterOptionsCountries.value = termFacetToCommonFacet(termFacetCounties);
79+
filterOptionsCountries.value.label = t("common.labels.country");
80+
} else {
81+
filterOptionsCountries.value = {
82+
type: "terms",
83+
paramName: COUNTRY_NAME_FACET,
84+
values: [],
85+
label: t("common.labels.country"),
86+
};
87+
}
88+
89+
const termFacetRegions = data.term_facets?.find((f) => f.name === REGION_NAME_FACET);
90+
if (termFacetRegions) {
91+
filterOptionsRegions.value = termFacetToCommonFacet(termFacetRegions);
92+
filterOptionsRegions.value.label = t("common.labels.region");
93+
} else {
94+
filterOptionsRegions.value = {
95+
type: "terms",
96+
paramName: REGION_NAME_FACET,
97+
values: [],
98+
label: t("common.labels.region"),
99+
};
100+
}
101+
102+
const termFacetCities = data.term_facets?.find((f) => f.name === CITY_FACET);
103+
if (termFacetCities) {
104+
filterOptionsCities.value = termFacetToCommonFacet(termFacetCities);
105+
filterOptionsCities.value.label = t("common.labels.city");
106+
} else {
107+
filterOptionsCities.value = {
108+
type: "terms",
109+
paramName: CITY_FACET,
110+
values: [],
111+
label: t("common.labels.city"),
112+
};
113+
}
16114
} catch (e) {
17115
Logger.error(`${useCartPickupLocations.name}.${fetchPickupLocations.name}`, e);
18116
throw e;
@@ -24,5 +122,21 @@ export function useCartPickupLocations() {
24122
pickupLocationsLoading,
25123
pickupLocations,
26124
fetchPickupLocations,
125+
126+
filterOptionsCountries,
127+
filterOptionsRegions,
128+
filterOptionsCities,
129+
130+
filterCountries,
131+
filterRegions,
132+
filterCities,
133+
filterKeyword,
134+
135+
filterSelectsAreEmpty,
136+
filterIsApplied,
137+
buildFilter,
138+
clearFilter,
27139
};
28140
}
141+
142+
export const useCartPickupLocations = createSharedComposable(_useCartPickupLocations);

client-app/shared/catalog/components/facet-filter.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
</VcMenuItem>
5353

5454
<div v-if="isAnchorAdded" ref="fadeVisibilityAnchor"></div>
55+
5556
<div v-if="hasFade" class="facet-filter-widget__fade"></div>
5657
</div>
5758
</template>
@@ -81,6 +82,7 @@
8182
<!-- Dropdown mode -->
8283
<VcDropdownMenu
8384
v-if="mode === 'dropdown'"
85+
:disabled="disabled"
8486
:offset-options="4"
8587
class="facet-filter-dropdown"
8688
z-index="10"
@@ -179,6 +181,7 @@ interface IEmits {
179181
interface IProps {
180182
facet: FacetItemType;
181183
loading?: boolean;
184+
disabled?: boolean;
182185
mode: "dropdown" | "collapsable";
183186
filter?: SearchProductFilterResult;
184187
}

client-app/shared/checkout/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export { default as OrderCommentSection } from "./order-comment-section.vue";
44
export { default as OrderSummary } from "./order-summary.vue";
55
export { default as PlaceOrder } from "./place-order.vue";
66
export { default as ProceedTo } from "./proceed-to.vue";
7+
export { default as SelectAddressFilter } from "./select-address-filter.vue";
78
export { default as SelectAddressModal } from "./select-address-modal.vue";
89
export { default as SelectPaymentMethodModal } from "./select-payment-method-modal.vue";
910
export { default as ShippingDetailsSection } from "./shipping-details-section.vue";

0 commit comments

Comments
 (0)