@bjsdistribution/dms-client-return 0.1.19-dev → 0.1.20-dev

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 (24) hide show
  1. package/dist/components/client-portal/OutstandingTable.d.ts +3 -0
  2. package/dist/components/client-portal/ReturnStatus.d.ts +5 -0
  3. package/dist/components/client-portal/return-confirm/ConfirmedMain.d.ts +3 -0
  4. package/dist/components/client-portal/return-confirm/ReturnConfirmedTable.d.ts +3 -0
  5. package/dist/components/store.d.ts +5 -1
  6. package/dist/dms-client-return.cjs.development.js +1105 -296
  7. package/dist/dms-client-return.cjs.development.js.map +1 -1
  8. package/dist/dms-client-return.cjs.production.min.js +1 -1
  9. package/dist/dms-client-return.cjs.production.min.js.map +1 -1
  10. package/dist/dms-client-return.esm.js +1106 -297
  11. package/dist/dms-client-return.esm.js.map +1 -1
  12. package/package.json +1 -1
  13. package/src/components/client-portal/OutstandingTable.tsx +412 -0
  14. package/src/components/client-portal/ReturnAfterSearchBar.tsx +116 -11
  15. package/src/components/client-portal/ReturnOverview.tsx +4 -4
  16. package/src/components/client-portal/ReturnRTFilters.tsx +59 -40
  17. package/src/components/client-portal/ReturnSearchBar.tsx +90 -9
  18. package/src/components/client-portal/ReturnStatus.tsx +36 -3
  19. package/src/components/client-portal/return-confirm/ConfirmedMain.tsx +235 -0
  20. package/src/components/client-portal/return-confirm/ReturnConfirmedTable.tsx +404 -0
  21. package/src/components/order-daily-overview/return-after-table/ReturnAfterTable.tsx +18 -38
  22. package/src/components/order-daily-overview/return-after-table/table/OrderTable.tsx +18 -24
  23. package/src/components/order-daily-overview/return-order-table/return-orders-filters/ReturnOrderTable.tsx +35 -146
  24. package/src/components/store.ts +23 -0
