Skip to content

Commit bd90eaf

Browse files
feat(VCST-4553): predefined product list (#2165)
## Description ## References ### Jira-link: https://virtocommerce.atlassian.net/browse/VCST-4553 ### Artifact URL: https://vc3prerelease.blob.core.windows.net/packages/vc-theme-b2b-vue-2.41.0-pr-2165-d068-d0687d7b.zip --------- Co-authored-by: Elena Mutykova <[email protected]>
1 parent 91e61dd commit bd90eaf

File tree

5 files changed

+156
-7
lines changed

5 files changed

+156
-7
lines changed

.serena/project.yml

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
languages:
2525
- vue
2626
- typescript
27-
encoding: 'utf-8'
27+
28+
# the encoding used by text files in the project
29+
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
30+
encoding: "utf-8"
2831

2932
# whether to use project's .gitignore files to ignore files
3033
ignore_all_files_in_gitignore: true
@@ -81,8 +84,28 @@ excluded_tools: []
8184

8285
# initial prompt for the project. It will always be given to the LLM upon activating the project
8386
# (contrary to the memories, which are loaded on demand).
84-
initial_prompt: ''
87+
initial_prompt: ""
88+
# the name by which the project can be referenced within Serena
89+
project_name: "frontend"
8590

86-
project_name: 'frontend'
91+
# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default)
8792
included_optional_tools: []
93+
94+
# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
95+
# This cannot be combined with non-empty excluded_tools or included_optional_tools.
8896
fixed_tools: []
97+
98+
# list of mode names to that are always to be included in the set of active modes
99+
# The full set of modes to be activated is base_modes + default_modes.
100+
# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply.
101+
# Otherwise, this setting overrides the global configuration.
102+
# Set this to [] to disable base modes for this project.
103+
# Set this to a list of mode names to always include the respective modes for this project.
104+
base_modes:
105+
106+
# list of mode names that are to be activated by default.
107+
# The full set of modes to be activated is base_modes + default_modes.
108+
# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply.
109+
# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
110+
# This setting can, in turn, be overridden by CLI parameters (--mode).
111+
default_modes:

client-app/pages/matcher/builderIo/customComponents.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,62 @@ export const builderIOComponents: Array<BuilderIOComponentType> = [
201201
},
202202
],
203203
},
204+
{
205+
name: "Predefined Products",
206+
component: ProductsBlock,
207+
inputs: [
208+
{
209+
name: "title",
210+
type: "string",
211+
defaultValue: "Predefined Products",
212+
},
213+
{
214+
name: "subtitle",
215+
type: "string",
216+
},
217+
{
218+
name: "cardType",
219+
type: "string",
220+
defaultValue: "full",
221+
enum: ["full", "short"],
222+
},
223+
{
224+
name: "columnsAmountTablet",
225+
type: "string",
226+
defaultValue: "3",
227+
enum: ["3", "2"],
228+
},
229+
{
230+
name: "columnsAmountDesktop",
231+
type: "string",
232+
defaultValue: "4",
233+
enum: ["4", "3"],
234+
},
235+
{
236+
name: "skus",
237+
type: "list",
238+
friendlyName: "SKUs",
239+
subFields: [
240+
{
241+
name: "sku",
242+
type: "string",
243+
friendlyName: "Product SKU",
244+
defaultValue: "",
245+
},
246+
],
247+
onChange: (options: Map<string, Array<{ sku: string }>>) => {
248+
const skus = options.get("skus");
249+
if (!Array.isArray(skus)) {
250+
return;
251+
}
252+
if (skus.length > 12) {
253+
options.set("skus", skus.slice(0, 12));
254+
alert("Maximum 12 SKUs allowed");
255+
}
256+
},
257+
},
258+
],
259+
},
204260
{
205261
component: Slider,
206262
name: "Slider",
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "Predefined products",
3+
"icon": "local_mall",
4+
"displayField": "name",
5+
"settings": [
6+
{
7+
"id": "title",
8+
"label": "Title",
9+
"type": "string",
10+
"tab": "Content"
11+
},
12+
{
13+
"id": "subtitle",
14+
"label": "Subtitle",
15+
"type": "string",
16+
"multiline": true,
17+
"tab": "Content"
18+
},
19+
{
20+
"id": "skus",
21+
"label": "SKUs",
22+
"type": "list",
23+
"tab": "Content",
24+
"default": [],
25+
"element": [
26+
{
27+
"id": "sku",
28+
"label": "Product SKU",
29+
"type": "string"
30+
}
31+
]
32+
}
33+
]
34+
}

client-app/shared/static-content/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ export const templateBlocks: { [key: string]: Component } = {
3737
"text-block": TextBlock,
3838
"title-block": TitleBlock,
3939
category: Category,
40+
"predefined-product-list": ProductsBlock,
4041
};

client-app/shared/static-content/components/products-block.vue

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
'2xl': Number(columnsAmountDesktop),
1919
}"
2020
>
21-
<ProductCard v-for="item in products" :key="item.id" :card-type="cardType" :product="item" />
21+
<ProductCard v-for="item in displayProducts" :key="item.id" :card-type="cardType" :product="item" />
2222
</VcProductsGrid>
2323
</div>
2424
</div>
2525
</template>
2626

2727
<script setup lang="ts">
28-
import { watchEffect } from "vue";
28+
import { computed, watchEffect } from "vue";
2929
import { ProductCard, useProducts } from "@/shared/catalog";
3030
3131
interface IProps {
@@ -39,6 +39,7 @@ interface IProps {
3939
cardType?: "full" | "short";
4040
columnsAmountDesktop?: string;
4141
columnsAmountTablet?: string;
42+
skus?: Array<{ sku: string }>;
4243
}
4344
4445
const props = withDefaults(defineProps<IProps>(), {
@@ -50,11 +51,45 @@ const props = withDefaults(defineProps<IProps>(), {
5051
5152
const { products, fetchProducts } = useProducts();
5253
54+
const skuCodes = computed(() => {
55+
const skus = Array.from(new Set(props.skus?.map((item) => item.sku)?.filter(Boolean) ?? []));
56+
if (!skus.length) {
57+
return [];
58+
}
59+
return skus;
60+
});
61+
62+
const skuFilterExpression = computed(() => {
63+
if (!skuCodes.value.length) {
64+
return "";
65+
}
66+
return `"code":"${skuCodes.value.join('","')}"`;
67+
});
68+
69+
const combinedFilter = computed(() => {
70+
const filters = [skuFilterExpression.value, props.filter].filter(Boolean);
71+
return filters.join(" ");
72+
});
73+
74+
const displayProducts = computed(() => {
75+
if (!skuCodes.value.length) {
76+
return products.value;
77+
}
78+
79+
const skuOrderMap = new Map(skuCodes.value.map((sku, index) => [sku, index]));
80+
81+
return [...products.value].sort((a, b) => {
82+
const orderA = skuOrderMap.get(a.code) ?? Number.MAX_SAFE_INTEGER;
83+
const orderB = skuOrderMap.get(b.code) ?? Number.MAX_SAFE_INTEGER;
84+
return orderA - orderB;
85+
});
86+
});
87+
5388
watchEffect(async () => {
5489
await fetchProducts({
55-
itemsPerPage: props.count,
90+
itemsPerPage: skuCodes.value.length || props.count,
5691
keyword: props.query,
57-
filter: props.filter,
92+
filter: combinedFilter.value || undefined,
5893
});
5994
});
6095
</script>

0 commit comments

Comments
 (0)