@evenicanpm/storefront-core 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/package.json +7 -3
  2. package/src/api-manager/README.md +52 -27
  3. package/src/api-manager/datasources/d365/d365-cart.datasource.ts +166 -17
  4. package/src/api-manager/datasources/d365/d365-invoice.datasource.ts +100 -0
  5. package/src/api-manager/datasources/d365/d365-order.datasource.ts +75 -18
  6. package/src/api-manager/datasources/d365/d365-product.datasource.ts +19 -1
  7. package/src/api-manager/datasources/d365/d365-user.datasource.ts +96 -22
  8. package/src/api-manager/datasources/d365/d365.datasource.ts +3 -0
  9. package/src/api-manager/datasources/d365/utils/get-context-cookie.ts +10 -3
  10. package/src/api-manager/datasources/e4/e4.datasource.ts +9 -0
  11. package/src/api-manager/datasources/e4/order/e4-order.datasource.ts +7 -4
  12. package/src/api-manager/datasources/e4/user/e4-user.datasource.ts +4 -0
  13. package/src/api-manager/index.ts +54 -3
  14. package/src/api-manager/lib/get-graphql-client.ts +11 -5
  15. package/src/api-manager/schemas/cart.schema.ts +10 -1
  16. package/src/api-manager/schemas/invoice.schema.ts +55 -0
  17. package/src/api-manager/schemas/order.schema.ts +13 -1
  18. package/src/api-manager/schemas/user.schema.ts +8 -0
  19. package/src/api-manager/services/create-query.ts +4 -10
  20. package/src/api-manager/services/invoice/queries/get-invoice-details.ts +18 -0
  21. package/src/api-manager/services/invoice/queries/get-invoices.ts +18 -0
  22. package/src/api-manager/services/order/queries/get-order-details.ts +1 -1
  23. package/src/api-manager/services/order/queries/get-orders.ts +6 -3
  24. package/src/api-manager/services/user/queries/get-customer-balance.ts +20 -0
  25. package/src/api-manager/types/Datasource.ts +21 -2
  26. package/src/auth/better-auth.ts +1 -1
  27. package/src/cms/blocks/block-manager.tsx +18 -3
  28. package/src/cms/blocks/components/cta-banner.tsx +65 -0
  29. package/src/cms/blocks/components/hero-image.tsx +83 -0
  30. package/src/cms/blocks/index.tsx +2 -0
  31. package/src/cms/blocks/interfaces.ts +20 -0
  32. package/src/cms/draft-mode-badge.tsx +26 -0
  33. package/src/cms/queries.ts +81 -0
  34. package/src/components/flex-box/flex-box.tsx +2 -0
  35. package/src/components/header/components/user.tsx +37 -12
  36. package/src/components/mini-cart/mini-cart.tsx +3 -3
  37. package/src/components/wishlist-dialogs/add-to-wishlist/compound/wishlist-dialog-header.tsx +1 -0
  38. package/src/pages/account/account-navigation.tsx +88 -60
  39. package/src/pages/account/account-routes.ts +52 -0
  40. package/src/pages/account/orders/order-history-filter-types.tsx +26 -0
  41. package/src/pages/account/orders/order-history-filters-panel.tsx +375 -0
  42. package/src/pages/account/orders/order-history-header.tsx +54 -0
  43. package/src/pages/account/orders/order-history-pagination.tsx +55 -0
  44. package/src/pages/account/orders/order-history-root.tsx +125 -0
  45. package/src/pages/account/orders/order-history-row.tsx +110 -0
  46. package/src/pages/account/orders/order-history-search-and-filter.tsx +449 -0
  47. package/src/pages/account/orders/order-history-search-bar.tsx +84 -0
  48. package/src/pages/account/orders/order-history-search-dropdown.tsx +53 -0
  49. package/src/pages/account/orders/order-history-sort.tsx +90 -0
  50. package/src/pages/account/orders/order-history-table.tsx +54 -0
  51. package/src/pages/account/orders/order-row.tsx +2 -2
  52. package/src/pages/account/orders/orders-drop-down-handler.tsx +19 -0
  53. package/src/pages/account/table-header.tsx +20 -0
  54. package/src/pages/account/wishlist/wishlist-item.tsx +1 -1
  55. package/src/pages/blog/blog-card.tsx +9 -3
  56. package/src/pages/blog/blog-detail-view.tsx +150 -0
  57. package/src/pages/blog/blog-list-view.tsx +59 -0
  58. package/src/pages/cart/estimate-shipping.tsx +6 -5
  59. package/src/pages/checkout/checkout-alt-form/checkout-form.tsx +43 -21
  60. package/src/pages/checkout/checkout-alt-form/steps/payment/payment-details.tsx +144 -19
  61. package/src/pages/cms-page-view.tsx +53 -0
  62. package/src/pages/quickorder/order-upload.tsx +12 -6
  63. package/src/pages/quickorder/quick-order.tsx +25 -20
