@licklist/design 0.44.489 → 0.44.491
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.
- package/dist/customers/components/filter/CustomerFilter.d.ts +13 -0
- package/dist/customers/components/filter/CustomerFilter.d.ts.map +1 -0
- package/dist/customers/components/filter/CustomerFilter.js +1 -0
- package/dist/customers/components/filter/index.d.ts +3 -0
- package/dist/customers/components/filter/index.d.ts.map +1 -0
- package/dist/customers/components/index.d.ts +2 -0
- package/dist/customers/components/index.d.ts.map +1 -0
- package/dist/customers/index.d.ts +2 -0
- package/dist/customers/index.d.ts.map +1 -0
- package/dist/events/event-statistic-modal/EventStatisticModal.js +1 -1
- package/dist/iframe/payment/order-items-table/OrderItemsTable.js +1 -1
- package/dist/iframe/payment/payment-form/PaymentForm.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/product-set/form/ProductsControl.d.ts.map +1 -1
- package/dist/product-set/form/ProductsControl.js +1 -1
- package/dist/sales/guest-profile/previous-bookings/PreviousBookings.d.ts +3 -2
- package/dist/sales/guest-profile/previous-bookings/PreviousBookings.d.ts.map +1 -1
- package/dist/sales/guest-profile/previous-bookings/PreviousBookings.js +1 -1
- package/dist/sales/notes/NotesTableRow.js +1 -1
- package/dist/setting/dashboard/snippets/card/SnippetCard.js +1 -1
- package/dist/styles/customers/Filter.scss +53 -0
- package/dist/styles/customers/_index.scss +1 -0
- package/dist/styles/packages.scss +1 -0
- package/dist/table/ReactTableHelperComponent.d.ts +12 -0
- package/dist/table/ReactTableHelperComponent.d.ts.map +1 -0
- package/dist/table/ReactTableHelperComponent.js +1 -0
- package/dist/table/TableHelperComponent.d.ts +2 -3
- package/dist/table/TableHelperComponent.d.ts.map +1 -1
- package/dist/table/hooks/useTableQueryOptions.d.ts +20 -0
- package/dist/table/hooks/useTableQueryOptions.d.ts.map +1 -0
- package/dist/table/hooks/useTableQueryOptions.js +1 -0
- package/dist/table/index.d.ts +1 -0
- package/dist/table/index.d.ts.map +1 -1
- package/dist/table/types.d.ts +41 -0
- package/dist/table/types.d.ts.map +1 -0
- package/dist/table/utils/index.d.ts +1 -0
- package/dist/table/utils/index.d.ts.map +1 -1
- package/dist/table/utils/index.js +1 -1
- package/package.json +2 -1
- package/src/customers/components/filter/CustomerFilter.stories.tsx +18 -0
- package/src/customers/components/filter/CustomerFilter.tsx +48 -0
- package/src/customers/components/filter/index.ts +2 -0
- package/src/customers/components/index.ts +1 -0
- package/src/customers/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/product-set/form/ProductsControl.tsx +20 -1
- package/src/sales/guest-profile/previous-bookings/PreviousBookings.stories.tsx +35 -5
- package/src/sales/guest-profile/previous-bookings/PreviousBookings.tsx +11 -3
- package/src/styles/customers/Filter.scss +53 -0
- package/src/styles/customers/_index.scss +1 -0
- package/src/styles/packages.scss +1 -0
- package/src/table/ReactTableHelperComponent.tsx +321 -0
- package/src/table/Table.stories.tsx +127 -1
- package/src/table/TableHelperComponent.tsx +3 -1
- package/src/table/hooks/useTableQueryOptions.ts +49 -0
- package/src/table/index.ts +1 -0
- package/src/table/types.ts +47 -0
- package/src/table/utils/index.ts +2 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Meta, Story } from "@storybook/react";
|
|
3
|
+
import { CustomerFilter, CustomerFilterProps } from "./CustomerFilter";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: "Customers/Filter",
|
|
7
|
+
component: CustomerFilter,
|
|
8
|
+
} as Meta;
|
|
9
|
+
|
|
10
|
+
export const Default: Story<CustomerFilterProps> = () => {
|
|
11
|
+
const [values, setValues] = useState({
|
|
12
|
+
name: "",
|
|
13
|
+
email: "",
|
|
14
|
+
phone: "",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return <CustomerFilter values={values} onChange={setValues} />;
|
|
18
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useTranslation } from "react-i18next";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import { TextField } from "../../../static/TextField";
|
|
5
|
+
|
|
6
|
+
type CustomerFilterValues = {
|
|
7
|
+
name: string;
|
|
8
|
+
email: string;
|
|
9
|
+
phone: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const FILTER_FIELDS = {
|
|
13
|
+
name: "name",
|
|
14
|
+
email: "email",
|
|
15
|
+
phone: "phone",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export interface CustomerFilterProps {
|
|
19
|
+
values: CustomerFilterValues;
|
|
20
|
+
onChange: (values: CustomerFilterValues) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const CustomerFilter = ({ values, onChange }: CustomerFilterProps) => {
|
|
24
|
+
const { t } = useTranslation(["Design"]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="customers-filter d-flex">
|
|
28
|
+
<div className="d-flex customers-filter-items">
|
|
29
|
+
{Object.keys(FILTER_FIELDS).map((filterKeyName) => {
|
|
30
|
+
const label = t(FILTER_FIELDS[filterKeyName]);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<TextField
|
|
34
|
+
key={filterKeyName}
|
|
35
|
+
className={clsx("mb-0", "col-4", "customer-filter")}
|
|
36
|
+
type="text"
|
|
37
|
+
label={label}
|
|
38
|
+
value={values[filterKeyName]}
|
|
39
|
+
onChange={(event) =>
|
|
40
|
+
onChange({ ...values, [filterKeyName]: event.target.value })
|
|
41
|
+
}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
})}
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./filter";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./components";
|
package/src/index.ts
CHANGED
|
@@ -85,11 +85,14 @@ export function ProductsControl({
|
|
|
85
85
|
trigger,
|
|
86
86
|
setValue,
|
|
87
87
|
watch,
|
|
88
|
+
getValues,
|
|
88
89
|
} = form;
|
|
89
90
|
|
|
90
91
|
const productControlFieldName =
|
|
91
92
|
`steps.${stepIndex}.productCategories.${productCategoryIndex}.products` as const;
|
|
92
93
|
|
|
94
|
+
const productPointsKey = `steps.${stepIndex}.pointProducts` as const;
|
|
95
|
+
|
|
93
96
|
const { fields, append, remove, move } = useFieldArray({
|
|
94
97
|
name: productControlFieldName,
|
|
95
98
|
control,
|
|
@@ -156,6 +159,22 @@ export function ProductsControl({
|
|
|
156
159
|
});
|
|
157
160
|
};
|
|
158
161
|
|
|
162
|
+
const onProductRemove = (index: number) => {
|
|
163
|
+
const currentProduct = getValues(
|
|
164
|
+
`${productControlFieldName}.${index}` as const
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const currentPointProducts = getValues(productPointsKey);
|
|
168
|
+
|
|
169
|
+
setValue(
|
|
170
|
+
productPointsKey,
|
|
171
|
+
currentPointProducts?.filter(
|
|
172
|
+
(product) => product.productUuid !== currentProduct.uuid
|
|
173
|
+
) || []
|
|
174
|
+
);
|
|
175
|
+
remove(index);
|
|
176
|
+
};
|
|
177
|
+
|
|
159
178
|
return (
|
|
160
179
|
<>
|
|
161
180
|
<SortableTree
|
|
@@ -219,7 +238,7 @@ export function ProductsControl({
|
|
|
219
238
|
categoryType={categoryType}
|
|
220
239
|
/>
|
|
221
240
|
}
|
|
222
|
-
onDelete={() =>
|
|
241
|
+
onDelete={() => onProductRemove(index)}
|
|
223
242
|
validate={() => trigger(`${productControlFieldName}.${index}`)}
|
|
224
243
|
// preItem={<Popover className="d-none d-sm-block" />}
|
|
225
244
|
>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Meta } from "@storybook/react";
|
|
3
|
+
import { boolean } from "@storybook/addon-knobs";
|
|
3
4
|
import { Event } from "@licklist/core/dist/DataMapper/Provider/EventDataMapper";
|
|
4
5
|
import { User } from "@licklist/core/dist/DataMapper/User/UserDataMapper";
|
|
5
6
|
import { Product } from "@licklist/core/dist/DataMapper/Product/ProductDataMapper";
|
|
@@ -10,11 +11,26 @@ export default {
|
|
|
10
11
|
title: "Sales/Guest Profile/Previous Bookings",
|
|
11
12
|
} as Meta;
|
|
12
13
|
|
|
13
|
-
export const Default = (args) =>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
export const Default = (args) => {
|
|
15
|
+
const useProviderLink = boolean("useProviderLink", true);
|
|
16
|
+
|
|
17
|
+
const renderOrderTitleLinkByProvider = (order: Order) => {
|
|
18
|
+
return (
|
|
19
|
+
<a href={`/some_href/${order.id}`}>{order[order.orderableType]?.name}</a>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div>
|
|
25
|
+
<PreviousBookings
|
|
26
|
+
{...args}
|
|
27
|
+
renderOrderTitleLinkByProvider={
|
|
28
|
+
useProviderLink ? renderOrderTitleLinkByProvider : undefined
|
|
29
|
+
}
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
18
34
|
|
|
19
35
|
Default.args = {
|
|
20
36
|
orders: [
|
|
@@ -43,6 +59,8 @@ Default.args = {
|
|
|
43
59
|
updatedAt: "2022-05-20 18:28:56",
|
|
44
60
|
status: "cart",
|
|
45
61
|
tickets: [],
|
|
62
|
+
orderableType: "event",
|
|
63
|
+
orderableId: 1,
|
|
46
64
|
event: {
|
|
47
65
|
id: 1,
|
|
48
66
|
name: "testEvent1",
|
|
@@ -79,6 +97,8 @@ Default.args = {
|
|
|
79
97
|
updatedAt: "2022-05-20 18:28:56",
|
|
80
98
|
status: "cart",
|
|
81
99
|
tickets: [],
|
|
100
|
+
orderableType: "event",
|
|
101
|
+
orderableId: 2,
|
|
82
102
|
event: {
|
|
83
103
|
id: 2,
|
|
84
104
|
name: "testEvent2",
|
|
@@ -128,6 +148,8 @@ Default.args = {
|
|
|
128
148
|
updatedAt: "2022-05-20 18:28:56",
|
|
129
149
|
status: "cart",
|
|
130
150
|
tickets: [],
|
|
151
|
+
orderableType: "event",
|
|
152
|
+
orderableId: 3,
|
|
131
153
|
event: {
|
|
132
154
|
id: 3,
|
|
133
155
|
name: "testEvent3",
|
|
@@ -156,6 +178,8 @@ Default.args = {
|
|
|
156
178
|
updatedAt: "2022-05-20 18:28:56",
|
|
157
179
|
status: "cart",
|
|
158
180
|
tickets: [],
|
|
181
|
+
orderableType: "event",
|
|
182
|
+
orderableId: 3,
|
|
159
183
|
event: {
|
|
160
184
|
id: 3,
|
|
161
185
|
name: "testEvent3",
|
|
@@ -184,6 +208,8 @@ Default.args = {
|
|
|
184
208
|
updatedAt: "2022-05-20 18:28:56",
|
|
185
209
|
status: "cart",
|
|
186
210
|
tickets: [],
|
|
211
|
+
orderableType: "event",
|
|
212
|
+
orderableId: 3,
|
|
187
213
|
event: {
|
|
188
214
|
id: 3,
|
|
189
215
|
name: "testEvent3",
|
|
@@ -212,6 +238,8 @@ Default.args = {
|
|
|
212
238
|
updatedAt: "2022-05-20 18:28:56",
|
|
213
239
|
status: "cart",
|
|
214
240
|
tickets: [],
|
|
241
|
+
orderableType: "event",
|
|
242
|
+
orderableId: 3,
|
|
215
243
|
event: {
|
|
216
244
|
id: 3,
|
|
217
245
|
name: "testEvent3",
|
|
@@ -239,6 +267,8 @@ Default.args = {
|
|
|
239
267
|
updatedAt: "2022-05-20 18:28:56",
|
|
240
268
|
status: "cart",
|
|
241
269
|
tickets: [],
|
|
270
|
+
orderableType: "event",
|
|
271
|
+
orderableId: 3,
|
|
242
272
|
event: {
|
|
243
273
|
id: 3,
|
|
244
274
|
name: "testEvent3",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
1
|
+
import React, { useState, ReactNode } from "react";
|
|
2
2
|
import { useTranslation } from "react-i18next";
|
|
3
3
|
import { DateTime } from "luxon";
|
|
4
4
|
import { Button } from "react-bootstrap";
|
|
@@ -8,9 +8,13 @@ const MAX_ORDERS_COUNT = 6;
|
|
|
8
8
|
|
|
9
9
|
export type PreviousBookingsProps = {
|
|
10
10
|
orders: Order[];
|
|
11
|
+
renderOrderTitleLinkByProvider?: (order: Order) => ReactNode;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
|
-
export const PreviousBookings = ({
|
|
14
|
+
export const PreviousBookings = ({
|
|
15
|
+
orders,
|
|
16
|
+
renderOrderTitleLinkByProvider,
|
|
17
|
+
}: PreviousBookingsProps) => {
|
|
14
18
|
const { t } = useTranslation("Design");
|
|
15
19
|
const [showOlderBookings, setShowOlderBookings] = useState(false);
|
|
16
20
|
|
|
@@ -36,13 +40,17 @@ export const PreviousBookings = ({ orders }: PreviousBookingsProps) => {
|
|
|
36
40
|
{orders.length > 0 ? (
|
|
37
41
|
<div className="events-wrapper">
|
|
38
42
|
{orders.slice(0, endSlicedOrdersNumber).map((order) => {
|
|
43
|
+
const eventName = renderOrderTitleLinkByProvider
|
|
44
|
+
? renderOrderTitleLinkByProvider(order)
|
|
45
|
+
: order[order.orderableType]?.name;
|
|
46
|
+
|
|
39
47
|
return (
|
|
40
48
|
<div
|
|
41
49
|
className="event-info col-12 col-sm-6 col-md-6 col-lg-6 col-xl-6"
|
|
42
50
|
key={order.id}
|
|
43
51
|
>
|
|
44
52
|
<div className="info-wrapper">
|
|
45
|
-
<p className="label">{
|
|
53
|
+
<p className="label">{eventName}</p>
|
|
46
54
|
{order.createdAt && (
|
|
47
55
|
<p className="event-date">{formatDate(order.createdAt)}</p>
|
|
48
56
|
)}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
.customers-filter {
|
|
2
|
+
@include media-breakpoint-down(sm) {
|
|
3
|
+
label {
|
|
4
|
+
font-size: 0.8rem;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@include media-breakpoint-up(md) {
|
|
9
|
+
label {
|
|
10
|
+
font-size: 0.9rem;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@include media-breakpoint-up(lg) {
|
|
15
|
+
label {
|
|
16
|
+
font-size: 1rem;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@include media-breakpoint-down(lg) {
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.customers-filter-items {
|
|
25
|
+
width: 100%;
|
|
26
|
+
|
|
27
|
+
.customer-filter {
|
|
28
|
+
flex: 0 0 33.33%;
|
|
29
|
+
max-width: 33.33%;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@include media-breakpoint-down(xs) {
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
|
|
35
|
+
.customer-filter {
|
|
36
|
+
flex: 1;
|
|
37
|
+
max-width: 100%;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@include media-breakpoint-up(sm) {
|
|
42
|
+
.customer-filter {
|
|
43
|
+
&:first-child {
|
|
44
|
+
padding-left: 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&:last-child {
|
|
48
|
+
padding-right: 0;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "./Filter.scss";
|
package/src/styles/packages.scss
CHANGED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
useEffect,
|
|
3
|
+
useMemo,
|
|
4
|
+
forwardRef,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
Ref,
|
|
7
|
+
ReactElement,
|
|
8
|
+
} from "react";
|
|
9
|
+
import { Col, Row, Table } from "react-bootstrap";
|
|
10
|
+
import { useLocation } from "react-router-dom";
|
|
11
|
+
import { isEqual } from "lodash";
|
|
12
|
+
import clsx from "clsx";
|
|
13
|
+
import {
|
|
14
|
+
useReactTable,
|
|
15
|
+
ColumnDefResolved,
|
|
16
|
+
getCoreRowModel,
|
|
17
|
+
} from "@tanstack/react-table";
|
|
18
|
+
import RouteService from "@licklist/plugins/dist/services/Route/RouteService";
|
|
19
|
+
import TableService from "@licklist/plugins/dist/services/Table/TableService";
|
|
20
|
+
import { LoaderIndicator } from "../static/loader/LoaderIndicator";
|
|
21
|
+
import { FilterHelperComponent } from "./FilterHelperComponent";
|
|
22
|
+
import { PaginationHelperComponent } from "./PaginationHelperComponent";
|
|
23
|
+
import { PerPageHelperComponent } from "./PerPageHelperComponent";
|
|
24
|
+
import { flexRender } from "./utils";
|
|
25
|
+
import {
|
|
26
|
+
TableComponentProps,
|
|
27
|
+
TableComponentPropsWithOldTableData,
|
|
28
|
+
TableComponentPropsWithReactTableData,
|
|
29
|
+
TableColumnMeta,
|
|
30
|
+
ExtendedTableOptions,
|
|
31
|
+
} from "./types";
|
|
32
|
+
import { useTableQueryOptions } from "./hooks/useTableQueryOptions";
|
|
33
|
+
|
|
34
|
+
export type { ReactTableHelperRow } from "./types";
|
|
35
|
+
|
|
36
|
+
export type ReactTableHelperComponentProps<T extends object> =
|
|
37
|
+
TableComponentProps<T> &
|
|
38
|
+
(
|
|
39
|
+
| TableComponentPropsWithOldTableData<T>
|
|
40
|
+
| TableComponentPropsWithReactTableData<T>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export type ReactTableHelperComponentRef = {
|
|
44
|
+
options: ExtendedTableOptions | null;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* ReactTableHelperComponent
|
|
49
|
+
* simple table with our backend realization
|
|
50
|
+
* and pagination.
|
|
51
|
+
* @param props
|
|
52
|
+
* @constructor
|
|
53
|
+
*/
|
|
54
|
+
function WrappedReactTableHelperComponent<T extends object>(
|
|
55
|
+
props: ReactTableHelperComponentProps<T>,
|
|
56
|
+
ref: Ref<ReactTableHelperComponentRef>
|
|
57
|
+
) {
|
|
58
|
+
const {
|
|
59
|
+
paginator,
|
|
60
|
+
headers,
|
|
61
|
+
renderItemFn,
|
|
62
|
+
isLoading,
|
|
63
|
+
striped = true,
|
|
64
|
+
bordered = true,
|
|
65
|
+
displaySearchBar = true,
|
|
66
|
+
displayPerPageSelect = true,
|
|
67
|
+
displayShowingSection = true,
|
|
68
|
+
externalFilters = {},
|
|
69
|
+
initialOptions = {},
|
|
70
|
+
columns,
|
|
71
|
+
sortableColumns = [],
|
|
72
|
+
renderRow,
|
|
73
|
+
...tableProps
|
|
74
|
+
} = props;
|
|
75
|
+
|
|
76
|
+
const { pathname } = useLocation();
|
|
77
|
+
|
|
78
|
+
const {
|
|
79
|
+
sortKey,
|
|
80
|
+
sortDirection,
|
|
81
|
+
options,
|
|
82
|
+
setOptions,
|
|
83
|
+
optionsCache,
|
|
84
|
+
setOptionsCache,
|
|
85
|
+
cachedExternalFilters,
|
|
86
|
+
setCachedExternalFilters,
|
|
87
|
+
} = useTableQueryOptions({ initialOptions, externalFilters });
|
|
88
|
+
|
|
89
|
+
const tableColumns = useMemo(() => {
|
|
90
|
+
if (!columns && !headers) return [];
|
|
91
|
+
|
|
92
|
+
if (columns && !headers) {
|
|
93
|
+
return columns.map((column) => {
|
|
94
|
+
const { accessorKey } = column as ColumnDefResolved<T>;
|
|
95
|
+
const isSortable = sortableColumns.includes(accessorKey);
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
...column,
|
|
99
|
+
meta: {
|
|
100
|
+
className: TableService.getHeaderClasses(
|
|
101
|
+
{ isSortable, key: accessorKey, title: accessorKey },
|
|
102
|
+
sortKey,
|
|
103
|
+
sortDirection
|
|
104
|
+
),
|
|
105
|
+
onClick: isSortable ? () => onSort(accessorKey!) : undefined,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return headers.map((header) => {
|
|
112
|
+
if (typeof header === "string") {
|
|
113
|
+
return {
|
|
114
|
+
accessorKey: header.toLowerCase(),
|
|
115
|
+
header: () => header,
|
|
116
|
+
meta: {
|
|
117
|
+
className: TableService.getHeaderClasses(
|
|
118
|
+
header,
|
|
119
|
+
sortKey,
|
|
120
|
+
sortDirection
|
|
121
|
+
),
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
accessorKey: header?.key || header.title.toLowerCase(),
|
|
128
|
+
header: () => header.title,
|
|
129
|
+
meta: {
|
|
130
|
+
onClick: () => header.isSortable && onSort(header.key!),
|
|
131
|
+
className: TableService.getHeaderClasses(
|
|
132
|
+
header,
|
|
133
|
+
sortKey,
|
|
134
|
+
sortDirection
|
|
135
|
+
),
|
|
136
|
+
style: { width: header?.width || "auto" },
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
});
|
|
140
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
141
|
+
}, [headers, columns, sortKey, sortDirection, sortableColumns]);
|
|
142
|
+
|
|
143
|
+
const { getHeaderGroups, getRowModel } = useReactTable<T>({
|
|
144
|
+
data: paginator?.data || [],
|
|
145
|
+
columns: tableColumns,
|
|
146
|
+
getCoreRowModel: getCoreRowModel<T>(),
|
|
147
|
+
...tableProps,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
useImperativeHandle(ref, () => {
|
|
151
|
+
return { options };
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Redirect to the URL with a new parameters
|
|
155
|
+
// ONLY: if any option or external filters has changed
|
|
156
|
+
useEffect(
|
|
157
|
+
() => {
|
|
158
|
+
if (
|
|
159
|
+
isEqual(optionsCache, options) &&
|
|
160
|
+
isEqual(cachedExternalFilters, externalFilters)
|
|
161
|
+
)
|
|
162
|
+
return;
|
|
163
|
+
|
|
164
|
+
setOptionsCache(options);
|
|
165
|
+
setCachedExternalFilters(externalFilters);
|
|
166
|
+
|
|
167
|
+
const nextUrlSearchParams = new URLSearchParams({
|
|
168
|
+
...options,
|
|
169
|
+
...externalFilters,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
RouteService.redirectTo(
|
|
173
|
+
[pathname, nextUrlSearchParams.toString()].join("?")
|
|
174
|
+
);
|
|
175
|
+
},
|
|
176
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
177
|
+
[pathname, options, externalFilters]
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const onSort = (key: string) => {
|
|
181
|
+
let nextDirection = TableService.DEFAULT_SORT_DIRECTION;
|
|
182
|
+
|
|
183
|
+
if (sortKey === key) {
|
|
184
|
+
setOptions((prevOptions) => {
|
|
185
|
+
nextDirection = TableService.getSortDirection(
|
|
186
|
+
prevOptions.sortDirection,
|
|
187
|
+
nextDirection
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
...prevOptions,
|
|
192
|
+
sortKey: key,
|
|
193
|
+
sortDirection: nextDirection,
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
} else {
|
|
197
|
+
setOptions((prevOptions) => ({
|
|
198
|
+
...prevOptions,
|
|
199
|
+
sortKey: key,
|
|
200
|
+
sortDirection: nextDirection,
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const onPerPageChange = (nextPerPage: number) => {
|
|
206
|
+
setOptions((prevOptions) => ({
|
|
207
|
+
...prevOptions,
|
|
208
|
+
perPage: nextPerPage,
|
|
209
|
+
}));
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const onPageChange = (nextPage: number) => {
|
|
213
|
+
setOptions((prevOptions) => ({
|
|
214
|
+
...prevOptions,
|
|
215
|
+
page: nextPage,
|
|
216
|
+
}));
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const onFilterChange = (nextFilter: string) => {
|
|
220
|
+
setOptions(({ page: prevPage, ...prevOptions }) => {
|
|
221
|
+
let nextPage = prevPage;
|
|
222
|
+
|
|
223
|
+
if (
|
|
224
|
+
(!nextFilter && prevOptions.filter) ||
|
|
225
|
+
(nextFilter && !prevOptions.filter)
|
|
226
|
+
) {
|
|
227
|
+
nextPage = 1;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
...prevOptions,
|
|
232
|
+
page: nextPage,
|
|
233
|
+
filter: nextFilter,
|
|
234
|
+
};
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<div className={clsx("table-helper", isLoading ? "py-5" : "py-1")}>
|
|
240
|
+
<LoaderIndicator isLoaded={!isLoading}>
|
|
241
|
+
<Row>
|
|
242
|
+
<Col>
|
|
243
|
+
{displayPerPageSelect && (
|
|
244
|
+
<PerPageHelperComponent
|
|
245
|
+
onChangeFn={onPerPageChange}
|
|
246
|
+
defaultValue={
|
|
247
|
+
paginator?.per_page ?? TableService.DEFAULT_PER_PAGE
|
|
248
|
+
}
|
|
249
|
+
/>
|
|
250
|
+
)}
|
|
251
|
+
</Col>
|
|
252
|
+
<Col>
|
|
253
|
+
{displaySearchBar && (
|
|
254
|
+
<FilterHelperComponent
|
|
255
|
+
onClickFn={onFilterChange}
|
|
256
|
+
defaultValue={options.filter ?? ""}
|
|
257
|
+
/>
|
|
258
|
+
)}
|
|
259
|
+
</Col>
|
|
260
|
+
</Row>
|
|
261
|
+
<Row>
|
|
262
|
+
<Col>
|
|
263
|
+
<div className="table-responsive">
|
|
264
|
+
<Table striped={striped} bordered={bordered} hover>
|
|
265
|
+
<thead>
|
|
266
|
+
{getHeaderGroups().map((headerGroup) => (
|
|
267
|
+
<tr key={headerGroup.id}>
|
|
268
|
+
{headerGroup.headers.map((header) => {
|
|
269
|
+
const headerMeta = header.column.columnDef
|
|
270
|
+
.meta as TableColumnMeta;
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<th
|
|
274
|
+
key={header.id}
|
|
275
|
+
className={headerMeta?.className}
|
|
276
|
+
onClick={headerMeta?.onClick}
|
|
277
|
+
style={headerMeta?.style}
|
|
278
|
+
>
|
|
279
|
+
{flexRender(
|
|
280
|
+
header.column.columnDef.header,
|
|
281
|
+
header.getContext()
|
|
282
|
+
)}
|
|
283
|
+
</th>
|
|
284
|
+
);
|
|
285
|
+
})}
|
|
286
|
+
</tr>
|
|
287
|
+
))}
|
|
288
|
+
</thead>
|
|
289
|
+
<tbody>
|
|
290
|
+
{getRowModel().rows.map((row, index) => {
|
|
291
|
+
if (renderItemFn) {
|
|
292
|
+
return renderItemFn(row.original, index);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return renderRow(row);
|
|
296
|
+
})}
|
|
297
|
+
</tbody>
|
|
298
|
+
</Table>
|
|
299
|
+
</div>
|
|
300
|
+
</Col>
|
|
301
|
+
</Row>
|
|
302
|
+
|
|
303
|
+
<PaginationHelperComponent
|
|
304
|
+
displayShowingSection={displayShowingSection}
|
|
305
|
+
paginator={paginator}
|
|
306
|
+
onPageChangeFn={onPageChange}
|
|
307
|
+
/>
|
|
308
|
+
</LoaderIndicator>
|
|
309
|
+
</div>
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const ReactTableHelperComponent = forwardRef(
|
|
314
|
+
WrappedReactTableHelperComponent
|
|
315
|
+
) as <T extends object>(
|
|
316
|
+
props: ReactTableHelperComponentProps<T> & {
|
|
317
|
+
ref?: Ref<ReactTableHelperComponentRef>;
|
|
318
|
+
}
|
|
319
|
+
) => ReactElement;
|
|
320
|
+
|
|
321
|
+
export { ReactTableHelperComponent };
|