@@ -0,0 +1,404 @@
1
+ import { Empty } from 'antd';
2
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
3
+ import { Skeleton } from 'antd';
4
+ import { NavLink } from 'react-router-dom';
5
+ import {
6
+ Checkbox,
7
+ displayValueOrNA,
8
+ // useApiHook,
9
+ } from '@bjsdistribution/dms-component-library';
10
+ import {
11
+ useLoading,
12
+ usePrintOptionTOggle,
13
+ } from '../../order-daily-overview/store/store';
14
+ import {
15
+ useReturnConfirmedOrderData,
16
+ useSelectedClientAfterOrders,
17
+ } from '../../store';
18
+ import { useOrderId } from '../../order-view/store';
19
+ import SortIcon from '../../../common/SortIcon';
20
+ import CaretDownFilledIcon from '../../../common/CaretDownFilledIcon';
21
+ import {
22
+ CustomDrop,
23
+ EmptyDataContainer,
24
+ StyledTable,
25
+ StyledTableWrapper,
26
+ } from '../../order-daily-overview/return-order-table/return-orders-filters/returnstyles';
27
+ import PrinterIcon from '../../../assets/icons/PrinterIcon';
28
+ import DownIcon from '../../../assets/icons/DownIcon';
29
+ import PrintDropDown from '../../order-daily-overview/shared/elements/PrintDropDown';
30
+ import { formatDate } from '../../order-daily-overview/shared/utlis';
31
+
32
+ const ReturnConfirmedTable = () => {
33
+ const dropdownRefParent = useRef<HTMLDivElement>(null);
34
+ const dropdownRef = useRef<HTMLDivElement>(null);
35
+ const [printToogle, setPrintToggle] = usePrintOptionTOggle();
36
+ const [, setOrderId] = useOrderId();
37
+ const [returnConfirmedTable] = useReturnConfirmedOrderData();
38
+ const [loading] = useLoading();
39
+ const [selectClientAll, setSelectClientAll] = useState(false);
40
+ const [
41
+ selectedOrderIds,
42
+ setSelectedOrderIds,
43
+ ] = useSelectedClientAfterOrders();
44
+ //sorting
45
+ const [sortConfig, setSortConfig] = useState<{
46
+ key: string;
47
+ direction: 'asc' | 'desc';
48
+ } | null>(null);
49
+
50
+ const handleSort = (key: string) => {
51
+ setSortConfig((prev: any) => {
52
+ if (prev?.key === key && prev.direction === 'asc') {
53
+ return { key, direction: 'desc' };
54
+ }
55
+ return { key, direction: 'asc' };
56
+ });
57
+ };
58
+
59
+ const sortedData = useMemo(() => {
60
+ if (!returnConfirmedTable || !sortConfig) return returnConfirmedTable;
61
+
62
+ const { key, direction } = sortConfig;
63
+ return [...returnConfirmedTable].sort((a, b) => {
64
+ const valueA = a[key];
65
+ const valueB = b[key];
66
+
67
+ if (typeof valueA === 'number' && typeof valueB === 'number') {
68
+ return direction === 'asc' ? valueA - valueB : valueB - valueA;
69
+ }
70
+ if (typeof valueA === 'string' && typeof valueB === 'string') {
71
+ return direction === 'asc'
72
+ ? valueA.localeCompare(valueB)
73
+ : valueB.localeCompare(valueA);
74
+ }
75
+ return 0;
76
+ });
77
+ }, [returnConfirmedTable, sortConfig]);
78
+
79
+ const renderSortIcon = (columnKey: string) => {
80
+ if (!sortConfig || sortConfig.key !== columnKey) {
81
+ return <SortIcon />;
82
+ }
83
+ return sortConfig.direction === 'asc' ? (
84
+ <CaretDownFilledIcon />
85
+ ) : (
86
+ <CaretDownFilledIcon />
87
+ );
88
+ };
89
+
90
+ const OpenDropDown = (index: number) => {
91
+ setPrintToggle((prevIndex: any) => (prevIndex === index ? null : index));
92
+ };
93
+
94
+ // Close dropdown outside click
95
+ useEffect(() => {
96
+ document.addEventListener('mousedown', handleClickOutside);
97
+ return () => {
98
+ document.removeEventListener('mousedown', handleClickOutside);
99
+ };
100
+ }, []);
101
+ const handleClickOutside = (event: MouseEvent) => {
102
+ if (
103
+ dropdownRef.current &&
104
+ !dropdownRef.current.contains(event.target as Node)
105
+ ) {
106
+ setPrintToggle(null);
107
+ }
108
+ };
109
+
110
+ // const handleSelectAll = (e: any) => {
111
+ // setSelectAll(e.target.checked);
112
+ // if (e.target.checked) {
113
+ // setSelectedReturnOrder(
114
+ // returnAfterOrder.map((e: any) => ({
115
+ // id: e.id,
116
+ // status_id: 3,
117
+ // }))
118
+ // );
119
+ // } else {
120
+ // setSelectedReturnOrder([]);
121
+ // }
122
+ // };
123
+
124
+ // const handleSelectInvoice = (id: any) => {
125
+ // setSelectedReturnOrder((prevSelectedInvoices: any) => {
126
+ // const isSelected = prevSelectedInvoices?.some(
127
+ // (item: any) => item.id === id
128
+ // );
129
+
130
+ // if (isSelected) {
131
+ // return prevSelectedInvoices.filter((items: any) => items.id !== id);
132
+ // } else {
133
+ // return [...prevSelectedInvoices, { id, status_id: 3 }];
134
+ // }
135
+ // });
136
+ // };
137
+
138
+ const getStatusClass = (status: string) => {
139
+ switch (status) {
140
+ case 'Cancelled':
141
+ return { color: '#E95252', background: 'rgba(233, 82, 82, 0.15)' };
142
+ case 'On Hold':
143
+ return { color: '#F4A503', background: '#FFF1D6' };
144
+ case 'Sub-Contracted':
145
+ return { color: '#F4A503', background: '#FFF1D6' };
146
+ case 'Awaiting route':
147
+ return { color: '#845ADF', background: 'rgba(132, 90, 223, 0.15)' };
148
+ case 'Awaiting':
149
+ return { color: '#845ADF', background: 'rgba(132, 90, 223, 0.15)' };
150
+ case 'Completed':
151
+ return {
152
+ color: '#1F9254',
153
+ background: 'rgba(41, 204, 106, 0.15)',
154
+ };
155
+ case 'Outstanding':
156
+ return { color: '#FF9900', background: 'rgba(255, 153, 0, 0.15)' };
157
+ case 'Routed':
158
+ return { color: '#6396E5', background: 'rgba(99, 150, 229, 0.15)' };
159
+ default:
160
+ return { color: '#000', background: '#fff' };
161
+ }
162
+ };
163
+
164
+ // API for Assign
165
+ // const {
166
+ // data: actionResponse,
167
+ // setShouldPerformAction: setAssignAction,
168
+ // error: apiError,
169
+ // } = useApiHook<{
170
+ // data: ApiResponse[];
171
+ // }>({
172
+ // endpoint: `return_orders/update/assign/`,
173
+ // method: 'PUT',
174
+ // body: [assignPayload],
175
+ // performAction: false,
176
+ // });
177
+
178
+ //client options
179
+ // const assignOptions = assignData?.map((option: any) => ({
180
+ // label: option?.type?.charAt(0)?.toUpperCase() + option?.type?.slice(1),
181
+ // value: option?.bjs_delivery,
182
+ // }));
183
+
184
+ // const handleAssignPayload = (Id: number, value: boolean) => {
185
+ // setCallAPi(false);
186
+ // setAssign(value);
187
+ // setAssignPayload({
188
+ // ...assignPayload,
189
+ // return_order_id: Id,
190
+ // bjs_delivery: value,
191
+ // });
192
+ // setAssignAction(true);
193
+ // };
194
+
195
+ // useEffect(() => {
196
+ // //@ts-ignore
197
+ // if (actionResponse?.code === 200) {
198
+ // setCallAPi(true);
199
+ // notification.success({
200
+ // message: 'Success',
201
+ // // @ts-ignore
202
+ // description: `${actionResponse?.message}`,
203
+ // });
204
+ // // @ts-ignore
205
+ // } else if (apiError?.detail) {
206
+ // notification.error({
207
+ // message: 'Failure',
208
+ // // @ts-ignore
209
+ // description: `${apiError?.detail[0]?.msg}`,
210
+ // });
211
+ // }
212
+ // }, [actionResponse, apiError]);
213
+
214
+ const handleSelectOrderId = (id: string | number) => {
215
+ setSelectedOrderIds(prev =>
216
+ prev.includes(id) ? prev.filter(orderId => orderId !== id) : [...prev, id]
217
+ );
218
+ };
219
+ const handleClientSelectAll = (e: React.ChangeEvent<HTMLInputElement>) => {
220
+ const isChecked = e.target.checked;
221
+ setSelectClientAll(isChecked);
222
+
223
+ if (isChecked) {
224
+ setSelectedOrderIds(
225
+ returnConfirmedTable?.map((item: any) => item?.id) || []
226
+ );
227
+ } else {
228
+ setSelectedOrderIds([]);
229
+ }
230
+ };
231
+ console.log('selectedOrderIds===>', selectedOrderIds);
232
+ console.log('returnConfirmedTable=====>', returnConfirmedTable);
233
+ return (
234
+ <>
235
+ <StyledTableWrapper className="fortables">
236
+ <StyledTable>
237
+ <thead>
238
+ <tr>
239
+ {/* <th className="emailInvoiceCheckbox">
240
+ <Checkbox checked={false} />
241
+ </th> */}
242
+ <th className="emailInvoiceCheckbox">
243
+ <Checkbox
244
+ checked={selectClientAll}
245
+ onChange={handleClientSelectAll}
246
+ />
247
+ </th>
248
+ <th onClick={() => handleSort('created_at')}>
249
+ <div className="sortIconClass">
250
+ Created {renderSortIcon('created_at')}
251
+ </div>
252
+ </th>
253
+ <th onClick={() => handleSort('return_location_name')}>
254
+ <div className="sortIconClass">
255
+ Return Location {renderSortIcon('return_location_name')}
256
+ </div>
257
+ </th>
258
+ <th onClick={() => handleSort('recipient_name')}>
259
+ <div className="sortIconClass">
260
+ Recipient {renderSortIcon('recipient_name')}
261
+ </div>
262
+ </th>
263
+ <th> Client</th>
264
+ <th>Consignment</th>
265
+ <th>Return Order No</th>
266
+ <th> Total Parts</th>
267
+ <th onClick={() => handleSort('weight')}>
268
+ <div className="sortIconClass">
269
+ Total Weight {renderSortIcon('weight')}
270
+ </div>
271
+ </th>
272
+ <th onClick={() => handleSort('cube')}>
273
+ <div className="sortIconClass">
274
+ Total CBM {renderSortIcon('cube')}
275
+ </div>
276
+ </th>
277
+ <th>Status</th>
278
+ <th className="emailInvoiceShare">Labels</th>
279
+ </tr>
280
+ </thead>
281
+ <tbody>
282
+ {loading ? (
283
+ <tr>
284
+ <td colSpan={16}>
285
+ <Skeleton active />
286
+ </td>
287
+ <td colSpan={16}></td>
288
+ </tr>
289
+ ) : sortedData?.length === 0 ? (
290
+ <tr>
291
+ <td colSpan={16}>
292
+ <EmptyDataContainer>
293
+ <Empty />
294
+ </EmptyDataContainer>
295
+ </td>
296
+ </tr>
297
+ ) : (
298
+ sortedData?.map((item: any, index: any) => {
299
+ const statusMapping: any = {
300
+ cancelled: 'Cancelled',
301
+ 'on hold': 'On Hold',
302
+ SC: 'Sub-Contracted',
303
+ 'awaiting route': 'Awaiting',
304
+ 'awaiting confirmation': 'Awaiting',
305
+ complete: 'Completed',
306
+ outstanding: 'Outstanding',
307
+ routed: 'Routed',
308
+ failed: 'Failed',
309
+ };
310
+ const status = statusMapping[item?.status_value] || 'Unknown';
311
+ const statusClass = getStatusClass(status);
312
+
313
+ return (
314
+ <tr key={item.id}>
315
+ <td>
316
+ <Checkbox
317
+ checked={selectedOrderIds.includes(item?.id)}
318
+ onChange={() => handleSelectOrderId(item?.id)}
319
+ />
320
+ </td>
321
+ <td>{formatDate(new Date(item?.created_at))}</td>
322
+ <td>{displayValueOrNA(item?.return_location_name)}</td>
323
+ <td onClick={() => setOrderId(item.id)}>
324
+ <ul style={{ listStyleType: 'none', padding: 0 }}>
325
+ <li
326
+ style={{
327
+ color: '#0099ff',
328
+ fontWeight: 600,
329
+ paddingLeft: 0,
330
+ }}
331
+ >
332
+ <NavLink to={`../${item.id}`}>
333
+ {displayValueOrNA(item?.recipient_name)}
334
+ </NavLink>
335
+ </li>
336
+ <li style={{ color: '#888075' }}>
337
+ {displayValueOrNA(item?.postcode)}
338
+ </li>
339
+ </ul>
340
+ </td>
341
+
342
+ <td>{displayValueOrNA(item?.customer_name)}</td>
343
+
344
+ <td>{displayValueOrNA(item?.consignment)}</td>
345
+ <td>{displayValueOrNA(item?.order_number)}</td>
346
+
347
+ <td>{displayValueOrNA(item?.total_products)}</td>
348
+ <td>
349
+ {displayValueOrNA(item?.weight)}{' '}
350
+ {item?.weight && item?.weight > 0 ? 'KG' : ''}
351
+ </td>
352
+
353
+ <td>{displayValueOrNA(item?.cube)}</td>
354
+
355
+ <td>
356
+ <ul
357
+ className="statuscontainer"
358
+ style={{
359
+ listStyleType: 'none',
360
+ background: statusClass.background,
361
+ }}
362
+ >
363
+ <li
364
+ className="statustext"
365
+ style={{ color: statusClass.color }}
366
+ >
367
+ {status}
368
+ </li>
369
+ </ul>
370
+ </td>
371
+ <td>
372
+ <ul className="actionbox">
373
+ <CustomDrop
374
+ ref={dropdownRefParent}
375
+ className={printToogle === index ? 'active' : ''}
376
+ >
377
+ <li
378
+ className="shareIconContainer"
379
+ onClick={() => OpenDropDown(index)}
380
+ >
381
+ <PrinterIcon />
382
+ <DownIcon />
383
+
384
+ {printToogle === index && (
385
+ <div ref={dropdownRef}>
386
+ <PrintDropDown legacyProductId={item} />
387
+ </div>
388
+ )}
389
+ </li>
390
+ </CustomDrop>
391
+ </ul>
392
+ </td>
393
+ </tr>
394
+ );
395
+ })
396
+ )}
397
+ </tbody>
398
+ </StyledTable>
399
+ </StyledTableWrapper>
400
+ </>
401
+ );
402
+ };
403
+
404
+ export default ReturnConfirmedTable;
@@ -10,19 +10,14 @@ import {
10
10
  UsePaginationReturnData,
11
11
  } from '../store/store';