@@ -0,0 +1,449 @@
1
+ import getStoresList from "@evenicanpm/storefront-core/src/api-manager/services/organization/queries/get-stores";
2
+ import type {
3
+ OrderSearchCriteria,
4
+ SalesStatus,
5
+ } from "@msdyn365-commerce/retail-proxy";
6
+ import { Box } from "@mui/material";
7
+ import { createContext, useContext, useState } from "react";
8
+ import {
9
+ type CreatedDateFilter,
10
+ FilterSourceType,
11
+ type OrderStatusFilter,
12
+ type OriginFilter,
13
+ } from "./order-history-filter-types";
14
+ import OrdersFilterPanel from "./order-history-filters-panel";
15
+ import { useOrderHistory } from "./order-history-root";
16
+ import OrdersSearchBar from "./order-history-search-bar";
17
+
18
+ // interface OrdersSearchAndFilterProps {
19
+ // handleSearch: (criteria: OrderSearchCriteria) => void;
20
+ // }
21
+
22
+ // export default function OrdersSearchAndFilter({
23
+ // handleSearch,
24
+ // }: OrdersSearchAndFilterProps) {
25
+ // const { data: stores } = getStoresList.useData({
26
+ // queryResultSettings: {
27
+ // Paging: {
28
+ // Skip: 0,
29
+ // Top: 1000,
30
+ // },
31
+ // },
32
+ // searchArea: {
33
+ // DistanceUnitValue: 0,
34
+ // Latitude: 0,
35
+ // Longitude: 0,
36
+ // Radius: 0,
37
+ // },
38
+ // });
39
+
40
+ // const originOptions: OriginFilter[] =
41
+ // stores?.map((store) => ({
42
+ // sourceType: FilterSourceType.Origin,
43
+ // label: store.location.OrgUnitName || "",
44
+ // value: store.location.ChannelId || 0,
45
+ // })) || [];
46
+
47
+ // // Search bar
48
+ // const [searchText, setSearchText] = useState<string>("");
49
+ // const [selectedSearchOption, setSelectedSearchOption] = useState<number>(0);
50
+
51
+ // // Filters
52
+ // const [selectedOrigins, setSelectedOrigins] = useState<OriginFilter[]>([]);
53
+ // const [createdDate, setCreatedDate] = useState<CreatedDateFilter>();
54
+ // const [orderStatus, setOrderStatus] = useState<OrderStatusFilter>();
55
+
56
+ // const handleSelectCreatedDate = (
57
+ // date: CreatedDateFilter | undefined,
58
+ // toggle = true,
59
+ // ) => {
60
+ // toggle
61
+ // ? setCreatedDate((prev) =>
62
+ // prev?.label === date?.label ? undefined : date,
63
+ // )
64
+ // : setCreatedDate(date);
65
+ // };
66
+
67
+ // const handleSelectOrderStatus = (status: OrderStatusFilter | undefined) => {
68
+ // setOrderStatus((prev) =>
69
+ // prev?.label === status?.label ? undefined : status,
70
+ // );
71
+ // };
72
+
73
+ // const handleSelectOrigin = (origin: OriginFilter) => {
74
+ // setSelectedOrigins((prev) => {
75
+ // const exists = prev.some((o) => o.label === origin.label);
76
+ // return exists
77
+ // ? prev.filter((o) => o.label !== origin.label)
78
+ // : [...prev, origin];
79
+ // });
80
+ // };
81
+
82
+ // const executeSearch = () => {
83
+ // const searchCriteria = createSearchCriteria();
84
+ // handleSearch(searchCriteria);
85
+ // };
86
+
87
+ // const createSearchCriteria = (): OrderSearchCriteria => {
88
+ // const orderSearchCriteria: OrderSearchCriteria = {};
89
+
90
+ // const channelIds: number[] = selectedOrigins.map((origin) => origin.value);
91
+ // if (channelIds.length > 0) {
92
+ // orderSearchCriteria.ChannelIds = channelIds;
93
+ // }
94
+ // const salesStatus = orderStatus?.value ?? undefined;
95
+ // const salesStatuses: SalesStatus[] =
96
+ // salesStatus !== undefined ? [salesStatus] : [];
97
+ // if (salesStatuses.length > 0) {
98
+ // orderSearchCriteria.OrderStatusValues = salesStatuses;
99
+ // }
100
+
101
+ // if (createdDate) {
102
+ // const { startDate, endDate } = getDateRange(createdDate);
103
+ // orderSearchCriteria.StartDateTime = startDate;
104
+ // orderSearchCriteria.EndDateTime = endDate;
105
+ // }
106
+
107
+ // if (searchText) {
108
+ // if (selectedSearchOption === 0) {
109
+ // orderSearchCriteria.ChannelReferenceId = searchText;
110
+ // } else if (selectedSearchOption === 1) {
111
+ // orderSearchCriteria.SalesId = searchText;
112
+ // } else if (selectedSearchOption === 2) {
113
+ // const channelIds = stores
114
+ // ?.filter((store) =>
115
+ // store.location.OrgUnitName?.toLocaleLowerCase().includes(
116
+ // searchText.toLowerCase(),
117
+ // ),
118
+ // )
119
+ // .map((store) => store.location.ChannelId)
120
+ // .filter((id): id is number => id !== undefined);
121
+
122
+ // if (channelIds?.length) {
123
+ // if (orderSearchCriteria.ChannelIds?.length) {
124
+ // // Find interesting channels between searched name and selected filters
125
+ // const intersectingChannelIds = channelIds.filter((id) =>
126
+ // orderSearchCriteria.ChannelIds?.includes(id),
127
+ // );
128
+
129
+ // orderSearchCriteria.ChannelIds = intersectingChannelIds;
130
+ // } else {
131
+ // orderSearchCriteria.ChannelIds = channelIds;
132
+ // }
133
+ // }
134
+ // }
135
+ // }
136
+
137
+ // return orderSearchCriteria;
138
+ // };
139
+
140
+ // const getDateRange = (
141
+ // option: CreatedDateFilter | undefined,
142
+ // ): {
143
+ // startDate: Date;
144
+ // endDate: Date;
145
+ // } => {
146
+ // const endDate = new Date(); // today
147
+ // const startDate = new Date();
148
+
149
+ // switch (option?.label) {
150
+ // case "Last 7 days":
151
+ // startDate.setDate(endDate.getDate() - 7);
152
+ // break;
153
+ // case "Last 30 days":
154
+ // startDate.setDate(endDate.getDate() - 30);
155
+ // break;
156
+ // case "Last 3 months":
157
+ // startDate.setMonth(endDate.getMonth() - 3);
158
+ // break;
159
+ // case "Last 6 months":
160
+ // startDate.setMonth(endDate.getMonth() - 6);
161
+ // break;
162
+ // case "Custom Dates":
163
+ // if (option.startValue && option.endValue) {
164
+ // const customStart = parseLocalDate(option.startValue);
165
+ // const customEnd = parseLocalDate(option.endValue, true);
166
+ // if (isNaN(customStart.getTime()) || isNaN(customEnd.getTime())) {
167
+ // throw new Error("Invalid date format in customized date range.");
168
+ // }
169
+
170
+ // startDate.setTime(customStart.getTime());
171
+ // endDate.setTime(customEnd.getTime());
172
+ // } else {
173
+ // throw new Error(
174
+ // "Customized date range must have start and end values.",
175
+ // );
176
+ // }
177
+ // break;
178
+ // default:
179
+ // throw new Error(`Unsupported date filter option: ${option}`);
180
+ // }
181
+
182
+ // return { startDate, endDate };
183
+ // };
184
+
185
+ // const parseLocalDate = (dateStr: string, endOfDay = false): Date => {
186
+ // const [year, month, day] = dateStr.split("-").map(Number);
187
+ // // month is 0-based in JS Date
188
+ // return endOfDay
189
+ // ? new Date(year, month - 1, day, 23, 59, 59, 999)
190
+ // : new Date(year, month - 1, day, 0, 0, 0, 0);
191
+ // };
192
+
193
+ // return (
194
+ // <Box>
195
+ // {/* SEARCH BAR */}
196
+ // <OrdersSearchBar
197
+ // setSearchText={setSearchText}
198
+ // selectedSearchOption={selectedSearchOption}
199
+ // setSelectedSearchOption={setSelectedSearchOption}
200
+ // executeSearch={executeSearch}
201
+ // />
202
+
203
+ // {/* FITLERS BAR */}
204
+ // <OrdersFilterPanel
205
+ // originOptions={originOptions}
206
+ // selectedOrigins={selectedOrigins}
207
+ // handleSelectOrigin={handleSelectOrigin}
208
+ // createdDate={createdDate}
209
+ // setCreatedDate={handleSelectCreatedDate}
210
+ // orderStatus={orderStatus}
211
+ // setOrderStatus={handleSelectOrderStatus}
212
+ // />
213
+ // </Box>
214
+ // );
215
+ // }
216
+
217
+ type OrdersSearchAndFilterContextType = {
218
+ // Search states
219
+ searchText: string;
220
+ setSearchText: (text: string) => void;
221
+ selectedSearchOption: number;
222
+ setSelectedSearchOption: (option: number) => void;
223
+
224
+ // Filter states
225
+ originOptions: OriginFilter[];
226
+ selectedOrigins: OriginFilter[];
227
+ handleSelectOrigin: (origin: OriginFilter) => void;
228
+ createdDate?: CreatedDateFilter;
229
+ handleSelectCreatedDate: (
230
+ date: CreatedDateFilter | undefined,
231
+ toggle?: boolean,
232
+ ) => void;
233
+ orderStatus?: OrderStatusFilter;
234
+ handleSelectOrderStatus: (status: OrderStatusFilter | undefined) => void;
235
+
236
+ // Actions
237
+ executeSearch: () => void;
238
+ };
239
+
240
+ const OrdersSearchAndFilterContext = createContext<
241
+ OrdersSearchAndFilterContextType | undefined
242
+ >(undefined);
243
+
244
+ export const useOrdersSearchAndFilter = () => {
245
+ const context = useContext(OrdersSearchAndFilterContext);
246
+ if (!context) {
247
+ throw new Error("Must be used within OrdersSearchAndFilterProvider");
248
+ }
249
+ return context;
250
+ };
251
+
252
+ const OrdersSearchAndFilter = ({ children }: { children: React.ReactNode }) => {
253
+ const { setOrderSearchCriteria } = useOrderHistory();
254
+ const { data: stores } = getStoresList.useData({
255
+ queryResultSettings: {
256
+ Paging: {
257
+ Skip: 0,
258
+ Top: 1000,
259
+ },
260
+ },
261
+ searchArea: {
262
+ DistanceUnitValue: 0,
263
+ Latitude: 0,
264
+ Longitude: 0,
265
+ Radius: 0,
266
+ },
267
+ });
268
+
269
+ // Search states
270
+ const [searchText, setSearchText] = useState<string>("");
271
+ const [selectedSearchOption, setSelectedSearchOption] = useState<number>(0);
272
+
273
+ // Filter states
274
+ const [selectedOrigins, setSelectedOrigins] = useState<OriginFilter[]>([]);
275
+ const [createdDate, setCreatedDate] = useState<CreatedDateFilter>();
276
+ const [orderStatus, setOrderStatus] = useState<OrderStatusFilter>();
277
+
278
+ const originOptions: OriginFilter[] =
279
+ stores?.map((store) => ({
280
+ sourceType: FilterSourceType.Origin,
281
+ label: store.location.OrgUnitName || "",
282
+ value: store.location.ChannelId || 0,
283
+ })) || [];
284
+
285
+ const handleSelectOrigin = (origin: OriginFilter) => {
286
+ setSelectedOrigins((prev) => {
287
+ const exists = prev.some((o) => o.label === origin.label);
288
+ return exists
289
+ ? prev.filter((o) => o.label !== origin.label)
290
+ : [...prev, origin];
291
+ });
292
+ };
293
+
294
+ const handleSelectCreatedDate = (
295
+ date: CreatedDateFilter | undefined,
296
+ toggle = true,
297
+ ) => {
298
+ toggle
299
+ ? setCreatedDate((prev) =>
300
+ prev?.label === date?.label ? undefined : date,
301
+ )
302
+ : setCreatedDate(date);
303
+ };
304
+
305
+ const handleSelectOrderStatus = (status: OrderStatusFilter | undefined) => {
306
+ setOrderStatus((prev) =>
307
+ prev?.label === status?.label ? undefined : status,
308
+ );
309
+ };
310
+
311
+ const executeSearch = () => {
312
+ const searchCriteria = createSearchCriteria();
313
+ setOrderSearchCriteria(searchCriteria);
314
+ };
315
+
316
+ const createSearchCriteria = (): OrderSearchCriteria => {
317
+ const orderSearchCriteria: OrderSearchCriteria = {};
318
+
319
+ const channelIds: number[] = selectedOrigins.map((origin) => origin.value);
320
+ if (channelIds.length > 0) {
321
+ orderSearchCriteria.ChannelIds = channelIds;
322
+ }
323
+ const salesStatus = orderStatus?.value ?? undefined;
324
+ const salesStatuses: SalesStatus[] =
325
+ salesStatus !== undefined ? [salesStatus] : [];
326
+ if (salesStatuses.length > 0) {
327
+ orderSearchCriteria.OrderStatusValues = salesStatuses;
328
+ }
329
+
330
+ if (createdDate) {
331
+ const { startDate, endDate } = getDateRange(createdDate);
332
+ orderSearchCriteria.StartDateTime = startDate;
333
+ orderSearchCriteria.EndDateTime = endDate;
334
+ }
335
+
336
+ if (searchText) {
337
+ if (selectedSearchOption === 0) {
338
+ orderSearchCriteria.ChannelReferenceId = searchText;
339
+ } else if (selectedSearchOption === 1) {
340
+ orderSearchCriteria.SalesId = searchText;
341
+ } else if (selectedSearchOption === 2) {
342
+ const channelIds = stores
343
+ ?.filter((store) =>
344
+ store.location.OrgUnitName?.toLocaleLowerCase().includes(
345
+ searchText.toLowerCase(),
346
+ ),
347
+ )
348
+ .map((store) => store.location.ChannelId)
349
+ .filter((id): id is number => id !== undefined);
350
+
351
+ if (channelIds?.length) {
352
+ if (orderSearchCriteria.ChannelIds?.length) {
353
+ const intersectingChannelIds = channelIds.filter((id) =>
354
+ orderSearchCriteria.ChannelIds?.includes(id),
355
+ );
356
+
357
+ orderSearchCriteria.ChannelIds = intersectingChannelIds;
358
+ } else {
359
+ orderSearchCriteria.ChannelIds = channelIds;
360
+ }
361
+ }
362
+ }
363
+ }
364
+
365
+ return orderSearchCriteria;
366
+ };
367
+
368
+ const getDateRange = (
369
+ option: CreatedDateFilter | undefined,
370
+ ): {
371
+ startDate: Date;
372
+ endDate: Date;
373
+ } => {
374
+ const endDate = new Date();
375
+ const startDate = new Date();
376
+
377
+ switch (option?.label) {
378
+ case "Last 7 days":
379
+ startDate.setDate(endDate.getDate() - 7);
380
+ break;
381
+ case "Last 30 days":
382
+ startDate.setDate(endDate.getDate() - 30);
383
+ break;
384
+ case "Last 3 months":
385
+ startDate.setMonth(endDate.getMonth() - 3);
386
+ break;
387
+ case "Last 6 months":
388
+ startDate.setMonth(endDate.getMonth() - 6);
389
+ break;
390
+ case "Custom Dates":
391
+ if (option.startValue && option.endValue) {
392
+ const customStart = parseLocalDate(option.startValue);
393
+ const customEnd = parseLocalDate(option.endValue, true);
394
+ if (
395
+ Number.isNaN(customStart.getTime()) ||
396
+ Number.isNaN(customEnd.getTime())
397
+ ) {
398
+ throw new Error("Invalid date format in customized date range.");
399
+ }
400
+
401
+ startDate.setTime(customStart.getTime());
402
+ endDate.setTime(customEnd.getTime());
403
+ } else {
404
+ throw new Error(
405
+ "Customized date range must have start and end values.",
406
+ );
407
+ }
408
+ break;
409
+ default:
410
+ throw new Error(`Unsupported date filter option: ${option}`);
411
+ }
412
+
413
+ return { startDate, endDate };
414
+ };
415
+
416
+ const parseLocalDate = (dateStr: string, endOfDay = false): Date => {
417
+ const [year, month, day] = dateStr.split("-").map(Number);
418
+ // month is 0-based in JS Date
419
+ return endOfDay
420
+ ? new Date(year, month - 1, day, 23, 59, 59, 999)
421
+ : new Date(year, month - 1, day, 0, 0, 0, 0);
422
+ };
423
+
424
+ const value = {
425
+ searchText,
426
+ setSearchText,
427
+ selectedSearchOption,
428
+ setSelectedSearchOption,
429
+ originOptions,
430
+ selectedOrigins,
431
+ handleSelectOrigin,
432
+ createdDate,
433
+ handleSelectCreatedDate,
434
+ orderStatus,
435
+ handleSelectOrderStatus,
436
+ executeSearch,
437
+ };
438
+
439
+ return (
440
+ <OrdersSearchAndFilterContext.Provider value={value}>
441
+ <Box>{children}</Box>
442
+ </OrdersSearchAndFilterContext.Provider>
443
+ );
444
+ };
445
+
446
+ OrdersSearchAndFilter.Search = OrdersSearchBar;
447
+ OrdersSearchAndFilter.FiltersPanel = OrdersFilterPanel;
448
+
449
+ export default OrdersSearchAndFilter;
@@ -0,0 +1,84 @@
1
+ import { Box, Button, TextField } from "@mui/material";
2
+ import { useTranslations } from "next-intl";
3
+ import { useOrdersSearchAndFilter } from "./order-history-search-and-filter";
4
+ import OrdersSearchDropdown from "./order-history-search-dropdown";
5
+
6
+ export type DisplaySearchOption = {
7
+ name: string;
8
+ id: number;
9
+ };
10
+
11
+ const searchOptions: DisplaySearchOption[] = [
12
+ { id: 0, name: "Order Number" },
13
+ { id: 1, name: "Sales ID" },
14
+ { id: 2, name: "Channel Name" },
15
+ ];
16
+
17
+ const OrdersSearchBar = () => {
18
+ const {
19
+ setSearchText,
20
+ selectedSearchOption,
21
+ setSelectedSearchOption,
22
+ executeSearch,
23
+ } = useOrdersSearchAndFilter();
24
+ const t = useTranslations("Account.Orders");
25
+
26
+ const findOptionNameById = () => {
27
+ return (
28
+ searchOptions.find((opt) => opt.id === selectedSearchOption)?.name || ""
29
+ );
30
+ };
31
+
32
+ const INPUT_PROPS = {
33
+ sx: {
34
+ height: 44,
35
+ padding: 0,
36
+ overflow: "hidden",
37
+ backgroundColor: "grey.200",
38
+ "& .MuiOutlinedInput-notchedOutline": { border: 0 },
39
+ "& .MuiOutlinedInput-input": {
40
+ paddingLeft: 2,
41
+ paddingRight: 2,
42
+ },
43
+ },
44
+ startAdornment: (
45
+ <OrdersSearchDropdown
46
+ title={findOptionNameById()}
47
+ handleChange={setSelectedSearchOption}
48
+ searchOptions={searchOptions}
49
+ />
50
+ ),
51
+ endAdornment: (
52
+ <Button
53
+ onClick={executeSearch}
54
+ color="primary"
55
+ disableElevation
56
+ variant="contained"
57
+ sx={{ px: "3rem", height: "100%", borderRadius: "0 4px 4px 0" }}
58
+ >
59
+ {t("searchBtn")}
60
+ </Button>
61
+ ),
62
+ };
63
+
64
+ return (
65
+ <Box
66
+ position="relative"
67
+ flex="1 1 0"
68
+ maxWidth="670px"
69
+ mx="auto"
70
+ mr="auto"
71
+ ml="0px"
72
+ >
73
+ <TextField
74
+ fullWidth
75
+ variant="outlined"
76
+ placeholder={t("searchOrderHistoryPlaceholder")}
77
+ onChange={(e) => setSearchText(e.target.value)}
78
+ InputProps={INPUT_PROPS}
79
+ />
80
+ </Box>
81
+ );
82
+ };
83
+
84
+ export default OrdersSearchBar;
@@ -0,0 +1,53 @@
1
+ "use client";
2
+
3
+ import Menu from "@evenicanpm/storefront-core/src/components/BazaarMenu";
4
+ import TouchRipple from "@mui/material/ButtonBase";
5
+ import MenuItem from "@mui/material/MenuItem";
6
+ import useTheme from "@mui/material/styles/useTheme";
7
+ import { MdKeyboardArrowDown as KeyboardArrowDownOutlined } from "react-icons/md";
8
+ import type { DisplaySearchOption } from "./order-history-search-bar";
9
+ import { OrdersDropDownHandler } from "./orders-drop-down-handler";
10
+
11
+ interface Props {
12
+ title: string;
13
+ handleChange: (optionId: number) => void;
14
+ searchOptions: DisplaySearchOption[];
15
+ }
16
+
17
+ export default function OrdersSearchDropdown({
18
+ title,
19
+ handleChange,
20
+ searchOptions,
21
+ }: Props) {
22
+ const { breakpoints } = useTheme();
23
+ const _searchOptions = Array.isArray(searchOptions) ? searchOptions : [];
24
+ const options: DisplaySearchOption[] = [
25
+ ..._searchOptions.map((opt) => ({ name: opt?.name ?? "", id: opt.id })),
26
+ ];
27
+
28
+ return (
29
+ <Menu
30
+ direction="right"
31
+ sx={{ zIndex: breakpoints.down("md") ? 99999 : 1502 }}
32
+ handler={(e) => (
33
+ <OrdersDropDownHandler as={TouchRipple} onClick={e}>
34
+ {title}
35
+ <KeyboardArrowDownOutlined fontSize="small" color="inherit" />
36
+ </OrdersDropDownHandler>
37
+ )}
38
+ options={(onClose) => {
39
+ return options.map((item: DisplaySearchOption) => (
40
+ <MenuItem
41
+ key={item.id}
42
+ onClick={() => {
43
+ handleChange(item.id);
44
+ onClose();
45
+ }}
46
+ >
47
+ {item.name}
48
+ </MenuItem>
49
+ ));
50
+ }}
51
+ />
52
+ );
53
+ }
@@ -0,0 +1,90 @@
1
+ import type { SortColumn } from "@msdyn365-commerce/retail-proxy";
2
+ import { FormControl, InputLabel, MenuItem, Select } from "@mui/material";
3
+ import { useTranslations } from "next-intl";
4
+ import { useState } from "react";
5
+
6
+ interface SortOption {
7
+ id: number;
8
+ label: string;
9
+ columnName: string;
10
+ isDescending: boolean;
11
+ }
12
+
13
+ const sortOptions: SortOption[] = [
14
+ {
15
+ id: 0,
16
+ label: "Newest order placed",
17
+ columnName: "CREATEDDATETIME",
18
+ isDescending: true,
19
+ },
20
+ {
21
+ id: 1,
22
+ label: "Oldest order placed",
23
+ columnName: "CREATEDDATETIME",
24
+ isDescending: false,
25
+ },
26
+ {
27
+ id: 2,
28
+ label: "Newest confirmed ship date",
29
+ columnName: "CONFIRMEDSHIPDATE",
30
+ isDescending: true,
31
+ },
32
+ {
33
+ id: 3,
34
+ label: "Oldest confirmed ship date",
35
+ columnName: "CONFIRMEDSHIPDATE",
36
+ isDescending: false,
37
+ },
38
+ ];
39
+
40
+ interface OrderSortProps {
41
+ setSortColumn: (selectedSortColumn: SortColumn) => void;
42
+ }
43
+
44
+ export default function OrdersSort({ setSortColumn }: OrderSortProps) {
45
+ const [selectedSort, setSelectedSort] = useState<number>(0);
46
+ const t = useTranslations("Account.Orders");
47
+
48
+ const handleSelectSort = (sortId: number) => {
49
+ const sortColumn = getSortCriteria(sortId);
50
+ setSortColumn(sortColumn);
51
+ setSelectedSort(sortId);
52
+ };
53
+
54
+ const getSortCriteria = (sortId: number): SortColumn => {
55
+ const sortOption = sortOptions.find((e) => e.id === sortId);
56
+ if (sortOption) {
57
+ return {
58
+ ColumnName: sortOption.columnName,
59
+ IsDescending: sortOption.isDescending,
60
+ };
61
+ } else {
62
+ return {
63
+ ColumnName: "CREATEDDATETIME",
64
+ IsDescending: false,
65
+ };
66
+ }
67
+ };
68
+
69
+ return (
70
+ <FormControl
71
+ fullWidth
72
+ size="small"
73
+ sx={{ maxWidth: 240, backgroundColor: "#fff" }}
74
+ >
75
+ <InputLabel id="orders-sort-label">{t("sortByLabel")}</InputLabel>
76
+ <Select
77
+ labelId="orders-sort-label"
78
+ value={selectedSort}
79
+ label={t("sortByLabel")}
80
+ onChange={(e) => handleSelectSort(Number(e.target.value))}
81
+ >
82
+ {sortOptions.map((option) => (
83
+ <MenuItem key={option.id} value={option.id}>
84
+ {option.label}
85
+ </MenuItem>
86
+ ))}
87
+ </Select>
88
+ </FormControl>
89
+ );
90
+ }