12
12
  import { ApiResponse } from '../common/interface';
13
- import { useAxios } from '@bjsdistribution/dms-component-library';
13
+ import { useApiHook } from '@bjsdistribution/dms-component-library';
14
14
  import { filtersReducerReturnAtom } from './table-filters/ReturnFilterStore';
15
15
  import { notification } from 'antd';
16
16
  import ReturnPagination from '../table-view/ReturnPagination';
17
- import {
18
- useCallApiAgain,
19
- useClientPortal,
20
- useSearchAfterText,
21
- } from '../../store';
22
- import { useParams } from 'react-router-dom';
17
+ import { useCallApiAgain } from '../../store';
23
18
 
24
19
  const ReturnAfterTable = () => {
25
- const [, setReturnOrderData] = useReturnAfterOrderData();
20
+ const [returnAfterOrder, setReturnOrderData] = useReturnAfterOrderData();
26
21
  const [, setLoading] = useLoading();
27
22
  const [state] = useAtom(filtersReducerReturnAtom);
28
23
  const [callApi] = useCallApiAgain();
@@ -33,69 +28,54 @@ const ReturnAfterTable = () => {
33
28
  const [itemsPerPage, setItemsPerPage] = useItemsPerReturnPage();
34
29
  const [, setPaginationObject] = UsePaginationData();
35
30
  const { page, total } = paginationObj;
36
- const [clientPortal] = useClientPortal();
37
- const [debouncedSearchText] = useSearchAfterText();
31
+
38
32
  const handlePageChange = (page: number) => {
39
33
  setCurrentPage(page);
40
34
  };
41
35
  const handleItemsPerPageChange = (itemsPerPage: number) => {
42
36
  setItemsPerPage(itemsPerPage);
43
37
  };
44
- const { status } = useParams();
45
38
 
46
39
  const {
47
40
  data: fetchedReturnOrderData,
48
41
  loading,
42
+ setShouldPerformAction,
49
43
  paginationData,
50
- fetchData,
51
- } = useAxios<ApiResponse>({
44
+ } = useApiHook<ApiResponse>({
52
45
  endpoint: '/v1/return/orders/',
53
46
  method: 'GET',
54
47
  filters: filters && filters?.length > 0 ? filters : undefined,
55
48
  pagination: pagination,
49
+ performAction: false,
56
50
  });
57
51
 
58
52
  useEffect(() => {
59
- if (callApi) {
60
- fetchData();
61
- }
53
+ callApi ? setShouldPerformAction(true) : setShouldPerformAction(false);
62
54
  }, [callApi]);
63
55
 
64
- useEffect(() => {
65
- if (!clientPortal) {
66
- fetchData();
67
- }
68
- }, []);
69
-
70
- //CP
71
- useEffect(() => {
72
- if (clientPortal && debouncedSearchText.trim().length === 0) {
73
- fetchData();
74
- }
75
- }, [debouncedSearchText, clientPortal, status]);
76
-
77
56
  useEffect(() => {
78
57
  setLoading(loading);
79
-
80
- if (
81
- fetchedReturnOrderData?.data &&
82
- (!clientPortal || debouncedSearchText.trim().length === 0)
83
- ) {
84
- setReturnOrderData(fetchedReturnOrderData.data);
85
-
58
+ if (fetchedReturnOrderData && fetchedReturnOrderData?.data) {
59
+ setReturnOrderData(fetchedReturnOrderData?.data);
86
60
  if (paginationData) {
87
61
  try {
88
62
  const { count, ...rest } = JSON.parse(paginationData);
89
63
  setPaginationObject(rest);
90
64
  } catch (error) {
65
+ console.error('Error parsing paginationData:', error);
91
66
  notification.error({
92
67
  message: 'Error',
93
68
  description: 'Failed to parse pagination data',
94
69
  });
95
70
  }
71
+ } else {
72
+ notification.error({
73
+ message: 'Error',
74
+ description: 'Pagination data is null or undefined',
75
+ });
96
76
  }
97
77
  }
98
- }, [fetchedReturnOrderData, loading]);
78
+ }, [fetchedReturnOrderData, loading, returnAfterOrder]);
99
79
 
100
80
  return (
101
81
  <div>
@@ -104,7 +84,7 @@ const ReturnAfterTable = () => {
104
84
  <div className="Tableconatiner">
105
85
  {/* <HeaderFilter /> */}
106
86
  <Container>
107
- {!clientPortal && <ReturnOrderFilter />}
87
+ <ReturnOrderFilter />
108
88
  <OrderTable />
109
89
  {total > 0 && (
110
90
  <ReturnPagination
@@ -19,7 +19,6 @@ import {
19
19
  useAssignData,
20
20
  useAssignPayload,
21
21
  useCallApiAgain,
22
- useClientPortal,
23
22
  } from '../../../store';
24
23
  import styled from 'styled-components';
25
24
  import { useApiHook } from '@bjsdistribution/dms-component-library';
@@ -40,7 +39,6 @@ const OrderTable = () => {
40
39
  const [, setAssign] = useState<boolean>(false);
41
40
  const [, setCallAPi] = useCallApiAgain();
42
41
  const [loading] = useLoading();
43
- const [clientPortal] = useClientPortal();
44
42
 
45
43
  //sorting
46
44
  const [sortConfig, setSortConfig] = useState<{
@@ -231,7 +229,7 @@ const OrderTable = () => {
231
229
  Return Location {renderSortIcon('return_location_name')}
232
230
  </div>
233
231
  </th>
234
- {!clientPortal && <th>Pick Up Location</th>}
232
+ <th>Pick Up Location</th>
235
233
  <th onClick={() => handleSort('recipient_name')}>
236
234
  <div className="sortIconClass">
237
235
  Recipient {renderSortIcon('recipient_name')}
@@ -251,7 +249,7 @@ const OrderTable = () => {
251
249
  Total CBM {renderSortIcon('cube')}
252
250
  </div>
253
251
  </th>
254
- {!clientPortal && <th>Assign</th>}
252
+ <th>Assign</th>
255
253
  <th>Status</th>
256
254
  <th className="emailInvoiceShare">Labels</th>
257
255
  </tr>
@@ -299,13 +297,11 @@ const OrderTable = () => {
299
297
  <td>{formatDate(new Date(item?.created_at))}</td>
300
298
  <td>{displayValueOrNA(item?.return_location_name)}</td>
301
299
 
302
- {!clientPortal && (
303
- <td>
304
- {item?.locations?.length
305
- ? item?.locations.join(', ')
306
- : 'N/A'}
307
- </td>
308
- )}
300
+ <td>
301
+ {item?.locations?.length
302
+ ? item?.locations.join(', ')
303
+ : 'N/A'}
304
+ </td>
309
305
 
310
306
  <td onClick={() => setOrderId(item.id)}>
311
307
  <ul style={{ listStyleType: 'none', padding: 0 }}>
@@ -339,19 +335,17 @@ const OrderTable = () => {
339
335
 
340
336
  <td>{displayValueOrNA(item?.cube)}</td>
341
337
 
342
- {!clientPortal && (
343
- <td key={item.id}>
344
- <StyledAntSelect
345
- options={assignOptions}
346
- placeholder="Select"
347
- onChange={(value: any) =>
348
- handleAssignPayload(item?.id, value)
349
- }
350
- style={{ width: '150px' }}
351
- value={item?.bjs_delivery}
352
- />
353
- </td>
354
- )}
338
+ <td key={item.id}>
339
+ <StyledAntSelect
340
+ options={assignOptions}
341
+ placeholder="Select"
342
+ onChange={(value: any) =>
343
+ handleAssignPayload(item?.id, value)
344
+ }
345
+ style={{ width: '150px' }}
346
+ value={item?.bjs_delivery}
347
+ />
348
+ </td>
355
349
 
356
350
  <td>
357
351
  <ul