@m5kdev/web-ui 0.8.9 → 0.8.10
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/packages/backend/dist/src/modules/auth/auth.dto.d.mts +5 -5
- package/dist/packages/backend/dist/src/modules/auth/auth.dto.d.ts +5 -5
- package/dist/packages/backend/dist/src/types.d.mts +12 -12
- package/dist/packages/backend/dist/src/types.d.ts +12 -12
- package/dist/src/modules/auth/components/ForgotPasswordForm.js +1 -1
- package/dist/src/modules/auth/components/ForgotPasswordForm.mjs +1 -1
- package/dist/src/modules/auth/components/LoginForm.js +1 -1
- package/dist/src/modules/auth/components/LoginForm.mjs +1 -1
- package/dist/src/modules/auth/components/ProfileRoute.js +1 -1
- package/dist/src/modules/auth/components/ProfileRoute.mjs +1 -1
- package/dist/src/modules/auth/components/ResetPasswordForm.js +1 -1
- package/dist/src/modules/auth/components/ResetPasswordForm.mjs +1 -1
- package/dist/src/modules/auth/components/SignupFormRoute.js +1 -1
- package/dist/src/modules/auth/components/SignupFormRoute.mjs +1 -1
- package/dist/src/modules/table/components/NuqsTable.js +1 -1
- package/dist/src/modules/table/components/NuqsTable.mjs +1 -1
- package/dist/src/modules/table/components/TableFiltering.js +11 -1
- package/dist/src/modules/table/components/TableFiltering.js.map +1 -1
- package/dist/src/modules/table/components/TableFiltering.mjs +11 -1
- package/dist/src/modules/table/components/TableFiltering.mjs.map +1 -1
- package/dist/src/modules/table/filterTransformers.js +20 -1
- package/dist/src/modules/table/filterTransformers.js.map +1 -1
- package/dist/src/modules/table/filterTransformers.mjs +20 -1
- package/dist/src/modules/table/filterTransformers.mjs.map +1 -1
- package/package.json +5 -5
|
@@ -15,9 +15,9 @@ declare const waitlistSchema: z.ZodObject<{
|
|
|
15
15
|
declare const waitlistOutputSchema: z.ZodObject<{
|
|
16
16
|
id: z.ZodString;
|
|
17
17
|
name: z.ZodNullable<z.ZodString>;
|
|
18
|
-
email: z.ZodNullable<z.ZodString>;
|
|
19
18
|
createdAt: z.ZodDate;
|
|
20
19
|
updatedAt: z.ZodNullable<z.ZodDate>;
|
|
20
|
+
email: z.ZodNullable<z.ZodString>;
|
|
21
21
|
status: z.ZodString;
|
|
22
22
|
}, z.core.$strip>;
|
|
23
23
|
type WaitlistOutput = z.infer<typeof waitlistOutputSchema>;
|
|
@@ -35,9 +35,9 @@ declare const accountClaimSchema: z.ZodObject<{
|
|
|
35
35
|
}, z.core.$strip>;
|
|
36
36
|
declare const accountClaimOutputSchema: z.ZodObject<{
|
|
37
37
|
id: z.ZodString;
|
|
38
|
+
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
38
39
|
createdAt: z.ZodDate;
|
|
39
40
|
updatedAt: z.ZodNullable<z.ZodDate>;
|
|
40
|
-
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
41
41
|
status: z.ZodString;
|
|
42
42
|
claimUserId: z.ZodNullable<z.ZodString>;
|
|
43
43
|
claimedAt: z.ZodNullable<z.ZodDate>;
|
|
@@ -57,10 +57,10 @@ declare const accountClaimMagicLinkSchema: z.ZodObject<{
|
|
|
57
57
|
}, z.core.$strip>;
|
|
58
58
|
declare const accountClaimMagicLinkOutputSchema: z.ZodObject<{
|
|
59
59
|
id: z.ZodString;
|
|
60
|
-
email: z.ZodString;
|
|
61
|
-
createdAt: z.ZodDate;
|
|
62
|
-
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
63
60
|
userId: z.ZodString;
|
|
61
|
+
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
62
|
+
createdAt: z.ZodDate;
|
|
63
|
+
email: z.ZodString;
|
|
64
64
|
claimId: z.ZodString;
|
|
65
65
|
url: z.ZodString;
|
|
66
66
|
}, z.core.$strip>;
|
|
@@ -15,9 +15,9 @@ declare const waitlistSchema: z.ZodObject<{
|
|
|
15
15
|
declare const waitlistOutputSchema: z.ZodObject<{
|
|
16
16
|
id: z.ZodString;
|
|
17
17
|
name: z.ZodNullable<z.ZodString>;
|
|
18
|
-
email: z.ZodNullable<z.ZodString>;
|
|
19
18
|
createdAt: z.ZodDate;
|
|
20
19
|
updatedAt: z.ZodNullable<z.ZodDate>;
|
|
20
|
+
email: z.ZodNullable<z.ZodString>;
|
|
21
21
|
status: z.ZodString;
|
|
22
22
|
}, z.core.$strip>;
|
|
23
23
|
type WaitlistOutput = z.infer<typeof waitlistOutputSchema>;
|
|
@@ -35,9 +35,9 @@ declare const accountClaimSchema: z.ZodObject<{
|
|
|
35
35
|
}, z.core.$strip>;
|
|
36
36
|
declare const accountClaimOutputSchema: z.ZodObject<{
|
|
37
37
|
id: z.ZodString;
|
|
38
|
+
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
38
39
|
createdAt: z.ZodDate;
|
|
39
40
|
updatedAt: z.ZodNullable<z.ZodDate>;
|
|
40
|
-
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
41
41
|
status: z.ZodString;
|
|
42
42
|
claimUserId: z.ZodNullable<z.ZodString>;
|
|
43
43
|
claimedAt: z.ZodNullable<z.ZodDate>;
|
|
@@ -57,10 +57,10 @@ declare const accountClaimMagicLinkSchema: z.ZodObject<{
|
|
|
57
57
|
}, z.core.$strip>;
|
|
58
58
|
declare const accountClaimMagicLinkOutputSchema: z.ZodObject<{
|
|
59
59
|
id: z.ZodString;
|
|
60
|
-
email: z.ZodString;
|
|
61
|
-
createdAt: z.ZodDate;
|
|
62
|
-
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
63
60
|
userId: z.ZodString;
|
|
61
|
+
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
62
|
+
createdAt: z.ZodDate;
|
|
63
|
+
email: z.ZodString;
|
|
64
64
|
claimId: z.ZodString;
|
|
65
65
|
url: z.ZodString;
|
|
66
66
|
}, z.core.$strip>;
|
|
@@ -60,9 +60,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
60
60
|
input: void;
|
|
61
61
|
output: {
|
|
62
62
|
id: string;
|
|
63
|
+
expiresAt: Date | null;
|
|
63
64
|
createdAt: Date;
|
|
64
65
|
updatedAt: Date | null;
|
|
65
|
-
expiresAt: Date | null;
|
|
66
66
|
status: string;
|
|
67
67
|
claimUserId: string | null;
|
|
68
68
|
claimedAt: Date | null;
|
|
@@ -77,10 +77,10 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
77
77
|
};
|
|
78
78
|
output: {
|
|
79
79
|
id: string;
|
|
80
|
-
email: string;
|
|
81
|
-
createdAt: Date;
|
|
82
|
-
expiresAt: Date | null;
|
|
83
80
|
userId: string;
|
|
81
|
+
expiresAt: Date | null;
|
|
82
|
+
createdAt: Date;
|
|
83
|
+
email: string;
|
|
84
84
|
claimId: string;
|
|
85
85
|
url: string;
|
|
86
86
|
};
|
|
@@ -92,10 +92,10 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
92
92
|
};
|
|
93
93
|
output: {
|
|
94
94
|
id: string;
|
|
95
|
-
email: string;
|
|
96
|
-
createdAt: Date;
|
|
97
|
-
expiresAt: Date | null;
|
|
98
95
|
userId: string;
|
|
96
|
+
expiresAt: Date | null;
|
|
97
|
+
createdAt: Date;
|
|
98
|
+
email: string;
|
|
99
99
|
claimId: string;
|
|
100
100
|
url: string;
|
|
101
101
|
}[];
|
|
@@ -151,9 +151,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
151
151
|
output: {
|
|
152
152
|
id: string;
|
|
153
153
|
name: string | null;
|
|
154
|
-
email: string | null;
|
|
155
154
|
createdAt: Date;
|
|
156
155
|
updatedAt: Date | null;
|
|
156
|
+
email: string | null;
|
|
157
157
|
status: string;
|
|
158
158
|
}[];
|
|
159
159
|
meta: any;
|
|
@@ -165,9 +165,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
165
165
|
output: {
|
|
166
166
|
id: string;
|
|
167
167
|
name: string | null;
|
|
168
|
-
email: string | null;
|
|
169
168
|
createdAt: Date;
|
|
170
169
|
updatedAt: Date | null;
|
|
170
|
+
email: string | null;
|
|
171
171
|
status: string;
|
|
172
172
|
};
|
|
173
173
|
meta: any;
|
|
@@ -196,9 +196,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
196
196
|
output: {
|
|
197
197
|
id: string;
|
|
198
198
|
name: string | null;
|
|
199
|
-
email: string | null;
|
|
200
199
|
createdAt: Date;
|
|
201
200
|
updatedAt: Date | null;
|
|
201
|
+
email: string | null;
|
|
202
202
|
status: string;
|
|
203
203
|
};
|
|
204
204
|
meta: any;
|
|
@@ -210,9 +210,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
210
210
|
output: {
|
|
211
211
|
id: string;
|
|
212
212
|
name: string | null;
|
|
213
|
-
email: string | null;
|
|
214
213
|
createdAt: Date;
|
|
215
214
|
updatedAt: Date | null;
|
|
215
|
+
email: string | null;
|
|
216
216
|
status: string;
|
|
217
217
|
};
|
|
218
218
|
meta: any;
|
|
@@ -224,9 +224,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
224
224
|
output: {
|
|
225
225
|
id: string;
|
|
226
226
|
name: string | null;
|
|
227
|
-
email: string | null;
|
|
228
227
|
createdAt: Date;
|
|
229
228
|
updatedAt: Date | null;
|
|
229
|
+
email: string | null;
|
|
230
230
|
status: string;
|
|
231
231
|
};
|
|
232
232
|
meta: any;
|
|
@@ -60,9 +60,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
60
60
|
input: void;
|
|
61
61
|
output: {
|
|
62
62
|
id: string;
|
|
63
|
+
expiresAt: Date | null;
|
|
63
64
|
createdAt: Date;
|
|
64
65
|
updatedAt: Date | null;
|
|
65
|
-
expiresAt: Date | null;
|
|
66
66
|
status: string;
|
|
67
67
|
claimUserId: string | null;
|
|
68
68
|
claimedAt: Date | null;
|
|
@@ -77,10 +77,10 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
77
77
|
};
|
|
78
78
|
output: {
|
|
79
79
|
id: string;
|
|
80
|
-
email: string;
|
|
81
|
-
createdAt: Date;
|
|
82
|
-
expiresAt: Date | null;
|
|
83
80
|
userId: string;
|
|
81
|
+
expiresAt: Date | null;
|
|
82
|
+
createdAt: Date;
|
|
83
|
+
email: string;
|
|
84
84
|
claimId: string;
|
|
85
85
|
url: string;
|
|
86
86
|
};
|
|
@@ -92,10 +92,10 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
92
92
|
};
|
|
93
93
|
output: {
|
|
94
94
|
id: string;
|
|
95
|
-
email: string;
|
|
96
|
-
createdAt: Date;
|
|
97
|
-
expiresAt: Date | null;
|
|
98
95
|
userId: string;
|
|
96
|
+
expiresAt: Date | null;
|
|
97
|
+
createdAt: Date;
|
|
98
|
+
email: string;
|
|
99
99
|
claimId: string;
|
|
100
100
|
url: string;
|
|
101
101
|
}[];
|
|
@@ -151,9 +151,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
151
151
|
output: {
|
|
152
152
|
id: string;
|
|
153
153
|
name: string | null;
|
|
154
|
-
email: string | null;
|
|
155
154
|
createdAt: Date;
|
|
156
155
|
updatedAt: Date | null;
|
|
156
|
+
email: string | null;
|
|
157
157
|
status: string;
|
|
158
158
|
}[];
|
|
159
159
|
meta: any;
|
|
@@ -165,9 +165,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
165
165
|
output: {
|
|
166
166
|
id: string;
|
|
167
167
|
name: string | null;
|
|
168
|
-
email: string | null;
|
|
169
168
|
createdAt: Date;
|
|
170
169
|
updatedAt: Date | null;
|
|
170
|
+
email: string | null;
|
|
171
171
|
status: string;
|
|
172
172
|
};
|
|
173
173
|
meta: any;
|
|
@@ -196,9 +196,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
196
196
|
output: {
|
|
197
197
|
id: string;
|
|
198
198
|
name: string | null;
|
|
199
|
-
email: string | null;
|
|
200
199
|
createdAt: Date;
|
|
201
200
|
updatedAt: Date | null;
|
|
201
|
+
email: string | null;
|
|
202
202
|
status: string;
|
|
203
203
|
};
|
|
204
204
|
meta: any;
|
|
@@ -210,9 +210,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
210
210
|
output: {
|
|
211
211
|
id: string;
|
|
212
212
|
name: string | null;
|
|
213
|
-
email: string | null;
|
|
214
213
|
createdAt: Date;
|
|
215
214
|
updatedAt: Date | null;
|
|
215
|
+
email: string | null;
|
|
216
216
|
status: string;
|
|
217
217
|
};
|
|
218
218
|
meta: any;
|
|
@@ -224,9 +224,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
|
|
|
224
224
|
output: {
|
|
225
225
|
id: string;
|
|
226
226
|
name: string | null;
|
|
227
|
-
email: string | null;
|
|
228
227
|
createdAt: Date;
|
|
229
228
|
updatedAt: Date | null;
|
|
229
|
+
email: string | null;
|
|
230
230
|
status: string;
|
|
231
231
|
};
|
|
232
232
|
meta: any;
|
|
@@ -5,8 +5,8 @@ let _heroui_react = require("@heroui/react");
|
|
|
5
5
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
6
6
|
let react_i18next = require("react-i18next");
|
|
7
7
|
let sonner = require("sonner");
|
|
8
|
-
let _m5kdev_frontend_modules_auth_auth_lib = require("@m5kdev/frontend/modules/auth/auth.lib");
|
|
9
8
|
let react_hook_form = require("react-hook-form");
|
|
9
|
+
let _m5kdev_frontend_modules_auth_auth_lib = require("@m5kdev/frontend/modules/auth/auth.lib");
|
|
10
10
|
//#region src/modules/auth/components/ForgotPasswordForm.tsx
|
|
11
11
|
function ForgotPasswordForm() {
|
|
12
12
|
const { t } = (0, react_i18next.useTranslation)();
|
|
@@ -3,8 +3,8 @@ import { Button, Input } from "@heroui/react";
|
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
5
|
import { toast } from "sonner";
|
|
6
|
-
import { authClient } from "@m5kdev/frontend/modules/auth/auth.lib";
|
|
7
6
|
import { useForm } from "react-hook-form";
|
|
7
|
+
import { authClient } from "@m5kdev/frontend/modules/auth/auth.lib";
|
|
8
8
|
//#region src/modules/auth/components/ForgotPasswordForm.tsx
|
|
9
9
|
function ForgotPasswordForm() {
|
|
10
10
|
const { t } = useTranslation();
|
|
@@ -7,9 +7,9 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
7
7
|
let react_i18next = require("react-i18next");
|
|
8
8
|
let react_router = require("react-router");
|
|
9
9
|
let sonner = require("sonner");
|
|
10
|
+
let react_hook_form = require("react-hook-form");
|
|
10
11
|
let _m5kdev_frontend_modules_auth_auth_lib = require("@m5kdev/frontend/modules/auth/auth.lib");
|
|
11
12
|
let _m5kdev_frontend_modules_auth_hooks_useSession = require("@m5kdev/frontend/modules/auth/hooks/useSession");
|
|
12
|
-
let react_hook_form = require("react-hook-form");
|
|
13
13
|
//#region src/modules/auth/components/LoginForm.tsx
|
|
14
14
|
function LoginForm({ providers }) {
|
|
15
15
|
const lastMethod = _m5kdev_frontend_modules_auth_auth_lib.authClient.getLastUsedLoginMethod();
|
|
@@ -5,9 +5,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
import { Link as Link$1, useNavigate } from "react-router";
|
|
7
7
|
import { toast } from "sonner";
|
|
8
|
+
import { useForm } from "react-hook-form";
|
|
8
9
|
import { authClient } from "@m5kdev/frontend/modules/auth/auth.lib";
|
|
9
10
|
import { useSession } from "@m5kdev/frontend/modules/auth/hooks/useSession";
|
|
10
|
-
import { useForm } from "react-hook-form";
|
|
11
11
|
//#region src/modules/auth/components/LoginForm.tsx
|
|
12
12
|
function LoginForm({ providers }) {
|
|
13
13
|
const lastMethod = authClient.getLastUsedLoginMethod();
|
|
@@ -6,9 +6,9 @@ let _heroui_react = require("@heroui/react");
|
|
|
6
6
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
7
|
let react_i18next = require("react-i18next");
|
|
8
8
|
let sonner = require("sonner");
|
|
9
|
+
let react_hook_form = require("react-hook-form");
|
|
9
10
|
let _m5kdev_frontend_modules_auth_auth_lib = require("@m5kdev/frontend/modules/auth/auth.lib");
|
|
10
11
|
let _m5kdev_frontend_modules_auth_hooks_useSession = require("@m5kdev/frontend/modules/auth/hooks/useSession");
|
|
11
|
-
let react_hook_form = require("react-hook-form");
|
|
12
12
|
let zod = require("zod");
|
|
13
13
|
//#region src/modules/auth/components/ProfileRoute.tsx
|
|
14
14
|
zod.z.object({
|
|
@@ -4,9 +4,9 @@ import { Button, Card, CardBody, CardHeader, Input } from "@heroui/react";
|
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
import { toast } from "sonner";
|
|
7
|
+
import { useForm } from "react-hook-form";
|
|
7
8
|
import { authClient } from "@m5kdev/frontend/modules/auth/auth.lib";
|
|
8
9
|
import { useSession } from "@m5kdev/frontend/modules/auth/hooks/useSession";
|
|
9
|
-
import { useForm } from "react-hook-form";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
//#region src/modules/auth/components/ProfileRoute.tsx
|
|
12
12
|
z.object({
|
|
@@ -5,8 +5,8 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
5
5
|
let react_i18next = require("react-i18next");
|
|
6
6
|
let react_router = require("react-router");
|
|
7
7
|
let sonner = require("sonner");
|
|
8
|
-
let _m5kdev_frontend_modules_auth_auth_lib = require("@m5kdev/frontend/modules/auth/auth.lib");
|
|
9
8
|
let react_hook_form = require("react-hook-form");
|
|
9
|
+
let _m5kdev_frontend_modules_auth_auth_lib = require("@m5kdev/frontend/modules/auth/auth.lib");
|
|
10
10
|
//#region src/modules/auth/components/ResetPasswordForm.tsx
|
|
11
11
|
function ResetPasswordForm() {
|
|
12
12
|
const { t } = (0, react_i18next.useTranslation)();
|
|
@@ -3,8 +3,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
4
|
import { Link as Link$1, useSearchParams } from "react-router";
|
|
5
5
|
import { toast } from "sonner";
|
|
6
|
-
import { authClient } from "@m5kdev/frontend/modules/auth/auth.lib";
|
|
7
6
|
import { useForm } from "react-hook-form";
|
|
7
|
+
import { authClient } from "@m5kdev/frontend/modules/auth/auth.lib";
|
|
8
8
|
//#region src/modules/auth/components/ResetPasswordForm.tsx
|
|
9
9
|
function ResetPasswordForm() {
|
|
10
10
|
const { t } = useTranslation();
|
|
@@ -6,9 +6,9 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
6
6
|
let react_i18next = require("react-i18next");
|
|
7
7
|
let react_router = require("react-router");
|
|
8
8
|
let sonner = require("sonner");
|
|
9
|
+
let react_hook_form = require("react-hook-form");
|
|
9
10
|
let _m5kdev_frontend_modules_auth_auth_lib = require("@m5kdev/frontend/modules/auth/auth.lib");
|
|
10
11
|
let _m5kdev_frontend_modules_auth_hooks_useSession = require("@m5kdev/frontend/modules/auth/hooks/useSession");
|
|
11
|
-
let react_hook_form = require("react-hook-form");
|
|
12
12
|
//#region src/modules/auth/components/SignupFormRoute.tsx
|
|
13
13
|
function getEmailProviderUrl(email) {
|
|
14
14
|
const domain = email.split("@")[1]?.toLowerCase();
|
|
@@ -4,9 +4,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
5
|
import { useNavigate } from "react-router";
|
|
6
6
|
import { toast } from "sonner";
|
|
7
|
+
import { useForm } from "react-hook-form";
|
|
7
8
|
import { authClient } from "@m5kdev/frontend/modules/auth/auth.lib";
|
|
8
9
|
import { useSession } from "@m5kdev/frontend/modules/auth/hooks/useSession";
|
|
9
|
-
import { useForm } from "react-hook-form";
|
|
10
10
|
//#region src/modules/auth/components/SignupFormRoute.tsx
|
|
11
11
|
function getEmailProviderUrl(email) {
|
|
12
12
|
const domain = email.split("@")[1]?.toLowerCase();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../../../_virtual/_rolldown/runtime.js");
|
|
3
3
|
const require_src_components_ui_button = require("../../../components/ui/button.js");
|
|
4
|
-
const require_src_modules_table_components_ColumnOrderAndVisibility = require("./ColumnOrderAndVisibility.js");
|
|
5
4
|
const require_src_components_ui_table = require("../../../components/ui/table.js");
|
|
5
|
+
const require_src_modules_table_components_ColumnOrderAndVisibility = require("./ColumnOrderAndVisibility.js");
|
|
6
6
|
const require_src_modules_table_components_TableFiltering = require("./TableFiltering.js");
|
|
7
7
|
const require_src_modules_table_components_TableGroupBy = require("./TableGroupBy.js");
|
|
8
8
|
const require_src_modules_table_components_TablePagination = require("./TablePagination.js");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Button as Button$1 } from "../../../components/ui/button.mjs";
|
|
2
|
-
import { ColumnOrderAndVisibility } from "./ColumnOrderAndVisibility.mjs";
|
|
3
2
|
import { Table as Table$1, TableBody as TableBody$1, TableCell as TableCell$1, TableHead, TableHeader as TableHeader$1, TableRow as TableRow$1 } from "../../../components/ui/table.mjs";
|
|
3
|
+
import { ColumnOrderAndVisibility } from "./ColumnOrderAndVisibility.mjs";
|
|
4
4
|
import { TableFiltering } from "./TableFiltering.mjs";
|
|
5
5
|
import { TableGroupBy } from "./TableGroupBy.mjs";
|
|
6
6
|
import { TablePagination } from "./TablePagination.mjs";
|
|
@@ -158,6 +158,15 @@ const defaultFilterMethods = {
|
|
|
158
158
|
value: "equals",
|
|
159
159
|
label: "Equals",
|
|
160
160
|
component: "select"
|
|
161
|
+
}],
|
|
162
|
+
jsonArray: [{
|
|
163
|
+
value: "oneOf",
|
|
164
|
+
label: "One Of",
|
|
165
|
+
component: "multiSelect"
|
|
166
|
+
}, {
|
|
167
|
+
value: "equals",
|
|
168
|
+
label: "Equals",
|
|
169
|
+
component: "select"
|
|
161
170
|
}]
|
|
162
171
|
};
|
|
163
172
|
const SINGLE_FILTER_KEY = "single-filter";
|
|
@@ -166,7 +175,8 @@ const mergeFilterMethods = (overrides) => ({
|
|
|
166
175
|
number: overrides?.number && overrides.number.length > 0 ? overrides.number : defaultFilterMethods.number,
|
|
167
176
|
date: overrides?.date && overrides.date.length > 0 ? overrides.date : defaultFilterMethods.date,
|
|
168
177
|
boolean: overrides?.boolean && overrides.boolean.length > 0 ? overrides.boolean : defaultFilterMethods.boolean,
|
|
169
|
-
enum: overrides?.enum && overrides.enum.length > 0 ? overrides.enum : defaultFilterMethods.enum
|
|
178
|
+
enum: overrides?.enum && overrides.enum.length > 0 ? overrides.enum : defaultFilterMethods.enum,
|
|
179
|
+
jsonArray: overrides?.jsonArray && overrides.jsonArray.length > 0 ? overrides.jsonArray : defaultFilterMethods.jsonArray
|
|
170
180
|
});
|
|
171
181
|
const TableFiltering = ({ columns, onFiltersChange, filters: initialFilters = [], onClose, singleFilter = false, filterMethods }) => {
|
|
172
182
|
const [filters, setFilters] = (0, react.useState)({});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableFiltering.js","names":["Input","DatePicker","DateRangePicker","Select","SelectItem","transformFiltersToHeroUI","transformFiltersFromHeroUI","Button","PlusIcon","XIcon"],"sources":["../../../../../src/modules/table/components/TableFiltering.tsx"],"sourcesContent":["import {\r\n DatePicker,\r\n DateRangePicker,\r\n type DateValue,\r\n Input,\r\n Select,\r\n SelectItem,\r\n type SharedSelection,\r\n} from \"@heroui/react\";\r\nimport { getLocalTimeZone, today } from \"@internationalized/date\";\r\nimport type { QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport type {\r\n ColumnDataType,\r\n ComponentForFilterMethod,\r\n FilterMethod,\r\n FilterMethods,\r\n} from \"@m5kdev/commons/modules/table/filter.types\";\r\nimport { PlusIcon, XIcon } from \"lucide-react\";\r\nimport type { ReactNode } from \"react\";\r\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\r\nimport { Button } from \"../../../components/ui/button\";\r\nimport {\r\n type FilterValue,\r\n type HeroUIFilter,\r\n transformFiltersFromHeroUI,\r\n transformFiltersToHeroUI,\r\n} from \"../filterTransformers\";\r\n\r\ntype ComponentRenderer = (\r\n value: FilterValue,\r\n onChange: (value: FilterValue) => void,\r\n options?: { label: string; value: string }[]\r\n) => ReactNode;\r\n\r\nconst componentForFilterMethod: Record<ComponentForFilterMethod, ComponentRenderer> = {\r\n text: (value, onChange) => (\r\n <Input\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as string) ?? \"\"}\r\n onChange={(e) => onChange(e.target.value)}\r\n />\r\n ),\r\n number: (value, onChange) => (\r\n <Input\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n type=\"number\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as number | null)?.toString() ?? \"\"}\r\n onChange={(e) => onChange(Number.parseFloat(e.target.value) || 0)}\r\n />\r\n ),\r\n date: (value, onChange) => (\r\n <DatePicker\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as any) ?? undefined}\r\n onChange={(date) => date && onChange(date as FilterValue)}\r\n maxValue={today(getLocalTimeZone()) as unknown as DateValue}\r\n />\r\n ),\r\n range: (value, onChange) => (\r\n <DateRangePicker\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as any) ?? undefined}\r\n onChange={(range) => range && onChange(range as FilterValue)}\r\n maxValue={today(getLocalTimeZone()) as unknown as DateValue}\r\n />\r\n ),\r\n radio: (value, onChange) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={(value as boolean | null) ? [\"true\"] : [\"false\"]}\r\n onSelectionChange={(keys) => onChange(keys.currentKey === \"true\")}\r\n >\r\n <SelectItem key=\"true\" className=\"text-sm\">\r\n True\r\n </SelectItem>\r\n <SelectItem key=\"false\" className=\"text-sm\">\r\n False\r\n </SelectItem>\r\n </Select>\r\n ),\r\n select: (value, onChange, options = []) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={(value as SharedSelection) ?? new Set()}\r\n onSelectionChange={(keys) => keys && onChange(keys as FilterValue)}\r\n >\r\n {options.map((option) => (\r\n <SelectItem key={option.value} className=\"text-sm\">\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n ),\r\n multiSelect: (value, onChange, options = []) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n selectionMode=\"multiple\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={value ? new Set(value as SharedSelection) : new Set()}\r\n onSelectionChange={(keys) => onChange(keys as FilterValue)}\r\n >\r\n {options.map((option) => (\r\n <SelectItem key={option.value} className=\"text-sm\">\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n ),\r\n};\r\n\r\nconst defaultFilterMethods: FilterMethods = {\r\n string: [\r\n { value: \"contains\", label: \"Contains\", component: \"text\" },\r\n { value: \"equals\", label: \"Equals\", component: \"text\" },\r\n { value: \"starts_with\", label: \"Starts With\", component: \"text\" },\r\n { value: \"ends_with\", label: \"Ends With\", component: \"text\" },\r\n ],\r\n number: [\r\n { value: \"equals\", label: \"Equals\", component: \"number\" },\r\n { value: \"greater_than\", label: \"Greater Than\", component: \"number\" },\r\n { value: \"less_than\", label: \"Less Than\", component: \"number\" },\r\n ],\r\n date: [\r\n { value: \"on\", label: \"On\", component: \"date\" },\r\n { value: \"between\", label: \"Between\", component: \"range\" },\r\n { value: \"before\", label: \"Before\", component: \"date\" },\r\n { value: \"after\", label: \"After\", component: \"date\" },\r\n { value: \"intersect\", label: \"During\", component: \"range\" },\r\n ],\r\n boolean: [{ value: \"equals\", label: \"Equals\", component: \"radio\" }],\r\n enum: [\r\n { value: \"oneOf\", label: \"One Of\", component: \"multiSelect\" },\r\n { value: \"equals\", label: \"Equals\", component: \"select\" },\r\n ],\r\n};\r\n\r\nconst SINGLE_FILTER_KEY = \"single-filter\";\r\n\r\ntype TableFilteringProps = {\r\n columns: {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }[];\r\n onFiltersChange: (filters: QueryFilters) => void;\r\n filters: QueryFilters;\r\n onClose?: () => void;\r\n singleFilter?: boolean;\r\n filterMethods?: Partial<FilterMethods>;\r\n};\r\n\r\nconst mergeFilterMethods = (overrides?: Partial<FilterMethods>): FilterMethods => ({\r\n string:\r\n overrides?.string && overrides.string.length > 0\r\n ? overrides.string\r\n : defaultFilterMethods.string,\r\n number:\r\n overrides?.number && overrides.number.length > 0\r\n ? overrides.number\r\n : defaultFilterMethods.number,\r\n date: overrides?.date && overrides.date.length > 0 ? overrides.date : defaultFilterMethods.date,\r\n boolean:\r\n overrides?.boolean && overrides.boolean.length > 0\r\n ? overrides.boolean\r\n : defaultFilterMethods.boolean,\r\n enum: overrides?.enum && overrides.enum.length > 0 ? overrides.enum : defaultFilterMethods.enum,\r\n});\r\n\r\nexport const TableFiltering = ({\r\n columns,\r\n onFiltersChange,\r\n filters: initialFilters = [],\r\n onClose,\r\n singleFilter = false,\r\n filterMethods,\r\n}: TableFilteringProps) => {\r\n const [filters, setFilters] = useState<Record<string, HeroUIFilter>>({});\r\n const effectiveFilterMethods = useMemo(() => mergeFilterMethods(filterMethods), [filterMethods]);\r\n\r\n const createEmptyFilter = useCallback(\r\n (): HeroUIFilter => ({\r\n columnId: \"\",\r\n type: null,\r\n value: null,\r\n method: null,\r\n options: null,\r\n endColumnId: null,\r\n periodStartColumnId: null,\r\n periodEndColumnId: null,\r\n }),\r\n []\r\n );\r\n\r\n const addFilter = useCallback(() => {\r\n setFilters((prev) => {\r\n if (!singleFilter) {\r\n const filterId = crypto.randomUUID();\r\n return {\r\n ...prev,\r\n [filterId]: createEmptyFilter(),\r\n };\r\n }\r\n\r\n // single filter mode\r\n return Object.keys(prev).length > 0 ? prev : { [SINGLE_FILTER_KEY]: createEmptyFilter() };\r\n });\r\n }, [createEmptyFilter, singleFilter]);\r\n\r\n const removeFilter = useCallback(\r\n (filterId: string) => {\r\n setFilters((prev) => {\r\n if (!singleFilter) {\r\n const { [filterId]: _, ...rest } = prev;\r\n return rest;\r\n }\r\n\r\n // single filter mode resets the lone filter\r\n return { [SINGLE_FILTER_KEY]: createEmptyFilter() };\r\n });\r\n },\r\n [createEmptyFilter, singleFilter]\r\n );\r\n\r\n const columnsMap = useMemo(\r\n () => new Map(columns.map((column) => [column.id, column])),\r\n [columns]\r\n );\r\n\r\n useEffect(() => {\r\n // Transform initialFilters from FiltersToApply format to HeroUIFilter format\r\n const transformedFilters = transformFiltersToHeroUI(\r\n initialFilters,\r\n columnsMap,\r\n effectiveFilterMethods\r\n );\r\n\r\n if (!singleFilter) {\r\n setFilters(Object.fromEntries(transformedFilters.map((filter) => [filter.columnId, filter])));\r\n return;\r\n }\r\n\r\n const firstFilter = transformedFilters[0];\r\n setFilters({\r\n [SINGLE_FILTER_KEY]: firstFilter ?? createEmptyFilter(),\r\n });\r\n }, [createEmptyFilter, initialFilters, singleFilter, columnsMap, effectiveFilterMethods]);\r\n\r\n const selectColumn = useCallback(\r\n (filterId: string, columnId: string) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n const column = columnsMap.get(columnId);\r\n if (!column) return prev;\r\n\r\n // If Period column, auto-set intersect method\r\n const isPeriodColumn = columnId.endsWith(\"__period\");\r\n const intersectMethod = isPeriodColumn\r\n ? (effectiveFilterMethods.date.find((m) => m.value === \"intersect\") ?? null)\r\n : null;\r\n\r\n return {\r\n ...prev,\r\n [filterId]: {\r\n ...oldFilter,\r\n columnId,\r\n type: column.type ?? null,\r\n options: column.options ?? null,\r\n endColumnId: column.endColumnId ?? null,\r\n periodStartColumnId: column.periodStartColumnId ?? null,\r\n periodEndColumnId: column.periodEndColumnId ?? null,\r\n method: intersectMethod,\r\n value: null,\r\n },\r\n };\r\n });\r\n },\r\n [columnsMap, effectiveFilterMethods]\r\n );\r\n\r\n const selectMethod = useCallback((filterId: string, method: FilterMethod) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n return {\r\n ...prev,\r\n [filterId]: { ...oldFilter, method, value: null },\r\n };\r\n });\r\n }, []);\r\n\r\n const selectValue = useCallback((filterId: string, value: FilterValue) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n return {\r\n ...prev,\r\n [filterId]: { ...oldFilter, value },\r\n };\r\n });\r\n }, []);\r\n\r\n const filterEntries = useMemo(() => Object.entries(filters), [filters]);\r\n\r\n const availableColumnsMap = useMemo(() => {\r\n const map = new Map<string, typeof columns>();\r\n filterEntries.forEach(([filterId]) => {\r\n const columnsUsedByOtherFilters = new Set(\r\n filterEntries\r\n .filter(([id]) => id !== filterId)\r\n .map(([_, f]) => f.columnId)\r\n .filter((id) => id !== \"\")\r\n );\r\n map.set(\r\n filterId,\r\n columns.filter((column) => !columnsUsedByOtherFilters.has(column.id))\r\n );\r\n });\r\n return map;\r\n }, [filterEntries, columns]);\r\n\r\n const applyFilters = useCallback(() => {\r\n const heroUIFilters = Object.values(filters);\r\n const filtersToApply = transformFiltersFromHeroUI(heroUIFilters);\r\n onFiltersChange(filtersToApply);\r\n onClose?.();\r\n }, [filters, onFiltersChange, onClose]);\r\n\r\n return (\r\n <div className=\"flex flex-col gap-2 p-1 min-w-[600px]\">\r\n {filterEntries.map(([filterId, filter]) => {\r\n const availableColumns = availableColumnsMap.get(filterId) ?? columns;\r\n return (\r\n <TableFilteringItem\r\n key={filterId}\r\n id={filterId}\r\n filter={filter}\r\n columns={availableColumns}\r\n selectColumn={selectColumn}\r\n selectMethod={selectMethod}\r\n removeFilter={removeFilter}\r\n selectValue={selectValue}\r\n filterMethods={effectiveFilterMethods}\r\n />\r\n );\r\n })}\r\n {!singleFilter && (\r\n <Button variant=\"outline\" size=\"sm\" onClick={addFilter}>\r\n <PlusIcon className=\"h-4 w-4\" />\r\n Add Filter\r\n </Button>\r\n )}\r\n <Button onClick={applyFilters}>{singleFilter ? \"Apply Filter\" : \"Apply Filters\"}</Button>\r\n </div>\r\n );\r\n};\r\n\r\nconst TableFilteringItem = ({\r\n id,\r\n filter,\r\n columns,\r\n selectColumn,\r\n selectMethod,\r\n selectValue,\r\n removeFilter,\r\n filterMethods,\r\n}: {\r\n id: string;\r\n filter: HeroUIFilter;\r\n columns: {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }[];\r\n selectColumn: (filterId: string, columnId: string) => void;\r\n selectMethod: (filterId: string, method: FilterMethod) => void;\r\n selectValue: (filterId: string, value: FilterValue) => void;\r\n removeFilter: (filterId: string) => void;\r\n filterMethods: FilterMethods;\r\n}) => {\r\n const handleColumnChange = useCallback(\r\n (keys: any) => {\r\n const columnId = String(keys.currentKey);\r\n selectColumn(id, columnId);\r\n },\r\n [id, selectColumn]\r\n );\r\n\r\n const methodsForType = useMemo(() => {\r\n if (!filter.type) return [];\r\n\r\n // Period columns only support intersect method\r\n const isPeriodColumn = filter.columnId.endsWith(\"__period\");\r\n if (isPeriodColumn) {\r\n const intersectMethod = filterMethods.date.find((m) => m.value === \"intersect\");\r\n return intersectMethod ? [intersectMethod] : [];\r\n }\r\n\r\n const baseMethods = filterMethods[filter.type as ColumnDataType] ?? [];\r\n const emptyMethods: FilterMethod[] = [\r\n { value: \"isEmpty\", label: \"Is Empty\", component: null },\r\n { value: \"isNotEmpty\", label: \"Is Not Empty\", component: null },\r\n ];\r\n\r\n if (filter.type !== \"boolean\" && filter.type !== \"date\") {\r\n return [...baseMethods, ...emptyMethods];\r\n }\r\n\r\n return baseMethods;\r\n }, [filter.type, filter.columnId, filter.method?.value, filterMethods]);\r\n\r\n const handleMethodChange = useCallback(\r\n (keys: any) => {\r\n if (!filter.type) return;\r\n // Use methodsForType instead of filterMethods to include dynamically added methods\r\n const method = methodsForType.find(\r\n (currentMethod: FilterMethod) => currentMethod.value === String(keys.currentKey)\r\n );\r\n if (method) {\r\n selectMethod(id, method);\r\n }\r\n },\r\n [id, filter.type, selectMethod, methodsForType]\r\n );\r\n\r\n const handleValueChange = useCallback(\r\n (value: FilterValue) => {\r\n selectValue(id, value);\r\n },\r\n [id, selectValue]\r\n );\r\n\r\n const methodSelect = useMemo(() => {\r\n if (!filter.type) return null;\r\n return (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Method\"\r\n className=\"w-40 flex-shrink-0 text-sm\"\r\n selectedKeys={filter.method?.value ? [filter.method.value] : []}\r\n onSelectionChange={handleMethodChange}\r\n popoverProps={{\r\n className: \"w-auto min-w-max\",\r\n }}\r\n >\r\n {methodsForType.map((method: FilterMethod) => (\r\n <SelectItem key={method.value} className=\"text-sm\">\r\n {method.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n );\r\n }, [filter.type, filter.method?.value, methodsForType, handleMethodChange]);\r\n\r\n const filterValueComponent = useMemo(() => {\r\n if (!filter.method?.component) {\r\n return <div className=\"flex-1 min-w-0\" />;\r\n }\r\n const component = filter.method.component as ComponentForFilterMethod;\r\n const ComponentFn =\r\n componentForFilterMethod[component as keyof typeof componentForFilterMethod];\r\n if (!ComponentFn) return <div className=\"flex-1 min-w-0\" />;\r\n return ComponentFn(filter.value as any, handleValueChange, filter.options ?? []);\r\n }, [filter.method?.component, filter.value, filter.options, handleValueChange]);\r\n\r\n const columnSelectItems = useMemo(\r\n () =>\r\n columns.map((column) => (\r\n <SelectItem key={column.id} className=\"text-sm\">\r\n {String(column.label)}\r\n </SelectItem>\r\n )),\r\n [columns]\r\n );\r\n\r\n return (\r\n <div className=\"flex items-center gap-2 w-full\">\r\n <div className=\"flex flex-1 items-center gap-2 min-w-0\">\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Column\"\r\n className=\"w-40 flex-shrink-0 text-sm\"\r\n selectedKeys={filter.columnId ? [filter.columnId] : []}\r\n onSelectionChange={handleColumnChange}\r\n popoverProps={{\r\n className: \"w-auto min-w-max\",\r\n }}\r\n >\r\n {columnSelectItems}\r\n </Select>\r\n {methodSelect}\r\n {filterValueComponent}\r\n </div>\r\n <Button variant=\"outline\" size=\"sm\" onClick={() => removeFilter(id)}>\r\n <XIcon className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n );\r\n};\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TableFiltering.js","names":["Input","DatePicker","DateRangePicker","Select","SelectItem","transformFiltersToHeroUI","transformFiltersFromHeroUI","Button","PlusIcon","XIcon"],"sources":["../../../../../src/modules/table/components/TableFiltering.tsx"],"sourcesContent":["import {\r\n DatePicker,\r\n DateRangePicker,\r\n type DateValue,\r\n Input,\r\n Select,\r\n SelectItem,\r\n type SharedSelection,\r\n} from \"@heroui/react\";\r\nimport { getLocalTimeZone, today } from \"@internationalized/date\";\r\nimport type { QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport type {\r\n ColumnDataType,\r\n ComponentForFilterMethod,\r\n FilterMethod,\r\n FilterMethods,\r\n} from \"@m5kdev/commons/modules/table/filter.types\";\r\nimport { PlusIcon, XIcon } from \"lucide-react\";\r\nimport type { ReactNode } from \"react\";\r\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\r\nimport { Button } from \"../../../components/ui/button\";\r\nimport {\r\n type FilterValue,\r\n type HeroUIFilter,\r\n transformFiltersFromHeroUI,\r\n transformFiltersToHeroUI,\r\n} from \"../filterTransformers\";\r\n\r\ntype ComponentRenderer = (\r\n value: FilterValue,\r\n onChange: (value: FilterValue) => void,\r\n options?: { label: string; value: string }[]\r\n) => ReactNode;\r\n\r\nconst componentForFilterMethod: Record<ComponentForFilterMethod, ComponentRenderer> = {\r\n text: (value, onChange) => (\r\n <Input\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as string) ?? \"\"}\r\n onChange={(e) => onChange(e.target.value)}\r\n />\r\n ),\r\n number: (value, onChange) => (\r\n <Input\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n type=\"number\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as number | null)?.toString() ?? \"\"}\r\n onChange={(e) => onChange(Number.parseFloat(e.target.value) || 0)}\r\n />\r\n ),\r\n date: (value, onChange) => (\r\n <DatePicker\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as any) ?? undefined}\r\n onChange={(date) => date && onChange(date as FilterValue)}\r\n maxValue={today(getLocalTimeZone()) as unknown as DateValue}\r\n />\r\n ),\r\n range: (value, onChange) => (\r\n <DateRangePicker\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as any) ?? undefined}\r\n onChange={(range) => range && onChange(range as FilterValue)}\r\n maxValue={today(getLocalTimeZone()) as unknown as DateValue}\r\n />\r\n ),\r\n radio: (value, onChange) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={(value as boolean | null) ? [\"true\"] : [\"false\"]}\r\n onSelectionChange={(keys) => onChange(keys.currentKey === \"true\")}\r\n >\r\n <SelectItem key=\"true\" className=\"text-sm\">\r\n True\r\n </SelectItem>\r\n <SelectItem key=\"false\" className=\"text-sm\">\r\n False\r\n </SelectItem>\r\n </Select>\r\n ),\r\n select: (value, onChange, options = []) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={(value as SharedSelection) ?? new Set()}\r\n onSelectionChange={(keys) => keys && onChange(keys as FilterValue)}\r\n >\r\n {options.map((option) => (\r\n <SelectItem key={option.value} className=\"text-sm\">\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n ),\r\n multiSelect: (value, onChange, options = []) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n selectionMode=\"multiple\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={value ? new Set(value as SharedSelection) : new Set()}\r\n onSelectionChange={(keys) => onChange(keys as FilterValue)}\r\n >\r\n {options.map((option) => (\r\n <SelectItem key={option.value} className=\"text-sm\">\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n ),\r\n};\r\n\r\nconst defaultFilterMethods: FilterMethods = {\r\n string: [\r\n { value: \"contains\", label: \"Contains\", component: \"text\" },\r\n { value: \"equals\", label: \"Equals\", component: \"text\" },\r\n { value: \"starts_with\", label: \"Starts With\", component: \"text\" },\r\n { value: \"ends_with\", label: \"Ends With\", component: \"text\" },\r\n ],\r\n number: [\r\n { value: \"equals\", label: \"Equals\", component: \"number\" },\r\n { value: \"greater_than\", label: \"Greater Than\", component: \"number\" },\r\n { value: \"less_than\", label: \"Less Than\", component: \"number\" },\r\n ],\r\n date: [\r\n { value: \"on\", label: \"On\", component: \"date\" },\r\n { value: \"between\", label: \"Between\", component: \"range\" },\r\n { value: \"before\", label: \"Before\", component: \"date\" },\r\n { value: \"after\", label: \"After\", component: \"date\" },\r\n { value: \"intersect\", label: \"During\", component: \"range\" },\r\n ],\r\n boolean: [{ value: \"equals\", label: \"Equals\", component: \"radio\" }],\r\n enum: [\r\n { value: \"oneOf\", label: \"One Of\", component: \"multiSelect\" },\r\n { value: \"equals\", label: \"Equals\", component: \"select\" },\r\n ],\r\n jsonArray: [\r\n { value: \"oneOf\", label: \"One Of\", component: \"multiSelect\" },\r\n { value: \"equals\", label: \"Equals\", component: \"select\" },\r\n ],\r\n};\r\n\r\nconst SINGLE_FILTER_KEY = \"single-filter\";\r\n\r\ntype TableFilteringProps = {\r\n columns: {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }[];\r\n onFiltersChange: (filters: QueryFilters) => void;\r\n filters: QueryFilters;\r\n onClose?: () => void;\r\n singleFilter?: boolean;\r\n filterMethods?: Partial<FilterMethods>;\r\n};\r\n\r\nconst mergeFilterMethods = (overrides?: Partial<FilterMethods>): FilterMethods => ({\r\n string:\r\n overrides?.string && overrides.string.length > 0\r\n ? overrides.string\r\n : defaultFilterMethods.string,\r\n number:\r\n overrides?.number && overrides.number.length > 0\r\n ? overrides.number\r\n : defaultFilterMethods.number,\r\n date: overrides?.date && overrides.date.length > 0 ? overrides.date : defaultFilterMethods.date,\r\n boolean:\r\n overrides?.boolean && overrides.boolean.length > 0\r\n ? overrides.boolean\r\n : defaultFilterMethods.boolean,\r\n enum: overrides?.enum && overrides.enum.length > 0 ? overrides.enum : defaultFilterMethods.enum,\r\n jsonArray:\r\n overrides?.jsonArray && overrides.jsonArray.length > 0\r\n ? overrides.jsonArray\r\n : defaultFilterMethods.jsonArray,\r\n});\r\n\r\nexport const TableFiltering = ({\r\n columns,\r\n onFiltersChange,\r\n filters: initialFilters = [],\r\n onClose,\r\n singleFilter = false,\r\n filterMethods,\r\n}: TableFilteringProps) => {\r\n const [filters, setFilters] = useState<Record<string, HeroUIFilter>>({});\r\n const effectiveFilterMethods = useMemo(() => mergeFilterMethods(filterMethods), [filterMethods]);\r\n\r\n const createEmptyFilter = useCallback(\r\n (): HeroUIFilter => ({\r\n columnId: \"\",\r\n type: null,\r\n value: null,\r\n method: null,\r\n options: null,\r\n endColumnId: null,\r\n periodStartColumnId: null,\r\n periodEndColumnId: null,\r\n }),\r\n []\r\n );\r\n\r\n const addFilter = useCallback(() => {\r\n setFilters((prev) => {\r\n if (!singleFilter) {\r\n const filterId = crypto.randomUUID();\r\n return {\r\n ...prev,\r\n [filterId]: createEmptyFilter(),\r\n };\r\n }\r\n\r\n // single filter mode\r\n return Object.keys(prev).length > 0 ? prev : { [SINGLE_FILTER_KEY]: createEmptyFilter() };\r\n });\r\n }, [createEmptyFilter, singleFilter]);\r\n\r\n const removeFilter = useCallback(\r\n (filterId: string) => {\r\n setFilters((prev) => {\r\n if (!singleFilter) {\r\n const { [filterId]: _, ...rest } = prev;\r\n return rest;\r\n }\r\n\r\n // single filter mode resets the lone filter\r\n return { [SINGLE_FILTER_KEY]: createEmptyFilter() };\r\n });\r\n },\r\n [createEmptyFilter, singleFilter]\r\n );\r\n\r\n const columnsMap = useMemo(\r\n () => new Map(columns.map((column) => [column.id, column])),\r\n [columns]\r\n );\r\n\r\n useEffect(() => {\r\n // Transform initialFilters from FiltersToApply format to HeroUIFilter format\r\n const transformedFilters = transformFiltersToHeroUI(\r\n initialFilters,\r\n columnsMap,\r\n effectiveFilterMethods\r\n );\r\n\r\n if (!singleFilter) {\r\n setFilters(Object.fromEntries(transformedFilters.map((filter) => [filter.columnId, filter])));\r\n return;\r\n }\r\n\r\n const firstFilter = transformedFilters[0];\r\n setFilters({\r\n [SINGLE_FILTER_KEY]: firstFilter ?? createEmptyFilter(),\r\n });\r\n }, [createEmptyFilter, initialFilters, singleFilter, columnsMap, effectiveFilterMethods]);\r\n\r\n const selectColumn = useCallback(\r\n (filterId: string, columnId: string) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n const column = columnsMap.get(columnId);\r\n if (!column) return prev;\r\n\r\n // If Period column, auto-set intersect method\r\n const isPeriodColumn = columnId.endsWith(\"__period\");\r\n const intersectMethod = isPeriodColumn\r\n ? (effectiveFilterMethods.date.find((m) => m.value === \"intersect\") ?? null)\r\n : null;\r\n\r\n return {\r\n ...prev,\r\n [filterId]: {\r\n ...oldFilter,\r\n columnId,\r\n type: column.type ?? null,\r\n options: column.options ?? null,\r\n endColumnId: column.endColumnId ?? null,\r\n periodStartColumnId: column.periodStartColumnId ?? null,\r\n periodEndColumnId: column.periodEndColumnId ?? null,\r\n method: intersectMethod,\r\n value: null,\r\n },\r\n };\r\n });\r\n },\r\n [columnsMap, effectiveFilterMethods]\r\n );\r\n\r\n const selectMethod = useCallback((filterId: string, method: FilterMethod) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n return {\r\n ...prev,\r\n [filterId]: { ...oldFilter, method, value: null },\r\n };\r\n });\r\n }, []);\r\n\r\n const selectValue = useCallback((filterId: string, value: FilterValue) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n return {\r\n ...prev,\r\n [filterId]: { ...oldFilter, value },\r\n };\r\n });\r\n }, []);\r\n\r\n const filterEntries = useMemo(() => Object.entries(filters), [filters]);\r\n\r\n const availableColumnsMap = useMemo(() => {\r\n const map = new Map<string, typeof columns>();\r\n filterEntries.forEach(([filterId]) => {\r\n const columnsUsedByOtherFilters = new Set(\r\n filterEntries\r\n .filter(([id]) => id !== filterId)\r\n .map(([_, f]) => f.columnId)\r\n .filter((id) => id !== \"\")\r\n );\r\n map.set(\r\n filterId,\r\n columns.filter((column) => !columnsUsedByOtherFilters.has(column.id))\r\n );\r\n });\r\n return map;\r\n }, [filterEntries, columns]);\r\n\r\n const applyFilters = useCallback(() => {\r\n const heroUIFilters = Object.values(filters);\r\n const filtersToApply = transformFiltersFromHeroUI(heroUIFilters);\r\n onFiltersChange(filtersToApply);\r\n onClose?.();\r\n }, [filters, onFiltersChange, onClose]);\r\n\r\n return (\r\n <div className=\"flex flex-col gap-2 p-1 min-w-[600px]\">\r\n {filterEntries.map(([filterId, filter]) => {\r\n const availableColumns = availableColumnsMap.get(filterId) ?? columns;\r\n return (\r\n <TableFilteringItem\r\n key={filterId}\r\n id={filterId}\r\n filter={filter}\r\n columns={availableColumns}\r\n selectColumn={selectColumn}\r\n selectMethod={selectMethod}\r\n removeFilter={removeFilter}\r\n selectValue={selectValue}\r\n filterMethods={effectiveFilterMethods}\r\n />\r\n );\r\n })}\r\n {!singleFilter && (\r\n <Button variant=\"outline\" size=\"sm\" onClick={addFilter}>\r\n <PlusIcon className=\"h-4 w-4\" />\r\n Add Filter\r\n </Button>\r\n )}\r\n <Button onClick={applyFilters}>{singleFilter ? \"Apply Filter\" : \"Apply Filters\"}</Button>\r\n </div>\r\n );\r\n};\r\n\r\nconst TableFilteringItem = ({\r\n id,\r\n filter,\r\n columns,\r\n selectColumn,\r\n selectMethod,\r\n selectValue,\r\n removeFilter,\r\n filterMethods,\r\n}: {\r\n id: string;\r\n filter: HeroUIFilter;\r\n columns: {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }[];\r\n selectColumn: (filterId: string, columnId: string) => void;\r\n selectMethod: (filterId: string, method: FilterMethod) => void;\r\n selectValue: (filterId: string, value: FilterValue) => void;\r\n removeFilter: (filterId: string) => void;\r\n filterMethods: FilterMethods;\r\n}) => {\r\n const handleColumnChange = useCallback(\r\n (keys: any) => {\r\n const columnId = String(keys.currentKey);\r\n selectColumn(id, columnId);\r\n },\r\n [id, selectColumn]\r\n );\r\n\r\n const methodsForType = useMemo(() => {\r\n if (!filter.type) return [];\r\n\r\n // Period columns only support intersect method\r\n const isPeriodColumn = filter.columnId.endsWith(\"__period\");\r\n if (isPeriodColumn) {\r\n const intersectMethod = filterMethods.date.find((m) => m.value === \"intersect\");\r\n return intersectMethod ? [intersectMethod] : [];\r\n }\r\n\r\n const baseMethods = filterMethods[filter.type as ColumnDataType] ?? [];\r\n const emptyMethods: FilterMethod[] = [\r\n { value: \"isEmpty\", label: \"Is Empty\", component: null },\r\n { value: \"isNotEmpty\", label: \"Is Not Empty\", component: null },\r\n ];\r\n\r\n if (filter.type !== \"boolean\" && filter.type !== \"date\") {\r\n return [...baseMethods, ...emptyMethods];\r\n }\r\n\r\n return baseMethods;\r\n }, [filter.type, filter.columnId, filter.method?.value, filterMethods]);\r\n\r\n const handleMethodChange = useCallback(\r\n (keys: any) => {\r\n if (!filter.type) return;\r\n // Use methodsForType instead of filterMethods to include dynamically added methods\r\n const method = methodsForType.find(\r\n (currentMethod: FilterMethod) => currentMethod.value === String(keys.currentKey)\r\n );\r\n if (method) {\r\n selectMethod(id, method);\r\n }\r\n },\r\n [id, filter.type, selectMethod, methodsForType]\r\n );\r\n\r\n const handleValueChange = useCallback(\r\n (value: FilterValue) => {\r\n selectValue(id, value);\r\n },\r\n [id, selectValue]\r\n );\r\n\r\n const methodSelect = useMemo(() => {\r\n if (!filter.type) return null;\r\n return (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Method\"\r\n className=\"w-40 flex-shrink-0 text-sm\"\r\n selectedKeys={filter.method?.value ? [filter.method.value] : []}\r\n onSelectionChange={handleMethodChange}\r\n popoverProps={{\r\n className: \"w-auto min-w-max\",\r\n }}\r\n >\r\n {methodsForType.map((method: FilterMethod) => (\r\n <SelectItem key={method.value} className=\"text-sm\">\r\n {method.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n );\r\n }, [filter.type, filter.method?.value, methodsForType, handleMethodChange]);\r\n\r\n const filterValueComponent = useMemo(() => {\r\n if (!filter.method?.component) {\r\n return <div className=\"flex-1 min-w-0\" />;\r\n }\r\n const component = filter.method.component as ComponentForFilterMethod;\r\n const ComponentFn =\r\n componentForFilterMethod[component as keyof typeof componentForFilterMethod];\r\n if (!ComponentFn) return <div className=\"flex-1 min-w-0\" />;\r\n return ComponentFn(filter.value as any, handleValueChange, filter.options ?? []);\r\n }, [filter.method?.component, filter.value, filter.options, handleValueChange]);\r\n\r\n const columnSelectItems = useMemo(\r\n () =>\r\n columns.map((column) => (\r\n <SelectItem key={column.id} className=\"text-sm\">\r\n {String(column.label)}\r\n </SelectItem>\r\n )),\r\n [columns]\r\n );\r\n\r\n return (\r\n <div className=\"flex items-center gap-2 w-full\">\r\n <div className=\"flex flex-1 items-center gap-2 min-w-0\">\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Column\"\r\n className=\"w-40 flex-shrink-0 text-sm\"\r\n selectedKeys={filter.columnId ? [filter.columnId] : []}\r\n onSelectionChange={handleColumnChange}\r\n popoverProps={{\r\n className: \"w-auto min-w-max\",\r\n }}\r\n >\r\n {columnSelectItems}\r\n </Select>\r\n {methodSelect}\r\n {filterValueComponent}\r\n </div>\r\n <Button variant=\"outline\" size=\"sm\" onClick={() => removeFilter(id)}>\r\n <XIcon className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n );\r\n};\r\n"],"mappings":"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"}
|
|
@@ -156,6 +156,15 @@ const defaultFilterMethods = {
|
|
|
156
156
|
value: "equals",
|
|
157
157
|
label: "Equals",
|
|
158
158
|
component: "select"
|
|
159
|
+
}],
|
|
160
|
+
jsonArray: [{
|
|
161
|
+
value: "oneOf",
|
|
162
|
+
label: "One Of",
|
|
163
|
+
component: "multiSelect"
|
|
164
|
+
}, {
|
|
165
|
+
value: "equals",
|
|
166
|
+
label: "Equals",
|
|
167
|
+
component: "select"
|
|
159
168
|
}]
|
|
160
169
|
};
|
|
161
170
|
const SINGLE_FILTER_KEY = "single-filter";
|
|
@@ -164,7 +173,8 @@ const mergeFilterMethods = (overrides) => ({
|
|
|
164
173
|
number: overrides?.number && overrides.number.length > 0 ? overrides.number : defaultFilterMethods.number,
|
|
165
174
|
date: overrides?.date && overrides.date.length > 0 ? overrides.date : defaultFilterMethods.date,
|
|
166
175
|
boolean: overrides?.boolean && overrides.boolean.length > 0 ? overrides.boolean : defaultFilterMethods.boolean,
|
|
167
|
-
enum: overrides?.enum && overrides.enum.length > 0 ? overrides.enum : defaultFilterMethods.enum
|
|
176
|
+
enum: overrides?.enum && overrides.enum.length > 0 ? overrides.enum : defaultFilterMethods.enum,
|
|
177
|
+
jsonArray: overrides?.jsonArray && overrides.jsonArray.length > 0 ? overrides.jsonArray : defaultFilterMethods.jsonArray
|
|
168
178
|
});
|
|
169
179
|
const TableFiltering = ({ columns, onFiltersChange, filters: initialFilters = [], onClose, singleFilter = false, filterMethods }) => {
|
|
170
180
|
const [filters, setFilters] = useState({});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableFiltering.mjs","names":["Button"],"sources":["../../../../../src/modules/table/components/TableFiltering.tsx"],"sourcesContent":["import {\r\n DatePicker,\r\n DateRangePicker,\r\n type DateValue,\r\n Input,\r\n Select,\r\n SelectItem,\r\n type SharedSelection,\r\n} from \"@heroui/react\";\r\nimport { getLocalTimeZone, today } from \"@internationalized/date\";\r\nimport type { QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport type {\r\n ColumnDataType,\r\n ComponentForFilterMethod,\r\n FilterMethod,\r\n FilterMethods,\r\n} from \"@m5kdev/commons/modules/table/filter.types\";\r\nimport { PlusIcon, XIcon } from \"lucide-react\";\r\nimport type { ReactNode } from \"react\";\r\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\r\nimport { Button } from \"../../../components/ui/button\";\r\nimport {\r\n type FilterValue,\r\n type HeroUIFilter,\r\n transformFiltersFromHeroUI,\r\n transformFiltersToHeroUI,\r\n} from \"../filterTransformers\";\r\n\r\ntype ComponentRenderer = (\r\n value: FilterValue,\r\n onChange: (value: FilterValue) => void,\r\n options?: { label: string; value: string }[]\r\n) => ReactNode;\r\n\r\nconst componentForFilterMethod: Record<ComponentForFilterMethod, ComponentRenderer> = {\r\n text: (value, onChange) => (\r\n <Input\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as string) ?? \"\"}\r\n onChange={(e) => onChange(e.target.value)}\r\n />\r\n ),\r\n number: (value, onChange) => (\r\n <Input\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n type=\"number\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as number | null)?.toString() ?? \"\"}\r\n onChange={(e) => onChange(Number.parseFloat(e.target.value) || 0)}\r\n />\r\n ),\r\n date: (value, onChange) => (\r\n <DatePicker\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as any) ?? undefined}\r\n onChange={(date) => date && onChange(date as FilterValue)}\r\n maxValue={today(getLocalTimeZone()) as unknown as DateValue}\r\n />\r\n ),\r\n range: (value, onChange) => (\r\n <DateRangePicker\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as any) ?? undefined}\r\n onChange={(range) => range && onChange(range as FilterValue)}\r\n maxValue={today(getLocalTimeZone()) as unknown as DateValue}\r\n />\r\n ),\r\n radio: (value, onChange) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={(value as boolean | null) ? [\"true\"] : [\"false\"]}\r\n onSelectionChange={(keys) => onChange(keys.currentKey === \"true\")}\r\n >\r\n <SelectItem key=\"true\" className=\"text-sm\">\r\n True\r\n </SelectItem>\r\n <SelectItem key=\"false\" className=\"text-sm\">\r\n False\r\n </SelectItem>\r\n </Select>\r\n ),\r\n select: (value, onChange, options = []) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={(value as SharedSelection) ?? new Set()}\r\n onSelectionChange={(keys) => keys && onChange(keys as FilterValue)}\r\n >\r\n {options.map((option) => (\r\n <SelectItem key={option.value} className=\"text-sm\">\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n ),\r\n multiSelect: (value, onChange, options = []) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n selectionMode=\"multiple\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={value ? new Set(value as SharedSelection) : new Set()}\r\n onSelectionChange={(keys) => onChange(keys as FilterValue)}\r\n >\r\n {options.map((option) => (\r\n <SelectItem key={option.value} className=\"text-sm\">\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n ),\r\n};\r\n\r\nconst defaultFilterMethods: FilterMethods = {\r\n string: [\r\n { value: \"contains\", label: \"Contains\", component: \"text\" },\r\n { value: \"equals\", label: \"Equals\", component: \"text\" },\r\n { value: \"starts_with\", label: \"Starts With\", component: \"text\" },\r\n { value: \"ends_with\", label: \"Ends With\", component: \"text\" },\r\n ],\r\n number: [\r\n { value: \"equals\", label: \"Equals\", component: \"number\" },\r\n { value: \"greater_than\", label: \"Greater Than\", component: \"number\" },\r\n { value: \"less_than\", label: \"Less Than\", component: \"number\" },\r\n ],\r\n date: [\r\n { value: \"on\", label: \"On\", component: \"date\" },\r\n { value: \"between\", label: \"Between\", component: \"range\" },\r\n { value: \"before\", label: \"Before\", component: \"date\" },\r\n { value: \"after\", label: \"After\", component: \"date\" },\r\n { value: \"intersect\", label: \"During\", component: \"range\" },\r\n ],\r\n boolean: [{ value: \"equals\", label: \"Equals\", component: \"radio\" }],\r\n enum: [\r\n { value: \"oneOf\", label: \"One Of\", component: \"multiSelect\" },\r\n { value: \"equals\", label: \"Equals\", component: \"select\" },\r\n ],\r\n};\r\n\r\nconst SINGLE_FILTER_KEY = \"single-filter\";\r\n\r\ntype TableFilteringProps = {\r\n columns: {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }[];\r\n onFiltersChange: (filters: QueryFilters) => void;\r\n filters: QueryFilters;\r\n onClose?: () => void;\r\n singleFilter?: boolean;\r\n filterMethods?: Partial<FilterMethods>;\r\n};\r\n\r\nconst mergeFilterMethods = (overrides?: Partial<FilterMethods>): FilterMethods => ({\r\n string:\r\n overrides?.string && overrides.string.length > 0\r\n ? overrides.string\r\n : defaultFilterMethods.string,\r\n number:\r\n overrides?.number && overrides.number.length > 0\r\n ? overrides.number\r\n : defaultFilterMethods.number,\r\n date: overrides?.date && overrides.date.length > 0 ? overrides.date : defaultFilterMethods.date,\r\n boolean:\r\n overrides?.boolean && overrides.boolean.length > 0\r\n ? overrides.boolean\r\n : defaultFilterMethods.boolean,\r\n enum: overrides?.enum && overrides.enum.length > 0 ? overrides.enum : defaultFilterMethods.enum,\r\n});\r\n\r\nexport const TableFiltering = ({\r\n columns,\r\n onFiltersChange,\r\n filters: initialFilters = [],\r\n onClose,\r\n singleFilter = false,\r\n filterMethods,\r\n}: TableFilteringProps) => {\r\n const [filters, setFilters] = useState<Record<string, HeroUIFilter>>({});\r\n const effectiveFilterMethods = useMemo(() => mergeFilterMethods(filterMethods), [filterMethods]);\r\n\r\n const createEmptyFilter = useCallback(\r\n (): HeroUIFilter => ({\r\n columnId: \"\",\r\n type: null,\r\n value: null,\r\n method: null,\r\n options: null,\r\n endColumnId: null,\r\n periodStartColumnId: null,\r\n periodEndColumnId: null,\r\n }),\r\n []\r\n );\r\n\r\n const addFilter = useCallback(() => {\r\n setFilters((prev) => {\r\n if (!singleFilter) {\r\n const filterId = crypto.randomUUID();\r\n return {\r\n ...prev,\r\n [filterId]: createEmptyFilter(),\r\n };\r\n }\r\n\r\n // single filter mode\r\n return Object.keys(prev).length > 0 ? prev : { [SINGLE_FILTER_KEY]: createEmptyFilter() };\r\n });\r\n }, [createEmptyFilter, singleFilter]);\r\n\r\n const removeFilter = useCallback(\r\n (filterId: string) => {\r\n setFilters((prev) => {\r\n if (!singleFilter) {\r\n const { [filterId]: _, ...rest } = prev;\r\n return rest;\r\n }\r\n\r\n // single filter mode resets the lone filter\r\n return { [SINGLE_FILTER_KEY]: createEmptyFilter() };\r\n });\r\n },\r\n [createEmptyFilter, singleFilter]\r\n );\r\n\r\n const columnsMap = useMemo(\r\n () => new Map(columns.map((column) => [column.id, column])),\r\n [columns]\r\n );\r\n\r\n useEffect(() => {\r\n // Transform initialFilters from FiltersToApply format to HeroUIFilter format\r\n const transformedFilters = transformFiltersToHeroUI(\r\n initialFilters,\r\n columnsMap,\r\n effectiveFilterMethods\r\n );\r\n\r\n if (!singleFilter) {\r\n setFilters(Object.fromEntries(transformedFilters.map((filter) => [filter.columnId, filter])));\r\n return;\r\n }\r\n\r\n const firstFilter = transformedFilters[0];\r\n setFilters({\r\n [SINGLE_FILTER_KEY]: firstFilter ?? createEmptyFilter(),\r\n });\r\n }, [createEmptyFilter, initialFilters, singleFilter, columnsMap, effectiveFilterMethods]);\r\n\r\n const selectColumn = useCallback(\r\n (filterId: string, columnId: string) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n const column = columnsMap.get(columnId);\r\n if (!column) return prev;\r\n\r\n // If Period column, auto-set intersect method\r\n const isPeriodColumn = columnId.endsWith(\"__period\");\r\n const intersectMethod = isPeriodColumn\r\n ? (effectiveFilterMethods.date.find((m) => m.value === \"intersect\") ?? null)\r\n : null;\r\n\r\n return {\r\n ...prev,\r\n [filterId]: {\r\n ...oldFilter,\r\n columnId,\r\n type: column.type ?? null,\r\n options: column.options ?? null,\r\n endColumnId: column.endColumnId ?? null,\r\n periodStartColumnId: column.periodStartColumnId ?? null,\r\n periodEndColumnId: column.periodEndColumnId ?? null,\r\n method: intersectMethod,\r\n value: null,\r\n },\r\n };\r\n });\r\n },\r\n [columnsMap, effectiveFilterMethods]\r\n );\r\n\r\n const selectMethod = useCallback((filterId: string, method: FilterMethod) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n return {\r\n ...prev,\r\n [filterId]: { ...oldFilter, method, value: null },\r\n };\r\n });\r\n }, []);\r\n\r\n const selectValue = useCallback((filterId: string, value: FilterValue) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n return {\r\n ...prev,\r\n [filterId]: { ...oldFilter, value },\r\n };\r\n });\r\n }, []);\r\n\r\n const filterEntries = useMemo(() => Object.entries(filters), [filters]);\r\n\r\n const availableColumnsMap = useMemo(() => {\r\n const map = new Map<string, typeof columns>();\r\n filterEntries.forEach(([filterId]) => {\r\n const columnsUsedByOtherFilters = new Set(\r\n filterEntries\r\n .filter(([id]) => id !== filterId)\r\n .map(([_, f]) => f.columnId)\r\n .filter((id) => id !== \"\")\r\n );\r\n map.set(\r\n filterId,\r\n columns.filter((column) => !columnsUsedByOtherFilters.has(column.id))\r\n );\r\n });\r\n return map;\r\n }, [filterEntries, columns]);\r\n\r\n const applyFilters = useCallback(() => {\r\n const heroUIFilters = Object.values(filters);\r\n const filtersToApply = transformFiltersFromHeroUI(heroUIFilters);\r\n onFiltersChange(filtersToApply);\r\n onClose?.();\r\n }, [filters, onFiltersChange, onClose]);\r\n\r\n return (\r\n <div className=\"flex flex-col gap-2 p-1 min-w-[600px]\">\r\n {filterEntries.map(([filterId, filter]) => {\r\n const availableColumns = availableColumnsMap.get(filterId) ?? columns;\r\n return (\r\n <TableFilteringItem\r\n key={filterId}\r\n id={filterId}\r\n filter={filter}\r\n columns={availableColumns}\r\n selectColumn={selectColumn}\r\n selectMethod={selectMethod}\r\n removeFilter={removeFilter}\r\n selectValue={selectValue}\r\n filterMethods={effectiveFilterMethods}\r\n />\r\n );\r\n })}\r\n {!singleFilter && (\r\n <Button variant=\"outline\" size=\"sm\" onClick={addFilter}>\r\n <PlusIcon className=\"h-4 w-4\" />\r\n Add Filter\r\n </Button>\r\n )}\r\n <Button onClick={applyFilters}>{singleFilter ? \"Apply Filter\" : \"Apply Filters\"}</Button>\r\n </div>\r\n );\r\n};\r\n\r\nconst TableFilteringItem = ({\r\n id,\r\n filter,\r\n columns,\r\n selectColumn,\r\n selectMethod,\r\n selectValue,\r\n removeFilter,\r\n filterMethods,\r\n}: {\r\n id: string;\r\n filter: HeroUIFilter;\r\n columns: {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }[];\r\n selectColumn: (filterId: string, columnId: string) => void;\r\n selectMethod: (filterId: string, method: FilterMethod) => void;\r\n selectValue: (filterId: string, value: FilterValue) => void;\r\n removeFilter: (filterId: string) => void;\r\n filterMethods: FilterMethods;\r\n}) => {\r\n const handleColumnChange = useCallback(\r\n (keys: any) => {\r\n const columnId = String(keys.currentKey);\r\n selectColumn(id, columnId);\r\n },\r\n [id, selectColumn]\r\n );\r\n\r\n const methodsForType = useMemo(() => {\r\n if (!filter.type) return [];\r\n\r\n // Period columns only support intersect method\r\n const isPeriodColumn = filter.columnId.endsWith(\"__period\");\r\n if (isPeriodColumn) {\r\n const intersectMethod = filterMethods.date.find((m) => m.value === \"intersect\");\r\n return intersectMethod ? [intersectMethod] : [];\r\n }\r\n\r\n const baseMethods = filterMethods[filter.type as ColumnDataType] ?? [];\r\n const emptyMethods: FilterMethod[] = [\r\n { value: \"isEmpty\", label: \"Is Empty\", component: null },\r\n { value: \"isNotEmpty\", label: \"Is Not Empty\", component: null },\r\n ];\r\n\r\n if (filter.type !== \"boolean\" && filter.type !== \"date\") {\r\n return [...baseMethods, ...emptyMethods];\r\n }\r\n\r\n return baseMethods;\r\n }, [filter.type, filter.columnId, filter.method?.value, filterMethods]);\r\n\r\n const handleMethodChange = useCallback(\r\n (keys: any) => {\r\n if (!filter.type) return;\r\n // Use methodsForType instead of filterMethods to include dynamically added methods\r\n const method = methodsForType.find(\r\n (currentMethod: FilterMethod) => currentMethod.value === String(keys.currentKey)\r\n );\r\n if (method) {\r\n selectMethod(id, method);\r\n }\r\n },\r\n [id, filter.type, selectMethod, methodsForType]\r\n );\r\n\r\n const handleValueChange = useCallback(\r\n (value: FilterValue) => {\r\n selectValue(id, value);\r\n },\r\n [id, selectValue]\r\n );\r\n\r\n const methodSelect = useMemo(() => {\r\n if (!filter.type) return null;\r\n return (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Method\"\r\n className=\"w-40 flex-shrink-0 text-sm\"\r\n selectedKeys={filter.method?.value ? [filter.method.value] : []}\r\n onSelectionChange={handleMethodChange}\r\n popoverProps={{\r\n className: \"w-auto min-w-max\",\r\n }}\r\n >\r\n {methodsForType.map((method: FilterMethod) => (\r\n <SelectItem key={method.value} className=\"text-sm\">\r\n {method.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n );\r\n }, [filter.type, filter.method?.value, methodsForType, handleMethodChange]);\r\n\r\n const filterValueComponent = useMemo(() => {\r\n if (!filter.method?.component) {\r\n return <div className=\"flex-1 min-w-0\" />;\r\n }\r\n const component = filter.method.component as ComponentForFilterMethod;\r\n const ComponentFn =\r\n componentForFilterMethod[component as keyof typeof componentForFilterMethod];\r\n if (!ComponentFn) return <div className=\"flex-1 min-w-0\" />;\r\n return ComponentFn(filter.value as any, handleValueChange, filter.options ?? []);\r\n }, [filter.method?.component, filter.value, filter.options, handleValueChange]);\r\n\r\n const columnSelectItems = useMemo(\r\n () =>\r\n columns.map((column) => (\r\n <SelectItem key={column.id} className=\"text-sm\">\r\n {String(column.label)}\r\n </SelectItem>\r\n )),\r\n [columns]\r\n );\r\n\r\n return (\r\n <div className=\"flex items-center gap-2 w-full\">\r\n <div className=\"flex flex-1 items-center gap-2 min-w-0\">\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Column\"\r\n className=\"w-40 flex-shrink-0 text-sm\"\r\n selectedKeys={filter.columnId ? [filter.columnId] : []}\r\n onSelectionChange={handleColumnChange}\r\n popoverProps={{\r\n className: \"w-auto min-w-max\",\r\n }}\r\n >\r\n {columnSelectItems}\r\n </Select>\r\n {methodSelect}\r\n {filterValueComponent}\r\n </div>\r\n <Button variant=\"outline\" size=\"sm\" onClick={() => removeFilter(id)}>\r\n <XIcon className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n );\r\n};\r\n"],"mappings":";;;;;;;;AAkCA,MAAM,2BAAgF;CACpF,OAAO,OAAO,aACZ,oBAAC,OAAD;EACE,MAAK;EACL,cAAW;EACX,WAAU;EACV,OAAQ,SAAoB;EAC5B,WAAW,MAAM,SAAS,EAAE,OAAO,MAAM;EACzC,CAAA;CAEJ,SAAS,OAAO,aACd,oBAAC,OAAD;EACE,MAAK;EACL,cAAW;EACX,MAAK;EACL,WAAU;EACV,OAAQ,OAAyB,UAAU,IAAI;EAC/C,WAAW,MAAM,SAAS,OAAO,WAAW,EAAE,OAAO,MAAM,IAAI,EAAE;EACjE,CAAA;CAEJ,OAAO,OAAO,aACZ,oBAAC,YAAD;EACE,MAAK;EACL,cAAW;EACX,WAAU;EACV,OAAQ,SAAiB,KAAA;EACzB,WAAW,SAAS,QAAQ,SAAS,KAAoB;EACzD,UAAU,MAAM,kBAAkB,CAAC;EACnC,CAAA;CAEJ,QAAQ,OAAO,aACb,oBAAC,iBAAD;EACE,MAAK;EACL,cAAW;EACX,WAAU;EACV,OAAQ,SAAiB,KAAA;EACzB,WAAW,UAAU,SAAS,SAAS,MAAqB;EAC5D,UAAU,MAAM,kBAAkB,CAAC;EACnC,CAAA;CAEJ,QAAQ,OAAO,aACb,qBAAC,QAAD;EACE,MAAK;EACL,cAAW;EACX,WAAU;EACV,cAAe,QAA2B,CAAC,OAAO,GAAG,CAAC,QAAQ;EAC9D,oBAAoB,SAAS,SAAS,KAAK,eAAe,OAAO;YALnE,CAOE,oBAAC,YAAD;GAAuB,WAAU;aAAU;GAE9B,EAFG,OAEH,EACb,oBAAC,YAAD;GAAwB,WAAU;aAAU;GAE/B,EAFG,QAEH,CACN;;CAEX,SAAS,OAAO,UAAU,UAAU,EAAE,KACpC,oBAAC,QAAD;EACE,MAAK;EACL,cAAW;EACX,WAAU;EACV,cAAe,yBAA6B,IAAI,KAAK;EACrD,oBAAoB,SAAS,QAAQ,SAAS,KAAoB;YAEjE,QAAQ,KAAK,WACZ,oBAAC,YAAD;GAA+B,WAAU;aACtC,OAAO;GACG,EAFI,OAAO,MAEX,CACb;EACK,CAAA;CAEX,cAAc,OAAO,UAAU,UAAU,EAAE,KACzC,oBAAC,QAAD;EACE,MAAK;EACL,cAAW;EACX,eAAc;EACd,WAAU;EACV,cAAc,QAAQ,IAAI,IAAI,MAAyB,mBAAG,IAAI,KAAK;EACnE,oBAAoB,SAAS,SAAS,KAAoB;YAEzD,QAAQ,KAAK,WACZ,oBAAC,YAAD;GAA+B,WAAU;aACtC,OAAO;GACG,EAFI,OAAO,MAEX,CACb;EACK,CAAA;CAEZ;AAED,MAAM,uBAAsC;CAC1C,QAAQ;EACN;GAAE,OAAO;GAAY,OAAO;GAAY,WAAW;GAAQ;EAC3D;GAAE,OAAO;GAAU,OAAO;GAAU,WAAW;GAAQ;EACvD;GAAE,OAAO;GAAe,OAAO;GAAe,WAAW;GAAQ;EACjE;GAAE,OAAO;GAAa,OAAO;GAAa,WAAW;GAAQ;EAC9D;CACD,QAAQ;EACN;GAAE,OAAO;GAAU,OAAO;GAAU,WAAW;GAAU;EACzD;GAAE,OAAO;GAAgB,OAAO;GAAgB,WAAW;GAAU;EACrE;GAAE,OAAO;GAAa,OAAO;GAAa,WAAW;GAAU;EAChE;CACD,MAAM;EACJ;GAAE,OAAO;GAAM,OAAO;GAAM,WAAW;GAAQ;EAC/C;GAAE,OAAO;GAAW,OAAO;GAAW,WAAW;GAAS;EAC1D;GAAE,OAAO;GAAU,OAAO;GAAU,WAAW;GAAQ;EACvD;GAAE,OAAO;GAAS,OAAO;GAAS,WAAW;GAAQ;EACrD;GAAE,OAAO;GAAa,OAAO;GAAU,WAAW;GAAS;EAC5D;CACD,SAAS,CAAC;EAAE,OAAO;EAAU,OAAO;EAAU,WAAW;EAAS,CAAC;CACnE,MAAM,CACJ;EAAE,OAAO;EAAS,OAAO;EAAU,WAAW;EAAe,EAC7D;EAAE,OAAO;EAAU,OAAO;EAAU,WAAW;EAAU,CAC1D;CACF;AAED,MAAM,oBAAoB;AAmB1B,MAAM,sBAAsB,eAAuD;CACjF,QACE,WAAW,UAAU,UAAU,OAAO,SAAS,IAC3C,UAAU,SACV,qBAAqB;CAC3B,QACE,WAAW,UAAU,UAAU,OAAO,SAAS,IAC3C,UAAU,SACV,qBAAqB;CAC3B,MAAM,WAAW,QAAQ,UAAU,KAAK,SAAS,IAAI,UAAU,OAAO,qBAAqB;CAC3F,SACE,WAAW,WAAW,UAAU,QAAQ,SAAS,IAC7C,UAAU,UACV,qBAAqB;CAC3B,MAAM,WAAW,QAAQ,UAAU,KAAK,SAAS,IAAI,UAAU,OAAO,qBAAqB;CAC5F;AAED,MAAa,kBAAkB,EAC7B,SACA,iBACA,SAAS,iBAAiB,EAAE,EAC5B,SACA,eAAe,OACf,oBACyB;CACzB,MAAM,CAAC,SAAS,cAAc,SAAuC,EAAE,CAAC;CACxE,MAAM,yBAAyB,cAAc,mBAAmB,cAAc,EAAE,CAAC,cAAc,CAAC;CAEhG,MAAM,oBAAoB,mBACH;EACnB,UAAU;EACV,MAAM;EACN,OAAO;EACP,QAAQ;EACR,SAAS;EACT,aAAa;EACb,qBAAqB;EACrB,mBAAmB;EACpB,GACD,EAAE,CACH;CAED,MAAM,YAAY,kBAAkB;AAClC,cAAY,SAAS;AACnB,OAAI,CAAC,cAAc;IACjB,MAAM,WAAW,OAAO,YAAY;AACpC,WAAO;KACL,GAAG;MACF,WAAW,mBAAmB;KAChC;;AAIH,UAAO,OAAO,KAAK,KAAK,CAAC,SAAS,IAAI,OAAO,GAAG,oBAAoB,mBAAmB,EAAE;IACzF;IACD,CAAC,mBAAmB,aAAa,CAAC;CAErC,MAAM,eAAe,aAClB,aAAqB;AACpB,cAAY,SAAS;AACnB,OAAI,CAAC,cAAc;IACjB,MAAM,GAAG,WAAW,GAAG,GAAG,SAAS;AACnC,WAAO;;AAIT,UAAO,GAAG,oBAAoB,mBAAmB,EAAE;IACnD;IAEJ,CAAC,mBAAmB,aAAa,CAClC;CAED,MAAM,aAAa,cACX,IAAI,IAAI,QAAQ,KAAK,WAAW,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,EAC3D,CAAC,QAAQ,CACV;AAED,iBAAgB;EAEd,MAAM,qBAAqB,yBACzB,gBACA,YACA,uBACD;AAED,MAAI,CAAC,cAAc;AACjB,cAAW,OAAO,YAAY,mBAAmB,KAAK,WAAW,CAAC,OAAO,UAAU,OAAO,CAAC,CAAC,CAAC;AAC7F;;EAGF,MAAM,cAAc,mBAAmB;AACvC,aAAW,GACR,oBAAoB,eAAe,mBAAmB,EACxD,CAAC;IACD;EAAC;EAAmB;EAAgB;EAAc;EAAY;EAAuB,CAAC;CAEzF,MAAM,eAAe,aAClB,UAAkB,aAAqB;AACtC,cAAY,SAAS;GACnB,MAAM,YAAY,KAAK;AACvB,OAAI,CAAC,UAAW,QAAO;GACvB,MAAM,SAAS,WAAW,IAAI,SAAS;AACvC,OAAI,CAAC,OAAQ,QAAO;GAIpB,MAAM,kBADiB,SAAS,SAAS,WAAW,GAE/C,uBAAuB,KAAK,MAAM,MAAM,EAAE,UAAU,YAAY,IAAI,OACrE;AAEJ,UAAO;IACL,GAAG;KACF,WAAW;KACV,GAAG;KACH;KACA,MAAM,OAAO,QAAQ;KACrB,SAAS,OAAO,WAAW;KAC3B,aAAa,OAAO,eAAe;KACnC,qBAAqB,OAAO,uBAAuB;KACnD,mBAAmB,OAAO,qBAAqB;KAC/C,QAAQ;KACR,OAAO;KACR;IACF;IACD;IAEJ,CAAC,YAAY,uBAAuB,CACrC;CAED,MAAM,eAAe,aAAa,UAAkB,WAAyB;AAC3E,cAAY,SAAS;GACnB,MAAM,YAAY,KAAK;AACvB,OAAI,CAAC,UAAW,QAAO;AACvB,UAAO;IACL,GAAG;KACF,WAAW;KAAE,GAAG;KAAW;KAAQ,OAAO;KAAM;IAClD;IACD;IACD,EAAE,CAAC;CAEN,MAAM,cAAc,aAAa,UAAkB,UAAuB;AACxE,cAAY,SAAS;GACnB,MAAM,YAAY,KAAK;AACvB,OAAI,CAAC,UAAW,QAAO;AACvB,UAAO;IACL,GAAG;KACF,WAAW;KAAE,GAAG;KAAW;KAAO;IACpC;IACD;IACD,EAAE,CAAC;CAEN,MAAM,gBAAgB,cAAc,OAAO,QAAQ,QAAQ,EAAE,CAAC,QAAQ,CAAC;CAEvE,MAAM,sBAAsB,cAAc;EACxC,MAAM,sBAAM,IAAI,KAA6B;AAC7C,gBAAc,SAAS,CAAC,cAAc;GACpC,MAAM,4BAA4B,IAAI,IACpC,cACG,QAAQ,CAAC,QAAQ,OAAO,SAAS,CACjC,KAAK,CAAC,GAAG,OAAO,EAAE,SAAS,CAC3B,QAAQ,OAAO,OAAO,GAAG,CAC7B;AACD,OAAI,IACF,UACA,QAAQ,QAAQ,WAAW,CAAC,0BAA0B,IAAI,OAAO,GAAG,CAAC,CACtE;IACD;AACF,SAAO;IACN,CAAC,eAAe,QAAQ,CAAC;CAE5B,MAAM,eAAe,kBAAkB;AAGrC,kBADuB,2BADD,OAAO,OAAO,QAAQ,CACoB,CACjC;AAC/B,aAAW;IACV;EAAC;EAAS;EAAiB;EAAQ,CAAC;AAEvC,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,cAAc,KAAK,CAAC,UAAU,YAAY;AAEzC,WACE,oBAAC,oBAAD;KAEE,IAAI;KACI;KACR,SANqB,oBAAoB,IAAI,SAAS,IAAI;KAO5C;KACA;KACA;KACD;KACb,eAAe;KACf,EATK,SASL;KAEJ;GACD,CAAC,gBACA,qBAACA,UAAD;IAAQ,SAAQ;IAAU,MAAK;IAAK,SAAS;cAA7C,CACE,oBAAC,UAAD,EAAU,WAAU,WAAY,CAAA,EAAA,aAEzB;;GAEX,oBAACA,UAAD;IAAQ,SAAS;cAAe,eAAe,iBAAiB;IAAyB,CAAA;GACrF;;;AAIV,MAAM,sBAAsB,EAC1B,IACA,QACA,SACA,cACA,cACA,aACA,cACA,oBAkBI;CACJ,MAAM,qBAAqB,aACxB,SAAc;AAEb,eAAa,IADI,OAAO,KAAK,WAAW,CACd;IAE5B,CAAC,IAAI,aAAa,CACnB;CAED,MAAM,iBAAiB,cAAc;AACnC,MAAI,CAAC,OAAO,KAAM,QAAO,EAAE;AAI3B,MADuB,OAAO,SAAS,SAAS,WAAW,EACvC;GAClB,MAAM,kBAAkB,cAAc,KAAK,MAAM,MAAM,EAAE,UAAU,YAAY;AAC/E,UAAO,kBAAkB,CAAC,gBAAgB,GAAG,EAAE;;EAGjD,MAAM,cAAc,cAAc,OAAO,SAA2B,EAAE;EACtE,MAAM,eAA+B,CACnC;GAAE,OAAO;GAAW,OAAO;GAAY,WAAW;GAAM,EACxD;GAAE,OAAO;GAAc,OAAO;GAAgB,WAAW;GAAM,CAChE;AAED,MAAI,OAAO,SAAS,aAAa,OAAO,SAAS,OAC/C,QAAO,CAAC,GAAG,aAAa,GAAG,aAAa;AAG1C,SAAO;IACN;EAAC,OAAO;EAAM,OAAO;EAAU,OAAO,QAAQ;EAAO;EAAc,CAAC;CAEvE,MAAM,qBAAqB,aACxB,SAAc;AACb,MAAI,CAAC,OAAO,KAAM;EAElB,MAAM,SAAS,eAAe,MAC3B,kBAAgC,cAAc,UAAU,OAAO,KAAK,WAAW,CACjF;AACD,MAAI,OACF,cAAa,IAAI,OAAO;IAG5B;EAAC;EAAI,OAAO;EAAM;EAAc;EAAe,CAChD;CAED,MAAM,oBAAoB,aACvB,UAAuB;AACtB,cAAY,IAAI,MAAM;IAExB,CAAC,IAAI,YAAY,CAClB;CAED,MAAM,eAAe,cAAc;AACjC,MAAI,CAAC,OAAO,KAAM,QAAO;AACzB,SACE,oBAAC,QAAD;GACE,MAAK;GACL,cAAW;GACX,WAAU;GACV,cAAc,OAAO,QAAQ,QAAQ,CAAC,OAAO,OAAO,MAAM,GAAG,EAAE;GAC/D,mBAAmB;GACnB,cAAc,EACZ,WAAW,oBACZ;aAEA,eAAe,KAAK,WACnB,oBAAC,YAAD;IAA+B,WAAU;cACtC,OAAO;IACG,EAFI,OAAO,MAEX,CACb;GACK,CAAA;IAEV;EAAC,OAAO;EAAM,OAAO,QAAQ;EAAO;EAAgB;EAAmB,CAAC;CAE3E,MAAM,uBAAuB,cAAc;AACzC,MAAI,CAAC,OAAO,QAAQ,UAClB,QAAO,oBAAC,OAAD,EAAK,WAAU,kBAAmB,CAAA;EAG3C,MAAM,cACJ,yBAFgB,OAAO,OAAO;AAGhC,MAAI,CAAC,YAAa,QAAO,oBAAC,OAAD,EAAK,WAAU,kBAAmB,CAAA;AAC3D,SAAO,YAAY,OAAO,OAAc,mBAAmB,OAAO,WAAW,EAAE,CAAC;IAC/E;EAAC,OAAO,QAAQ;EAAW,OAAO;EAAO,OAAO;EAAS;EAAkB,CAAC;CAE/E,MAAM,oBAAoB,cAEtB,QAAQ,KAAK,WACX,oBAAC,YAAD;EAA4B,WAAU;YACnC,OAAO,OAAO,MAAM;EACV,EAFI,OAAO,GAEX,CACb,EACJ,CAAC,QAAQ,CACV;AAED,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf;IACE,oBAAC,QAAD;KACE,MAAK;KACL,cAAW;KACX,WAAU;KACV,cAAc,OAAO,WAAW,CAAC,OAAO,SAAS,GAAG,EAAE;KACtD,mBAAmB;KACnB,cAAc,EACZ,WAAW,oBACZ;eAEA;KACM,CAAA;IACR;IACA;IACG;MACN,oBAACA,UAAD;GAAQ,SAAQ;GAAU,MAAK;GAAK,eAAe,aAAa,GAAG;aACjE,oBAAC,OAAD,EAAO,WAAU,WAAY,CAAA;GACtB,CAAA,CACL"}
|
|
1
|
+
{"version":3,"file":"TableFiltering.mjs","names":["Button"],"sources":["../../../../../src/modules/table/components/TableFiltering.tsx"],"sourcesContent":["import {\r\n DatePicker,\r\n DateRangePicker,\r\n type DateValue,\r\n Input,\r\n Select,\r\n SelectItem,\r\n type SharedSelection,\r\n} from \"@heroui/react\";\r\nimport { getLocalTimeZone, today } from \"@internationalized/date\";\r\nimport type { QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport type {\r\n ColumnDataType,\r\n ComponentForFilterMethod,\r\n FilterMethod,\r\n FilterMethods,\r\n} from \"@m5kdev/commons/modules/table/filter.types\";\r\nimport { PlusIcon, XIcon } from \"lucide-react\";\r\nimport type { ReactNode } from \"react\";\r\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\r\nimport { Button } from \"../../../components/ui/button\";\r\nimport {\r\n type FilterValue,\r\n type HeroUIFilter,\r\n transformFiltersFromHeroUI,\r\n transformFiltersToHeroUI,\r\n} from \"../filterTransformers\";\r\n\r\ntype ComponentRenderer = (\r\n value: FilterValue,\r\n onChange: (value: FilterValue) => void,\r\n options?: { label: string; value: string }[]\r\n) => ReactNode;\r\n\r\nconst componentForFilterMethod: Record<ComponentForFilterMethod, ComponentRenderer> = {\r\n text: (value, onChange) => (\r\n <Input\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as string) ?? \"\"}\r\n onChange={(e) => onChange(e.target.value)}\r\n />\r\n ),\r\n number: (value, onChange) => (\r\n <Input\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n type=\"number\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as number | null)?.toString() ?? \"\"}\r\n onChange={(e) => onChange(Number.parseFloat(e.target.value) || 0)}\r\n />\r\n ),\r\n date: (value, onChange) => (\r\n <DatePicker\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as any) ?? undefined}\r\n onChange={(date) => date && onChange(date as FilterValue)}\r\n maxValue={today(getLocalTimeZone()) as unknown as DateValue}\r\n />\r\n ),\r\n range: (value, onChange) => (\r\n <DateRangePicker\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n value={(value as any) ?? undefined}\r\n onChange={(range) => range && onChange(range as FilterValue)}\r\n maxValue={today(getLocalTimeZone()) as unknown as DateValue}\r\n />\r\n ),\r\n radio: (value, onChange) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={(value as boolean | null) ? [\"true\"] : [\"false\"]}\r\n onSelectionChange={(keys) => onChange(keys.currentKey === \"true\")}\r\n >\r\n <SelectItem key=\"true\" className=\"text-sm\">\r\n True\r\n </SelectItem>\r\n <SelectItem key=\"false\" className=\"text-sm\">\r\n False\r\n </SelectItem>\r\n </Select>\r\n ),\r\n select: (value, onChange, options = []) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={(value as SharedSelection) ?? new Set()}\r\n onSelectionChange={(keys) => keys && onChange(keys as FilterValue)}\r\n >\r\n {options.map((option) => (\r\n <SelectItem key={option.value} className=\"text-sm\">\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n ),\r\n multiSelect: (value, onChange, options = []) => (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Value\"\r\n selectionMode=\"multiple\"\r\n className=\"flex-1 min-w-0 text-sm\"\r\n selectedKeys={value ? new Set(value as SharedSelection) : new Set()}\r\n onSelectionChange={(keys) => onChange(keys as FilterValue)}\r\n >\r\n {options.map((option) => (\r\n <SelectItem key={option.value} className=\"text-sm\">\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n ),\r\n};\r\n\r\nconst defaultFilterMethods: FilterMethods = {\r\n string: [\r\n { value: \"contains\", label: \"Contains\", component: \"text\" },\r\n { value: \"equals\", label: \"Equals\", component: \"text\" },\r\n { value: \"starts_with\", label: \"Starts With\", component: \"text\" },\r\n { value: \"ends_with\", label: \"Ends With\", component: \"text\" },\r\n ],\r\n number: [\r\n { value: \"equals\", label: \"Equals\", component: \"number\" },\r\n { value: \"greater_than\", label: \"Greater Than\", component: \"number\" },\r\n { value: \"less_than\", label: \"Less Than\", component: \"number\" },\r\n ],\r\n date: [\r\n { value: \"on\", label: \"On\", component: \"date\" },\r\n { value: \"between\", label: \"Between\", component: \"range\" },\r\n { value: \"before\", label: \"Before\", component: \"date\" },\r\n { value: \"after\", label: \"After\", component: \"date\" },\r\n { value: \"intersect\", label: \"During\", component: \"range\" },\r\n ],\r\n boolean: [{ value: \"equals\", label: \"Equals\", component: \"radio\" }],\r\n enum: [\r\n { value: \"oneOf\", label: \"One Of\", component: \"multiSelect\" },\r\n { value: \"equals\", label: \"Equals\", component: \"select\" },\r\n ],\r\n jsonArray: [\r\n { value: \"oneOf\", label: \"One Of\", component: \"multiSelect\" },\r\n { value: \"equals\", label: \"Equals\", component: \"select\" },\r\n ],\r\n};\r\n\r\nconst SINGLE_FILTER_KEY = \"single-filter\";\r\n\r\ntype TableFilteringProps = {\r\n columns: {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }[];\r\n onFiltersChange: (filters: QueryFilters) => void;\r\n filters: QueryFilters;\r\n onClose?: () => void;\r\n singleFilter?: boolean;\r\n filterMethods?: Partial<FilterMethods>;\r\n};\r\n\r\nconst mergeFilterMethods = (overrides?: Partial<FilterMethods>): FilterMethods => ({\r\n string:\r\n overrides?.string && overrides.string.length > 0\r\n ? overrides.string\r\n : defaultFilterMethods.string,\r\n number:\r\n overrides?.number && overrides.number.length > 0\r\n ? overrides.number\r\n : defaultFilterMethods.number,\r\n date: overrides?.date && overrides.date.length > 0 ? overrides.date : defaultFilterMethods.date,\r\n boolean:\r\n overrides?.boolean && overrides.boolean.length > 0\r\n ? overrides.boolean\r\n : defaultFilterMethods.boolean,\r\n enum: overrides?.enum && overrides.enum.length > 0 ? overrides.enum : defaultFilterMethods.enum,\r\n jsonArray:\r\n overrides?.jsonArray && overrides.jsonArray.length > 0\r\n ? overrides.jsonArray\r\n : defaultFilterMethods.jsonArray,\r\n});\r\n\r\nexport const TableFiltering = ({\r\n columns,\r\n onFiltersChange,\r\n filters: initialFilters = [],\r\n onClose,\r\n singleFilter = false,\r\n filterMethods,\r\n}: TableFilteringProps) => {\r\n const [filters, setFilters] = useState<Record<string, HeroUIFilter>>({});\r\n const effectiveFilterMethods = useMemo(() => mergeFilterMethods(filterMethods), [filterMethods]);\r\n\r\n const createEmptyFilter = useCallback(\r\n (): HeroUIFilter => ({\r\n columnId: \"\",\r\n type: null,\r\n value: null,\r\n method: null,\r\n options: null,\r\n endColumnId: null,\r\n periodStartColumnId: null,\r\n periodEndColumnId: null,\r\n }),\r\n []\r\n );\r\n\r\n const addFilter = useCallback(() => {\r\n setFilters((prev) => {\r\n if (!singleFilter) {\r\n const filterId = crypto.randomUUID();\r\n return {\r\n ...prev,\r\n [filterId]: createEmptyFilter(),\r\n };\r\n }\r\n\r\n // single filter mode\r\n return Object.keys(prev).length > 0 ? prev : { [SINGLE_FILTER_KEY]: createEmptyFilter() };\r\n });\r\n }, [createEmptyFilter, singleFilter]);\r\n\r\n const removeFilter = useCallback(\r\n (filterId: string) => {\r\n setFilters((prev) => {\r\n if (!singleFilter) {\r\n const { [filterId]: _, ...rest } = prev;\r\n return rest;\r\n }\r\n\r\n // single filter mode resets the lone filter\r\n return { [SINGLE_FILTER_KEY]: createEmptyFilter() };\r\n });\r\n },\r\n [createEmptyFilter, singleFilter]\r\n );\r\n\r\n const columnsMap = useMemo(\r\n () => new Map(columns.map((column) => [column.id, column])),\r\n [columns]\r\n );\r\n\r\n useEffect(() => {\r\n // Transform initialFilters from FiltersToApply format to HeroUIFilter format\r\n const transformedFilters = transformFiltersToHeroUI(\r\n initialFilters,\r\n columnsMap,\r\n effectiveFilterMethods\r\n );\r\n\r\n if (!singleFilter) {\r\n setFilters(Object.fromEntries(transformedFilters.map((filter) => [filter.columnId, filter])));\r\n return;\r\n }\r\n\r\n const firstFilter = transformedFilters[0];\r\n setFilters({\r\n [SINGLE_FILTER_KEY]: firstFilter ?? createEmptyFilter(),\r\n });\r\n }, [createEmptyFilter, initialFilters, singleFilter, columnsMap, effectiveFilterMethods]);\r\n\r\n const selectColumn = useCallback(\r\n (filterId: string, columnId: string) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n const column = columnsMap.get(columnId);\r\n if (!column) return prev;\r\n\r\n // If Period column, auto-set intersect method\r\n const isPeriodColumn = columnId.endsWith(\"__period\");\r\n const intersectMethod = isPeriodColumn\r\n ? (effectiveFilterMethods.date.find((m) => m.value === \"intersect\") ?? null)\r\n : null;\r\n\r\n return {\r\n ...prev,\r\n [filterId]: {\r\n ...oldFilter,\r\n columnId,\r\n type: column.type ?? null,\r\n options: column.options ?? null,\r\n endColumnId: column.endColumnId ?? null,\r\n periodStartColumnId: column.periodStartColumnId ?? null,\r\n periodEndColumnId: column.periodEndColumnId ?? null,\r\n method: intersectMethod,\r\n value: null,\r\n },\r\n };\r\n });\r\n },\r\n [columnsMap, effectiveFilterMethods]\r\n );\r\n\r\n const selectMethod = useCallback((filterId: string, method: FilterMethod) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n return {\r\n ...prev,\r\n [filterId]: { ...oldFilter, method, value: null },\r\n };\r\n });\r\n }, []);\r\n\r\n const selectValue = useCallback((filterId: string, value: FilterValue) => {\r\n setFilters((prev) => {\r\n const oldFilter = prev[filterId];\r\n if (!oldFilter) return prev;\r\n return {\r\n ...prev,\r\n [filterId]: { ...oldFilter, value },\r\n };\r\n });\r\n }, []);\r\n\r\n const filterEntries = useMemo(() => Object.entries(filters), [filters]);\r\n\r\n const availableColumnsMap = useMemo(() => {\r\n const map = new Map<string, typeof columns>();\r\n filterEntries.forEach(([filterId]) => {\r\n const columnsUsedByOtherFilters = new Set(\r\n filterEntries\r\n .filter(([id]) => id !== filterId)\r\n .map(([_, f]) => f.columnId)\r\n .filter((id) => id !== \"\")\r\n );\r\n map.set(\r\n filterId,\r\n columns.filter((column) => !columnsUsedByOtherFilters.has(column.id))\r\n );\r\n });\r\n return map;\r\n }, [filterEntries, columns]);\r\n\r\n const applyFilters = useCallback(() => {\r\n const heroUIFilters = Object.values(filters);\r\n const filtersToApply = transformFiltersFromHeroUI(heroUIFilters);\r\n onFiltersChange(filtersToApply);\r\n onClose?.();\r\n }, [filters, onFiltersChange, onClose]);\r\n\r\n return (\r\n <div className=\"flex flex-col gap-2 p-1 min-w-[600px]\">\r\n {filterEntries.map(([filterId, filter]) => {\r\n const availableColumns = availableColumnsMap.get(filterId) ?? columns;\r\n return (\r\n <TableFilteringItem\r\n key={filterId}\r\n id={filterId}\r\n filter={filter}\r\n columns={availableColumns}\r\n selectColumn={selectColumn}\r\n selectMethod={selectMethod}\r\n removeFilter={removeFilter}\r\n selectValue={selectValue}\r\n filterMethods={effectiveFilterMethods}\r\n />\r\n );\r\n })}\r\n {!singleFilter && (\r\n <Button variant=\"outline\" size=\"sm\" onClick={addFilter}>\r\n <PlusIcon className=\"h-4 w-4\" />\r\n Add Filter\r\n </Button>\r\n )}\r\n <Button onClick={applyFilters}>{singleFilter ? \"Apply Filter\" : \"Apply Filters\"}</Button>\r\n </div>\r\n );\r\n};\r\n\r\nconst TableFilteringItem = ({\r\n id,\r\n filter,\r\n columns,\r\n selectColumn,\r\n selectMethod,\r\n selectValue,\r\n removeFilter,\r\n filterMethods,\r\n}: {\r\n id: string;\r\n filter: HeroUIFilter;\r\n columns: {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }[];\r\n selectColumn: (filterId: string, columnId: string) => void;\r\n selectMethod: (filterId: string, method: FilterMethod) => void;\r\n selectValue: (filterId: string, value: FilterValue) => void;\r\n removeFilter: (filterId: string) => void;\r\n filterMethods: FilterMethods;\r\n}) => {\r\n const handleColumnChange = useCallback(\r\n (keys: any) => {\r\n const columnId = String(keys.currentKey);\r\n selectColumn(id, columnId);\r\n },\r\n [id, selectColumn]\r\n );\r\n\r\n const methodsForType = useMemo(() => {\r\n if (!filter.type) return [];\r\n\r\n // Period columns only support intersect method\r\n const isPeriodColumn = filter.columnId.endsWith(\"__period\");\r\n if (isPeriodColumn) {\r\n const intersectMethod = filterMethods.date.find((m) => m.value === \"intersect\");\r\n return intersectMethod ? [intersectMethod] : [];\r\n }\r\n\r\n const baseMethods = filterMethods[filter.type as ColumnDataType] ?? [];\r\n const emptyMethods: FilterMethod[] = [\r\n { value: \"isEmpty\", label: \"Is Empty\", component: null },\r\n { value: \"isNotEmpty\", label: \"Is Not Empty\", component: null },\r\n ];\r\n\r\n if (filter.type !== \"boolean\" && filter.type !== \"date\") {\r\n return [...baseMethods, ...emptyMethods];\r\n }\r\n\r\n return baseMethods;\r\n }, [filter.type, filter.columnId, filter.method?.value, filterMethods]);\r\n\r\n const handleMethodChange = useCallback(\r\n (keys: any) => {\r\n if (!filter.type) return;\r\n // Use methodsForType instead of filterMethods to include dynamically added methods\r\n const method = methodsForType.find(\r\n (currentMethod: FilterMethod) => currentMethod.value === String(keys.currentKey)\r\n );\r\n if (method) {\r\n selectMethod(id, method);\r\n }\r\n },\r\n [id, filter.type, selectMethod, methodsForType]\r\n );\r\n\r\n const handleValueChange = useCallback(\r\n (value: FilterValue) => {\r\n selectValue(id, value);\r\n },\r\n [id, selectValue]\r\n );\r\n\r\n const methodSelect = useMemo(() => {\r\n if (!filter.type) return null;\r\n return (\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Method\"\r\n className=\"w-40 flex-shrink-0 text-sm\"\r\n selectedKeys={filter.method?.value ? [filter.method.value] : []}\r\n onSelectionChange={handleMethodChange}\r\n popoverProps={{\r\n className: \"w-auto min-w-max\",\r\n }}\r\n >\r\n {methodsForType.map((method: FilterMethod) => (\r\n <SelectItem key={method.value} className=\"text-sm\">\r\n {method.label}\r\n </SelectItem>\r\n ))}\r\n </Select>\r\n );\r\n }, [filter.type, filter.method?.value, methodsForType, handleMethodChange]);\r\n\r\n const filterValueComponent = useMemo(() => {\r\n if (!filter.method?.component) {\r\n return <div className=\"flex-1 min-w-0\" />;\r\n }\r\n const component = filter.method.component as ComponentForFilterMethod;\r\n const ComponentFn =\r\n componentForFilterMethod[component as keyof typeof componentForFilterMethod];\r\n if (!ComponentFn) return <div className=\"flex-1 min-w-0\" />;\r\n return ComponentFn(filter.value as any, handleValueChange, filter.options ?? []);\r\n }, [filter.method?.component, filter.value, filter.options, handleValueChange]);\r\n\r\n const columnSelectItems = useMemo(\r\n () =>\r\n columns.map((column) => (\r\n <SelectItem key={column.id} className=\"text-sm\">\r\n {String(column.label)}\r\n </SelectItem>\r\n )),\r\n [columns]\r\n );\r\n\r\n return (\r\n <div className=\"flex items-center gap-2 w-full\">\r\n <div className=\"flex flex-1 items-center gap-2 min-w-0\">\r\n <Select\r\n size=\"sm\"\r\n aria-label=\"Select Column\"\r\n className=\"w-40 flex-shrink-0 text-sm\"\r\n selectedKeys={filter.columnId ? [filter.columnId] : []}\r\n onSelectionChange={handleColumnChange}\r\n popoverProps={{\r\n className: \"w-auto min-w-max\",\r\n }}\r\n >\r\n {columnSelectItems}\r\n </Select>\r\n {methodSelect}\r\n {filterValueComponent}\r\n </div>\r\n <Button variant=\"outline\" size=\"sm\" onClick={() => removeFilter(id)}>\r\n <XIcon className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n );\r\n};\r\n"],"mappings":"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"}
|
|
@@ -136,6 +136,20 @@ const transformFiltersToHeroUI = (filtersToTransform, columnsMap, filterMethods)
|
|
|
136
136
|
value = selection;
|
|
137
137
|
}
|
|
138
138
|
break;
|
|
139
|
+
case "jsonArray":
|
|
140
|
+
if (filter.method === "oneOf" && Array.isArray(filter.value)) value = new Set(filter.value);
|
|
141
|
+
else if (Array.isArray(filter.value) && filter.value.length > 0) {
|
|
142
|
+
const first = filter.value[0];
|
|
143
|
+
const selection = new Set([first]);
|
|
144
|
+
Object.defineProperty(selection, "currentKey", {
|
|
145
|
+
value: first,
|
|
146
|
+
writable: true,
|
|
147
|
+
enumerable: false,
|
|
148
|
+
configurable: true
|
|
149
|
+
});
|
|
150
|
+
value = selection;
|
|
151
|
+
} else value = filter.value;
|
|
152
|
+
break;
|
|
139
153
|
default: value = filter.value;
|
|
140
154
|
}
|
|
141
155
|
const column = columnsMap.get(columnId);
|
|
@@ -192,10 +206,15 @@ const transformFiltersFromHeroUI = (filters) => {
|
|
|
192
206
|
if (selection) value = filter.method?.value === "oneOf" ? Array.from(selection).map(String) : String(selection.currentKey);
|
|
193
207
|
break;
|
|
194
208
|
}
|
|
209
|
+
case "jsonArray": {
|
|
210
|
+
const selection = filter.value;
|
|
211
|
+
if (selection) value = filter.method?.value === "oneOf" ? Array.from(selection).map(String) : [String(selection.currentKey)];
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
195
214
|
default: value = filter.value;
|
|
196
215
|
}
|
|
197
216
|
if (!value || value === "" || filter.columnId === "") continue;
|
|
198
|
-
if (filter.type === "enum" && Array.isArray(value) && value.length === 0) continue;
|
|
217
|
+
if ((filter.type === "enum" || filter.type === "jsonArray") && Array.isArray(value) && value.length === 0) continue;
|
|
199
218
|
const actualMethod = isPeriodColumn ? "intersect" : filter.method.value;
|
|
200
219
|
const result = {
|
|
201
220
|
columnId: actualColumnId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterTransformers.js","names":["DateTime","CalendarDate"],"sources":["../../../../src/modules/table/filterTransformers.ts"],"sourcesContent":["import type { DateValue, RangeValue, SharedSelection } from \"@heroui/react\";\r\nimport { CalendarDate, getLocalTimeZone, today } from \"@internationalized/date\";\r\nimport type { QueryFilter, QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport type { ColumnDataType, FilterMethod } from \"@m5kdev/commons/modules/table/filter.types\";\r\nimport { DateTime } from \"luxon\";\r\n\r\nexport type FilterValue =\r\n | string\r\n | number\r\n | string[]\r\n | DateValue\r\n | RangeValue<DateValue>\r\n | boolean\r\n | SharedSelection\r\n | null;\r\n\r\nexport interface HeroUIFilter {\r\n columnId: string;\r\n type: ColumnDataType | null;\r\n value: FilterValue;\r\n method: FilterMethod | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n}\r\n\r\n/**\r\n * Convert CalendarDate to UTC ISO string at midnight UTC\r\n */\r\nexport const calendarDateToUTC = (date: CalendarDate): string => {\r\n return DateTime.utc(date.year, date.month, date.day).toISO() ?? \"\";\r\n};\r\n\r\n/**\r\n * Convert CalendarDate to end of day UTC ISO string\r\n */\r\nexport const calendarDateToEndOfDayUTC = (date: CalendarDate): string => {\r\n return DateTime.utc(date.year, date.month, date.day).endOf(\"day\").toISO() ?? \"\";\r\n};\r\n\r\n/**\r\n * Parse UTC ISO string to CalendarDate (preserves UTC date, no timezone shift)\r\n */\r\nconst parseUTCToCalendarDate = (isoString: string): CalendarDate | null => {\r\n try {\r\n const dt = DateTime.fromISO(isoString, { zone: \"utc\" });\r\n if (!dt.isValid) return null;\r\n return new CalendarDate(dt.year, dt.month, dt.day);\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Convert any date filter method from URL to a RangeValue for DateRangePicker\r\n * Handles: on, before, after, between, intersect\r\n * Parses UTC ISO strings as UTC to avoid timezone shifts\r\n */\r\nexport const dateFilterToRangeValue = (\r\n filters: QueryFilters | undefined,\r\n columnId: string\r\n): RangeValue<DateValue> | null => {\r\n if (!filters) return null;\r\n\r\n const filter = filters.find((f) => f.columnId === columnId);\r\n if (!filter || filter.type !== \"date\") return null;\r\n\r\n const todayDate = today(getLocalTimeZone());\r\n const epochStart = new CalendarDate(1970, 1, 1);\r\n\r\n try {\r\n switch (filter.method) {\r\n case \"on\": {\r\n // Same day range\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: day as unknown as DateValue,\r\n end: day as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"before\": {\r\n // [epochStart, selectedDay]\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: epochStart as unknown as DateValue,\r\n end: day as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"after\": {\r\n // [selectedDay, today]\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: day as unknown as DateValue,\r\n end: todayDate as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"between\":\r\n case \"intersect\": {\r\n // [value, valueTo]\r\n if (typeof filter.value !== \"string\" || !filter.value || !filter.valueTo) return null;\r\n const startDate = parseUTCToCalendarDate(filter.value);\r\n const endDate = parseUTCToCalendarDate(filter.valueTo);\r\n if (!startDate || !endDate) return null;\r\n return {\r\n start: startDate as unknown as DateValue,\r\n end: endDate as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n default:\r\n return null;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Transform filters from backend format (QueryFilter[]) to HeroUI format (HeroUIFilter[])\r\n * Used when loading filters from URL/backend to populate HeroUI components\r\n */\r\nexport const transformFiltersToHeroUI = (\r\n filtersToTransform: QueryFilters,\r\n columnsMap: Map<\r\n string,\r\n {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }\r\n >,\r\n filterMethods: Record<ColumnDataType, FilterMethod[]>\r\n): HeroUIFilter[] => {\r\n return filtersToTransform.map((filter) => {\r\n let value: FilterValue = null;\r\n let method: FilterMethod | null = null;\r\n let columnId = filter.columnId;\r\n\r\n // Check if this intersect filter should map to Period pseudo-column\r\n if (filter.type === \"date\" && filter.method === \"intersect\" && filter.endColumnId) {\r\n const periodColumnId = `${filter.columnId}__period`;\r\n const periodColumn = columnsMap.get(periodColumnId);\r\n if (periodColumn) {\r\n // Map to Period pseudo-column\r\n columnId = periodColumnId;\r\n }\r\n }\r\n\r\n // Find the method object from the methods configuration\r\n if (filter.type) {\r\n const availableMethods = filterMethods[filter.type as ColumnDataType];\r\n const methodObj = availableMethods?.find((m: FilterMethod) => m.value === filter.method);\r\n if (methodObj) {\r\n method = methodObj;\r\n } else if (filter.method === \"isEmpty\" || filter.method === \"isNotEmpty\") {\r\n // Handle isEmpty/isNotEmpty even if not in the provided method list\r\n method = {\r\n value: filter.method,\r\n label: filter.method === \"isEmpty\" ? \"Is Empty\" : \"Is Not Empty\",\r\n component: null,\r\n };\r\n }\r\n }\r\n\r\n // Transform value based on type\r\n switch (filter.type) {\r\n case \"string\":\r\n value = filter.value as string;\r\n break;\r\n case \"number\":\r\n value = filter.value as number;\r\n break;\r\n case \"date\":\r\n // Use the shared helper for range conversion, or parse single dates as UTC\r\n if (filter.method === \"between\" || filter.method === \"intersect\") {\r\n // For range methods, use the helper function\r\n const range = dateFilterToRangeValue([filter], filter.columnId);\r\n value = range;\r\n } else {\r\n // Single date value: parse UTC ISO string and extract UTC calendar date\r\n if (typeof filter.value === \"string\" && filter.value) {\r\n const day = parseUTCToCalendarDate(filter.value);\r\n value = day ? (day as unknown as DateValue) : null;\r\n } else {\r\n value = null;\r\n }\r\n }\r\n break;\r\n case \"boolean\":\r\n value = filter.value as boolean;\r\n break;\r\n case \"enum\":\r\n if (filter.method === \"oneOf\" && Array.isArray(filter.value)) {\r\n // Multi-select: array of strings to SharedSelection (Set)\r\n value = new Set(filter.value) as SharedSelection;\r\n } else {\r\n // Single select: string to SharedSelection with currentKey\r\n const selection = new Set([filter.value as string]) as SharedSelection;\r\n // Set currentKey property\r\n Object.defineProperty(selection, \"currentKey\", {\r\n value: filter.value as string,\r\n writable: true,\r\n enumerable: false,\r\n configurable: true,\r\n });\r\n value = selection;\r\n }\r\n break;\r\n default:\r\n value = filter.value;\r\n }\r\n\r\n const column = columnsMap.get(columnId);\r\n return {\r\n columnId,\r\n type: filter.type,\r\n value,\r\n method,\r\n options: column?.options ?? null,\r\n endColumnId: column?.endColumnId ?? null,\r\n periodStartColumnId: column?.periodStartColumnId ?? null,\r\n periodEndColumnId: column?.periodEndColumnId ?? null,\r\n };\r\n });\r\n};\r\n\r\n/**\r\n * Transform filters from HeroUI format (HeroUIFilter[]) to backend format (QueryFilter[])\r\n * Used when applying filters to send to backend/URL\r\n */\r\nexport const transformFiltersFromHeroUI = (filters: HeroUIFilter[]): QueryFilters => {\r\n const filtersToApply: QueryFilters = [];\r\n\r\n for (const filter of filters) {\r\n let value: FilterValue | undefined;\r\n let valueTo: FilterValue | undefined;\r\n\r\n // Handle isEmpty/isNotEmpty methods - they don't need a value\r\n if (filter.method?.value === \"isEmpty\" || filter.method?.value === \"isNotEmpty\") {\r\n if (filter.columnId === \"\") continue;\r\n\r\n const result: QueryFilter = {\r\n columnId: filter.columnId,\r\n type: filter.type as ColumnDataType,\r\n method: filter.method.value,\r\n value: \"\",\r\n };\r\n filtersToApply.push(result);\r\n continue;\r\n }\r\n\r\n // Handle Period pseudo-column: map to intersect on real columns\r\n const isPeriodColumn = filter.columnId.endsWith(\"__period\");\r\n const actualColumnId =\r\n isPeriodColumn && filter.periodStartColumnId ? filter.periodStartColumnId : filter.columnId;\r\n const actualEndColumnId =\r\n isPeriodColumn && filter.periodEndColumnId ? filter.periodEndColumnId : filter.endColumnId;\r\n\r\n switch (filter.type) {\r\n case \"date\":\r\n if (\r\n filter.method?.value === \"between\" ||\r\n filter.method?.value === \"intersect\" ||\r\n isPeriodColumn\r\n ) {\r\n const range = filter.value as RangeValue<DateValue>;\r\n if (range?.start && range?.end) {\r\n value = calendarDateToUTC(range.start as unknown as CalendarDate);\r\n valueTo = calendarDateToUTC(range.end as unknown as CalendarDate);\r\n }\r\n } else {\r\n const dateValue = filter.value as unknown as CalendarDate;\r\n if (dateValue?.year) {\r\n value = calendarDateToUTC(dateValue);\r\n }\r\n }\r\n break;\r\n case \"enum\": {\r\n const selection = filter.value as SharedSelection;\r\n if (selection) {\r\n value =\r\n filter.method?.value === \"oneOf\"\r\n ? Array.from(selection).map(String)\r\n : String(selection.currentKey);\r\n }\r\n break;\r\n }\r\n default:\r\n value = filter.value;\r\n }\r\n\r\n // Skip filters without valid values\r\n if (!value || value === \"\" || filter.columnId === \"\") continue;\r\n if (filter.type === \"enum\" && Array.isArray(value) && value.length === 0) continue;\r\n\r\n // For Period columns, always use intersect method\r\n const actualMethod = isPeriodColumn ? \"intersect\" : (filter.method as FilterMethod).value;\r\n\r\n const result: QueryFilter = {\r\n columnId: actualColumnId,\r\n type: filter.type as ColumnDataType,\r\n method: actualMethod,\r\n value: value as string | number | boolean | string[],\r\n ...(valueTo && { valueTo: valueTo as string }),\r\n ...(actualMethod === \"intersect\" && actualEndColumnId\r\n ? { endColumnId: actualEndColumnId }\r\n : {}),\r\n };\r\n filtersToApply.push(result);\r\n }\r\n\r\n return filtersToApply;\r\n};\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filterTransformers.js","names":["DateTime","CalendarDate"],"sources":["../../../../src/modules/table/filterTransformers.ts"],"sourcesContent":["import type { DateValue, RangeValue, SharedSelection } from \"@heroui/react\";\r\nimport { CalendarDate, getLocalTimeZone, today } from \"@internationalized/date\";\r\nimport type { QueryFilter, QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport type { ColumnDataType, FilterMethod } from \"@m5kdev/commons/modules/table/filter.types\";\r\nimport { DateTime } from \"luxon\";\r\n\r\nexport type FilterValue =\r\n | string\r\n | number\r\n | string[]\r\n | DateValue\r\n | RangeValue<DateValue>\r\n | boolean\r\n | SharedSelection\r\n | null;\r\n\r\nexport interface HeroUIFilter {\r\n columnId: string;\r\n type: ColumnDataType | null;\r\n value: FilterValue;\r\n method: FilterMethod | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n}\r\n\r\n/**\r\n * Convert CalendarDate to UTC ISO string at midnight UTC\r\n */\r\nexport const calendarDateToUTC = (date: CalendarDate): string => {\r\n return DateTime.utc(date.year, date.month, date.day).toISO() ?? \"\";\r\n};\r\n\r\n/**\r\n * Convert CalendarDate to end of day UTC ISO string\r\n */\r\nexport const calendarDateToEndOfDayUTC = (date: CalendarDate): string => {\r\n return DateTime.utc(date.year, date.month, date.day).endOf(\"day\").toISO() ?? \"\";\r\n};\r\n\r\n/**\r\n * Parse UTC ISO string to CalendarDate (preserves UTC date, no timezone shift)\r\n */\r\nconst parseUTCToCalendarDate = (isoString: string): CalendarDate | null => {\r\n try {\r\n const dt = DateTime.fromISO(isoString, { zone: \"utc\" });\r\n if (!dt.isValid) return null;\r\n return new CalendarDate(dt.year, dt.month, dt.day);\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Convert any date filter method from URL to a RangeValue for DateRangePicker\r\n * Handles: on, before, after, between, intersect\r\n * Parses UTC ISO strings as UTC to avoid timezone shifts\r\n */\r\nexport const dateFilterToRangeValue = (\r\n filters: QueryFilters | undefined,\r\n columnId: string\r\n): RangeValue<DateValue> | null => {\r\n if (!filters) return null;\r\n\r\n const filter = filters.find((f) => f.columnId === columnId);\r\n if (!filter || filter.type !== \"date\") return null;\r\n\r\n const todayDate = today(getLocalTimeZone());\r\n const epochStart = new CalendarDate(1970, 1, 1);\r\n\r\n try {\r\n switch (filter.method) {\r\n case \"on\": {\r\n // Same day range\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: day as unknown as DateValue,\r\n end: day as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"before\": {\r\n // [epochStart, selectedDay]\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: epochStart as unknown as DateValue,\r\n end: day as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"after\": {\r\n // [selectedDay, today]\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: day as unknown as DateValue,\r\n end: todayDate as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"between\":\r\n case \"intersect\": {\r\n // [value, valueTo]\r\n if (typeof filter.value !== \"string\" || !filter.value || !filter.valueTo) return null;\r\n const startDate = parseUTCToCalendarDate(filter.value);\r\n const endDate = parseUTCToCalendarDate(filter.valueTo);\r\n if (!startDate || !endDate) return null;\r\n return {\r\n start: startDate as unknown as DateValue,\r\n end: endDate as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n default:\r\n return null;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Transform filters from backend format (QueryFilter[]) to HeroUI format (HeroUIFilter[])\r\n * Used when loading filters from URL/backend to populate HeroUI components\r\n */\r\nexport const transformFiltersToHeroUI = (\r\n filtersToTransform: QueryFilters,\r\n columnsMap: Map<\r\n string,\r\n {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }\r\n >,\r\n filterMethods: Record<ColumnDataType, FilterMethod[]>\r\n): HeroUIFilter[] => {\r\n return filtersToTransform.map((filter) => {\r\n let value: FilterValue = null;\r\n let method: FilterMethod | null = null;\r\n let columnId = filter.columnId;\r\n\r\n // Check if this intersect filter should map to Period pseudo-column\r\n if (filter.type === \"date\" && filter.method === \"intersect\" && filter.endColumnId) {\r\n const periodColumnId = `${filter.columnId}__period`;\r\n const periodColumn = columnsMap.get(periodColumnId);\r\n if (periodColumn) {\r\n // Map to Period pseudo-column\r\n columnId = periodColumnId;\r\n }\r\n }\r\n\r\n // Find the method object from the methods configuration\r\n if (filter.type) {\r\n const availableMethods = filterMethods[filter.type as ColumnDataType];\r\n const methodObj = availableMethods?.find((m: FilterMethod) => m.value === filter.method);\r\n if (methodObj) {\r\n method = methodObj;\r\n } else if (filter.method === \"isEmpty\" || filter.method === \"isNotEmpty\") {\r\n // Handle isEmpty/isNotEmpty even if not in the provided method list\r\n method = {\r\n value: filter.method,\r\n label: filter.method === \"isEmpty\" ? \"Is Empty\" : \"Is Not Empty\",\r\n component: null,\r\n };\r\n }\r\n }\r\n\r\n // Transform value based on type\r\n switch (filter.type) {\r\n case \"string\":\r\n value = filter.value as string;\r\n break;\r\n case \"number\":\r\n value = filter.value as number;\r\n break;\r\n case \"date\":\r\n // Use the shared helper for range conversion, or parse single dates as UTC\r\n if (filter.method === \"between\" || filter.method === \"intersect\") {\r\n // For range methods, use the helper function\r\n const range = dateFilterToRangeValue([filter], filter.columnId);\r\n value = range;\r\n } else {\r\n // Single date value: parse UTC ISO string and extract UTC calendar date\r\n if (typeof filter.value === \"string\" && filter.value) {\r\n const day = parseUTCToCalendarDate(filter.value);\r\n value = day ? (day as unknown as DateValue) : null;\r\n } else {\r\n value = null;\r\n }\r\n }\r\n break;\r\n case \"boolean\":\r\n value = filter.value as boolean;\r\n break;\r\n case \"enum\":\r\n if (filter.method === \"oneOf\" && Array.isArray(filter.value)) {\r\n // Multi-select: array of strings to SharedSelection (Set)\r\n value = new Set(filter.value) as SharedSelection;\r\n } else {\r\n // Single select: string to SharedSelection with currentKey\r\n const selection = new Set([filter.value as string]) as SharedSelection;\r\n // Set currentKey property\r\n Object.defineProperty(selection, \"currentKey\", {\r\n value: filter.value as string,\r\n writable: true,\r\n enumerable: false,\r\n configurable: true,\r\n });\r\n value = selection;\r\n }\r\n break;\r\n case \"jsonArray\":\r\n if (filter.method === \"oneOf\" && Array.isArray(filter.value)) {\r\n value = new Set(filter.value) as SharedSelection;\r\n } else if (Array.isArray(filter.value) && filter.value.length > 0) {\r\n const first = filter.value[0] as string;\r\n const selection = new Set([first]) as SharedSelection;\r\n Object.defineProperty(selection, \"currentKey\", {\r\n value: first,\r\n writable: true,\r\n enumerable: false,\r\n configurable: true,\r\n });\r\n value = selection;\r\n } else {\r\n value = filter.value;\r\n }\r\n break;\r\n default:\r\n value = filter.value;\r\n }\r\n\r\n const column = columnsMap.get(columnId);\r\n return {\r\n columnId,\r\n type: filter.type,\r\n value,\r\n method,\r\n options: column?.options ?? null,\r\n endColumnId: column?.endColumnId ?? null,\r\n periodStartColumnId: column?.periodStartColumnId ?? null,\r\n periodEndColumnId: column?.periodEndColumnId ?? null,\r\n };\r\n });\r\n};\r\n\r\n/**\r\n * Transform filters from HeroUI format (HeroUIFilter[]) to backend format (QueryFilter[])\r\n * Used when applying filters to send to backend/URL\r\n */\r\nexport const transformFiltersFromHeroUI = (filters: HeroUIFilter[]): QueryFilters => {\r\n const filtersToApply: QueryFilters = [];\r\n\r\n for (const filter of filters) {\r\n let value: FilterValue | undefined;\r\n let valueTo: FilterValue | undefined;\r\n\r\n // Handle isEmpty/isNotEmpty methods - they don't need a value\r\n if (filter.method?.value === \"isEmpty\" || filter.method?.value === \"isNotEmpty\") {\r\n if (filter.columnId === \"\") continue;\r\n\r\n const result: QueryFilter = {\r\n columnId: filter.columnId,\r\n type: filter.type as ColumnDataType,\r\n method: filter.method.value,\r\n value: \"\",\r\n };\r\n filtersToApply.push(result);\r\n continue;\r\n }\r\n\r\n // Handle Period pseudo-column: map to intersect on real columns\r\n const isPeriodColumn = filter.columnId.endsWith(\"__period\");\r\n const actualColumnId =\r\n isPeriodColumn && filter.periodStartColumnId ? filter.periodStartColumnId : filter.columnId;\r\n const actualEndColumnId =\r\n isPeriodColumn && filter.periodEndColumnId ? filter.periodEndColumnId : filter.endColumnId;\r\n\r\n switch (filter.type) {\r\n case \"date\":\r\n if (\r\n filter.method?.value === \"between\" ||\r\n filter.method?.value === \"intersect\" ||\r\n isPeriodColumn\r\n ) {\r\n const range = filter.value as RangeValue<DateValue>;\r\n if (range?.start && range?.end) {\r\n value = calendarDateToUTC(range.start as unknown as CalendarDate);\r\n valueTo = calendarDateToUTC(range.end as unknown as CalendarDate);\r\n }\r\n } else {\r\n const dateValue = filter.value as unknown as CalendarDate;\r\n if (dateValue?.year) {\r\n value = calendarDateToUTC(dateValue);\r\n }\r\n }\r\n break;\r\n case \"enum\": {\r\n const selection = filter.value as SharedSelection;\r\n if (selection) {\r\n value =\r\n filter.method?.value === \"oneOf\"\r\n ? Array.from(selection).map(String)\r\n : String(selection.currentKey);\r\n }\r\n break;\r\n }\r\n case \"jsonArray\": {\r\n const selection = filter.value as SharedSelection;\r\n if (selection) {\r\n value =\r\n filter.method?.value === \"oneOf\"\r\n ? Array.from(selection).map(String)\r\n : [String(selection.currentKey)];\r\n }\r\n break;\r\n }\r\n default:\r\n value = filter.value;\r\n }\r\n\r\n // Skip filters without valid values\r\n if (!value || value === \"\" || filter.columnId === \"\") continue;\r\n if (\r\n (filter.type === \"enum\" || filter.type === \"jsonArray\") &&\r\n Array.isArray(value) &&\r\n value.length === 0\r\n ) {\r\n continue;\r\n }\r\n\r\n // For Period columns, always use intersect method\r\n const actualMethod = isPeriodColumn ? \"intersect\" : (filter.method as FilterMethod).value;\r\n\r\n const result: QueryFilter = {\r\n columnId: actualColumnId,\r\n type: filter.type as ColumnDataType,\r\n method: actualMethod,\r\n value: value as string | number | boolean | string[],\r\n ...(valueTo && { valueTo: valueTo as string }),\r\n ...(actualMethod === \"intersect\" && actualEndColumnId\r\n ? { endColumnId: actualEndColumnId }\r\n : {}),\r\n };\r\n filtersToApply.push(result);\r\n }\r\n\r\n return filtersToApply;\r\n};\r\n"],"mappings":"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"}
|
|
@@ -134,6 +134,20 @@ const transformFiltersToHeroUI = (filtersToTransform, columnsMap, filterMethods)
|
|
|
134
134
|
value = selection;
|
|
135
135
|
}
|
|
136
136
|
break;
|
|
137
|
+
case "jsonArray":
|
|
138
|
+
if (filter.method === "oneOf" && Array.isArray(filter.value)) value = new Set(filter.value);
|
|
139
|
+
else if (Array.isArray(filter.value) && filter.value.length > 0) {
|
|
140
|
+
const first = filter.value[0];
|
|
141
|
+
const selection = new Set([first]);
|
|
142
|
+
Object.defineProperty(selection, "currentKey", {
|
|
143
|
+
value: first,
|
|
144
|
+
writable: true,
|
|
145
|
+
enumerable: false,
|
|
146
|
+
configurable: true
|
|
147
|
+
});
|
|
148
|
+
value = selection;
|
|
149
|
+
} else value = filter.value;
|
|
150
|
+
break;
|
|
137
151
|
default: value = filter.value;
|
|
138
152
|
}
|
|
139
153
|
const column = columnsMap.get(columnId);
|
|
@@ -190,10 +204,15 @@ const transformFiltersFromHeroUI = (filters) => {
|
|
|
190
204
|
if (selection) value = filter.method?.value === "oneOf" ? Array.from(selection).map(String) : String(selection.currentKey);
|
|
191
205
|
break;
|
|
192
206
|
}
|
|
207
|
+
case "jsonArray": {
|
|
208
|
+
const selection = filter.value;
|
|
209
|
+
if (selection) value = filter.method?.value === "oneOf" ? Array.from(selection).map(String) : [String(selection.currentKey)];
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
193
212
|
default: value = filter.value;
|
|
194
213
|
}
|
|
195
214
|
if (!value || value === "" || filter.columnId === "") continue;
|
|
196
|
-
if (filter.type === "enum" && Array.isArray(value) && value.length === 0) continue;
|
|
215
|
+
if ((filter.type === "enum" || filter.type === "jsonArray") && Array.isArray(value) && value.length === 0) continue;
|
|
197
216
|
const actualMethod = isPeriodColumn ? "intersect" : filter.method.value;
|
|
198
217
|
const result = {
|
|
199
218
|
columnId: actualColumnId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterTransformers.mjs","names":[],"sources":["../../../../src/modules/table/filterTransformers.ts"],"sourcesContent":["import type { DateValue, RangeValue, SharedSelection } from \"@heroui/react\";\r\nimport { CalendarDate, getLocalTimeZone, today } from \"@internationalized/date\";\r\nimport type { QueryFilter, QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport type { ColumnDataType, FilterMethod } from \"@m5kdev/commons/modules/table/filter.types\";\r\nimport { DateTime } from \"luxon\";\r\n\r\nexport type FilterValue =\r\n | string\r\n | number\r\n | string[]\r\n | DateValue\r\n | RangeValue<DateValue>\r\n | boolean\r\n | SharedSelection\r\n | null;\r\n\r\nexport interface HeroUIFilter {\r\n columnId: string;\r\n type: ColumnDataType | null;\r\n value: FilterValue;\r\n method: FilterMethod | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n}\r\n\r\n/**\r\n * Convert CalendarDate to UTC ISO string at midnight UTC\r\n */\r\nexport const calendarDateToUTC = (date: CalendarDate): string => {\r\n return DateTime.utc(date.year, date.month, date.day).toISO() ?? \"\";\r\n};\r\n\r\n/**\r\n * Convert CalendarDate to end of day UTC ISO string\r\n */\r\nexport const calendarDateToEndOfDayUTC = (date: CalendarDate): string => {\r\n return DateTime.utc(date.year, date.month, date.day).endOf(\"day\").toISO() ?? \"\";\r\n};\r\n\r\n/**\r\n * Parse UTC ISO string to CalendarDate (preserves UTC date, no timezone shift)\r\n */\r\nconst parseUTCToCalendarDate = (isoString: string): CalendarDate | null => {\r\n try {\r\n const dt = DateTime.fromISO(isoString, { zone: \"utc\" });\r\n if (!dt.isValid) return null;\r\n return new CalendarDate(dt.year, dt.month, dt.day);\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Convert any date filter method from URL to a RangeValue for DateRangePicker\r\n * Handles: on, before, after, between, intersect\r\n * Parses UTC ISO strings as UTC to avoid timezone shifts\r\n */\r\nexport const dateFilterToRangeValue = (\r\n filters: QueryFilters | undefined,\r\n columnId: string\r\n): RangeValue<DateValue> | null => {\r\n if (!filters) return null;\r\n\r\n const filter = filters.find((f) => f.columnId === columnId);\r\n if (!filter || filter.type !== \"date\") return null;\r\n\r\n const todayDate = today(getLocalTimeZone());\r\n const epochStart = new CalendarDate(1970, 1, 1);\r\n\r\n try {\r\n switch (filter.method) {\r\n case \"on\": {\r\n // Same day range\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: day as unknown as DateValue,\r\n end: day as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"before\": {\r\n // [epochStart, selectedDay]\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: epochStart as unknown as DateValue,\r\n end: day as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"after\": {\r\n // [selectedDay, today]\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: day as unknown as DateValue,\r\n end: todayDate as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"between\":\r\n case \"intersect\": {\r\n // [value, valueTo]\r\n if (typeof filter.value !== \"string\" || !filter.value || !filter.valueTo) return null;\r\n const startDate = parseUTCToCalendarDate(filter.value);\r\n const endDate = parseUTCToCalendarDate(filter.valueTo);\r\n if (!startDate || !endDate) return null;\r\n return {\r\n start: startDate as unknown as DateValue,\r\n end: endDate as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n default:\r\n return null;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Transform filters from backend format (QueryFilter[]) to HeroUI format (HeroUIFilter[])\r\n * Used when loading filters from URL/backend to populate HeroUI components\r\n */\r\nexport const transformFiltersToHeroUI = (\r\n filtersToTransform: QueryFilters,\r\n columnsMap: Map<\r\n string,\r\n {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }\r\n >,\r\n filterMethods: Record<ColumnDataType, FilterMethod[]>\r\n): HeroUIFilter[] => {\r\n return filtersToTransform.map((filter) => {\r\n let value: FilterValue = null;\r\n let method: FilterMethod | null = null;\r\n let columnId = filter.columnId;\r\n\r\n // Check if this intersect filter should map to Period pseudo-column\r\n if (filter.type === \"date\" && filter.method === \"intersect\" && filter.endColumnId) {\r\n const periodColumnId = `${filter.columnId}__period`;\r\n const periodColumn = columnsMap.get(periodColumnId);\r\n if (periodColumn) {\r\n // Map to Period pseudo-column\r\n columnId = periodColumnId;\r\n }\r\n }\r\n\r\n // Find the method object from the methods configuration\r\n if (filter.type) {\r\n const availableMethods = filterMethods[filter.type as ColumnDataType];\r\n const methodObj = availableMethods?.find((m: FilterMethod) => m.value === filter.method);\r\n if (methodObj) {\r\n method = methodObj;\r\n } else if (filter.method === \"isEmpty\" || filter.method === \"isNotEmpty\") {\r\n // Handle isEmpty/isNotEmpty even if not in the provided method list\r\n method = {\r\n value: filter.method,\r\n label: filter.method === \"isEmpty\" ? \"Is Empty\" : \"Is Not Empty\",\r\n component: null,\r\n };\r\n }\r\n }\r\n\r\n // Transform value based on type\r\n switch (filter.type) {\r\n case \"string\":\r\n value = filter.value as string;\r\n break;\r\n case \"number\":\r\n value = filter.value as number;\r\n break;\r\n case \"date\":\r\n // Use the shared helper for range conversion, or parse single dates as UTC\r\n if (filter.method === \"between\" || filter.method === \"intersect\") {\r\n // For range methods, use the helper function\r\n const range = dateFilterToRangeValue([filter], filter.columnId);\r\n value = range;\r\n } else {\r\n // Single date value: parse UTC ISO string and extract UTC calendar date\r\n if (typeof filter.value === \"string\" && filter.value) {\r\n const day = parseUTCToCalendarDate(filter.value);\r\n value = day ? (day as unknown as DateValue) : null;\r\n } else {\r\n value = null;\r\n }\r\n }\r\n break;\r\n case \"boolean\":\r\n value = filter.value as boolean;\r\n break;\r\n case \"enum\":\r\n if (filter.method === \"oneOf\" && Array.isArray(filter.value)) {\r\n // Multi-select: array of strings to SharedSelection (Set)\r\n value = new Set(filter.value) as SharedSelection;\r\n } else {\r\n // Single select: string to SharedSelection with currentKey\r\n const selection = new Set([filter.value as string]) as SharedSelection;\r\n // Set currentKey property\r\n Object.defineProperty(selection, \"currentKey\", {\r\n value: filter.value as string,\r\n writable: true,\r\n enumerable: false,\r\n configurable: true,\r\n });\r\n value = selection;\r\n }\r\n break;\r\n default:\r\n value = filter.value;\r\n }\r\n\r\n const column = columnsMap.get(columnId);\r\n return {\r\n columnId,\r\n type: filter.type,\r\n value,\r\n method,\r\n options: column?.options ?? null,\r\n endColumnId: column?.endColumnId ?? null,\r\n periodStartColumnId: column?.periodStartColumnId ?? null,\r\n periodEndColumnId: column?.periodEndColumnId ?? null,\r\n };\r\n });\r\n};\r\n\r\n/**\r\n * Transform filters from HeroUI format (HeroUIFilter[]) to backend format (QueryFilter[])\r\n * Used when applying filters to send to backend/URL\r\n */\r\nexport const transformFiltersFromHeroUI = (filters: HeroUIFilter[]): QueryFilters => {\r\n const filtersToApply: QueryFilters = [];\r\n\r\n for (const filter of filters) {\r\n let value: FilterValue | undefined;\r\n let valueTo: FilterValue | undefined;\r\n\r\n // Handle isEmpty/isNotEmpty methods - they don't need a value\r\n if (filter.method?.value === \"isEmpty\" || filter.method?.value === \"isNotEmpty\") {\r\n if (filter.columnId === \"\") continue;\r\n\r\n const result: QueryFilter = {\r\n columnId: filter.columnId,\r\n type: filter.type as ColumnDataType,\r\n method: filter.method.value,\r\n value: \"\",\r\n };\r\n filtersToApply.push(result);\r\n continue;\r\n }\r\n\r\n // Handle Period pseudo-column: map to intersect on real columns\r\n const isPeriodColumn = filter.columnId.endsWith(\"__period\");\r\n const actualColumnId =\r\n isPeriodColumn && filter.periodStartColumnId ? filter.periodStartColumnId : filter.columnId;\r\n const actualEndColumnId =\r\n isPeriodColumn && filter.periodEndColumnId ? filter.periodEndColumnId : filter.endColumnId;\r\n\r\n switch (filter.type) {\r\n case \"date\":\r\n if (\r\n filter.method?.value === \"between\" ||\r\n filter.method?.value === \"intersect\" ||\r\n isPeriodColumn\r\n ) {\r\n const range = filter.value as RangeValue<DateValue>;\r\n if (range?.start && range?.end) {\r\n value = calendarDateToUTC(range.start as unknown as CalendarDate);\r\n valueTo = calendarDateToUTC(range.end as unknown as CalendarDate);\r\n }\r\n } else {\r\n const dateValue = filter.value as unknown as CalendarDate;\r\n if (dateValue?.year) {\r\n value = calendarDateToUTC(dateValue);\r\n }\r\n }\r\n break;\r\n case \"enum\": {\r\n const selection = filter.value as SharedSelection;\r\n if (selection) {\r\n value =\r\n filter.method?.value === \"oneOf\"\r\n ? Array.from(selection).map(String)\r\n : String(selection.currentKey);\r\n }\r\n break;\r\n }\r\n default:\r\n value = filter.value;\r\n }\r\n\r\n // Skip filters without valid values\r\n if (!value || value === \"\" || filter.columnId === \"\") continue;\r\n if (filter.type === \"enum\" && Array.isArray(value) && value.length === 0) continue;\r\n\r\n // For Period columns, always use intersect method\r\n const actualMethod = isPeriodColumn ? \"intersect\" : (filter.method as FilterMethod).value;\r\n\r\n const result: QueryFilter = {\r\n columnId: actualColumnId,\r\n type: filter.type as ColumnDataType,\r\n method: actualMethod,\r\n value: value as string | number | boolean | string[],\r\n ...(valueTo && { valueTo: valueTo as string }),\r\n ...(actualMethod === \"intersect\" && actualEndColumnId\r\n ? { endColumnId: actualEndColumnId }\r\n : {}),\r\n };\r\n filtersToApply.push(result);\r\n }\r\n\r\n return filtersToApply;\r\n};\r\n"],"mappings":";;;;;;AA8BA,MAAa,qBAAqB,SAA+B;AAC/D,QAAO,SAAS,IAAI,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI;;;;;AAMlE,MAAa,6BAA6B,SAA+B;AACvE,QAAO,SAAS,IAAI,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,CAAC,MAAM,MAAM,CAAC,OAAO,IAAI;;;;;AAM/E,MAAM,0BAA0B,cAA2C;AACzE,KAAI;EACF,MAAM,KAAK,SAAS,QAAQ,WAAW,EAAE,MAAM,OAAO,CAAC;AACvD,MAAI,CAAC,GAAG,QAAS,QAAO;AACxB,SAAO,IAAI,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI;SAC5C;AACN,SAAO;;;;;;;;AASX,MAAa,0BACX,SACA,aACiC;AACjC,KAAI,CAAC,QAAS,QAAO;CAErB,MAAM,SAAS,QAAQ,MAAM,MAAM,EAAE,aAAa,SAAS;AAC3D,KAAI,CAAC,UAAU,OAAO,SAAS,OAAQ,QAAO;CAE9C,MAAM,YAAY,MAAM,kBAAkB,CAAC;CAC3C,MAAM,aAAa,IAAI,aAAa,MAAM,GAAG,EAAE;AAE/C,KAAI;AACF,UAAQ,OAAO,QAAf;GACE,KAAK,MAAM;AAET,QAAI,OAAO,OAAO,UAAU,YAAY,CAAC,OAAO,MAAO,QAAO;IAC9D,MAAM,MAAM,uBAAuB,OAAO,MAAM;AAChD,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO;KACL,OAAO;KACP,KAAK;KACN;;GAEH,KAAK,UAAU;AAEb,QAAI,OAAO,OAAO,UAAU,YAAY,CAAC,OAAO,MAAO,QAAO;IAC9D,MAAM,MAAM,uBAAuB,OAAO,MAAM;AAChD,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO;KACL,OAAO;KACP,KAAK;KACN;;GAEH,KAAK,SAAS;AAEZ,QAAI,OAAO,OAAO,UAAU,YAAY,CAAC,OAAO,MAAO,QAAO;IAC9D,MAAM,MAAM,uBAAuB,OAAO,MAAM;AAChD,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO;KACL,OAAO;KACP,KAAK;KACN;;GAEH,KAAK;GACL,KAAK,aAAa;AAEhB,QAAI,OAAO,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,CAAC,OAAO,QAAS,QAAO;IACjF,MAAM,YAAY,uBAAuB,OAAO,MAAM;IACtD,MAAM,UAAU,uBAAuB,OAAO,QAAQ;AACtD,QAAI,CAAC,aAAa,CAAC,QAAS,QAAO;AACnC,WAAO;KACL,OAAO;KACP,KAAK;KACN;;GAEH,QACE,QAAO;;SAEL;AACN,SAAO;;;;;;;AAQX,MAAa,4BACX,oBACA,YAYA,kBACmB;AACnB,QAAO,mBAAmB,KAAK,WAAW;EACxC,IAAI,QAAqB;EACzB,IAAI,SAA8B;EAClC,IAAI,WAAW,OAAO;AAGtB,MAAI,OAAO,SAAS,UAAU,OAAO,WAAW,eAAe,OAAO,aAAa;GACjF,MAAM,iBAAiB,GAAG,OAAO,SAAS;AAE1C,OADqB,WAAW,IAAI,eAAe,CAGjD,YAAW;;AAKf,MAAI,OAAO,MAAM;GAEf,MAAM,YADmB,cAAc,OAAO,OACV,MAAM,MAAoB,EAAE,UAAU,OAAO,OAAO;AACxF,OAAI,UACF,UAAS;YACA,OAAO,WAAW,aAAa,OAAO,WAAW,aAE1D,UAAS;IACP,OAAO,OAAO;IACd,OAAO,OAAO,WAAW,YAAY,aAAa;IAClD,WAAW;IACZ;;AAKL,UAAQ,OAAO,MAAf;GACE,KAAK;AACH,YAAQ,OAAO;AACf;GACF,KAAK;AACH,YAAQ,OAAO;AACf;GACF,KAAK;AAEH,QAAI,OAAO,WAAW,aAAa,OAAO,WAAW,YAGnD,SADc,uBAAuB,CAAC,OAAO,EAAE,OAAO,SAAS;aAI3D,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO;KACpD,MAAM,MAAM,uBAAuB,OAAO,MAAM;AAChD,aAAQ,MAAO,MAA+B;UAE9C,SAAQ;AAGZ;GACF,KAAK;AACH,YAAQ,OAAO;AACf;GACF,KAAK;AACH,QAAI,OAAO,WAAW,WAAW,MAAM,QAAQ,OAAO,MAAM,CAE1D,SAAQ,IAAI,IAAI,OAAO,MAAM;SACxB;KAEL,MAAM,YAAY,IAAI,IAAI,CAAC,OAAO,MAAgB,CAAC;AAEnD,YAAO,eAAe,WAAW,cAAc;MAC7C,OAAO,OAAO;MACd,UAAU;MACV,YAAY;MACZ,cAAc;MACf,CAAC;AACF,aAAQ;;AAEV;GACF,QACE,SAAQ,OAAO;;EAGnB,MAAM,SAAS,WAAW,IAAI,SAAS;AACvC,SAAO;GACL;GACA,MAAM,OAAO;GACb;GACA;GACA,SAAS,QAAQ,WAAW;GAC5B,aAAa,QAAQ,eAAe;GACpC,qBAAqB,QAAQ,uBAAuB;GACpD,mBAAmB,QAAQ,qBAAqB;GACjD;GACD;;;;;;AAOJ,MAAa,8BAA8B,YAA0C;CACnF,MAAM,iBAA+B,EAAE;AAEvC,MAAK,MAAM,UAAU,SAAS;EAC5B,IAAI;EACJ,IAAI;AAGJ,MAAI,OAAO,QAAQ,UAAU,aAAa,OAAO,QAAQ,UAAU,cAAc;AAC/E,OAAI,OAAO,aAAa,GAAI;GAE5B,MAAM,SAAsB;IAC1B,UAAU,OAAO;IACjB,MAAM,OAAO;IACb,QAAQ,OAAO,OAAO;IACtB,OAAO;IACR;AACD,kBAAe,KAAK,OAAO;AAC3B;;EAIF,MAAM,iBAAiB,OAAO,SAAS,SAAS,WAAW;EAC3D,MAAM,iBACJ,kBAAkB,OAAO,sBAAsB,OAAO,sBAAsB,OAAO;EACrF,MAAM,oBACJ,kBAAkB,OAAO,oBAAoB,OAAO,oBAAoB,OAAO;AAEjF,UAAQ,OAAO,MAAf;GACE,KAAK;AACH,QACE,OAAO,QAAQ,UAAU,aACzB,OAAO,QAAQ,UAAU,eACzB,gBACA;KACA,MAAM,QAAQ,OAAO;AACrB,SAAI,OAAO,SAAS,OAAO,KAAK;AAC9B,cAAQ,kBAAkB,MAAM,MAAiC;AACjE,gBAAU,kBAAkB,MAAM,IAA+B;;WAE9D;KACL,MAAM,YAAY,OAAO;AACzB,SAAI,WAAW,KACb,SAAQ,kBAAkB,UAAU;;AAGxC;GACF,KAAK,QAAQ;IACX,MAAM,YAAY,OAAO;AACzB,QAAI,UACF,SACE,OAAO,QAAQ,UAAU,UACrB,MAAM,KAAK,UAAU,CAAC,IAAI,OAAO,GACjC,OAAO,UAAU,WAAW;AAEpC;;GAEF,QACE,SAAQ,OAAO;;AAInB,MAAI,CAAC,SAAS,UAAU,MAAM,OAAO,aAAa,GAAI;AACtD,MAAI,OAAO,SAAS,UAAU,MAAM,QAAQ,MAAM,IAAI,MAAM,WAAW,EAAG;EAG1E,MAAM,eAAe,iBAAiB,cAAe,OAAO,OAAwB;EAEpF,MAAM,SAAsB;GAC1B,UAAU;GACV,MAAM,OAAO;GACb,QAAQ;GACD;GACP,GAAI,WAAW,EAAW,SAAmB;GAC7C,GAAI,iBAAiB,eAAe,oBAChC,EAAE,aAAa,mBAAmB,GAClC,EAAE;GACP;AACD,iBAAe,KAAK,OAAO;;AAG7B,QAAO"}
|
|
1
|
+
{"version":3,"file":"filterTransformers.mjs","names":[],"sources":["../../../../src/modules/table/filterTransformers.ts"],"sourcesContent":["import type { DateValue, RangeValue, SharedSelection } from \"@heroui/react\";\r\nimport { CalendarDate, getLocalTimeZone, today } from \"@internationalized/date\";\r\nimport type { QueryFilter, QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport type { ColumnDataType, FilterMethod } from \"@m5kdev/commons/modules/table/filter.types\";\r\nimport { DateTime } from \"luxon\";\r\n\r\nexport type FilterValue =\r\n | string\r\n | number\r\n | string[]\r\n | DateValue\r\n | RangeValue<DateValue>\r\n | boolean\r\n | SharedSelection\r\n | null;\r\n\r\nexport interface HeroUIFilter {\r\n columnId: string;\r\n type: ColumnDataType | null;\r\n value: FilterValue;\r\n method: FilterMethod | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n}\r\n\r\n/**\r\n * Convert CalendarDate to UTC ISO string at midnight UTC\r\n */\r\nexport const calendarDateToUTC = (date: CalendarDate): string => {\r\n return DateTime.utc(date.year, date.month, date.day).toISO() ?? \"\";\r\n};\r\n\r\n/**\r\n * Convert CalendarDate to end of day UTC ISO string\r\n */\r\nexport const calendarDateToEndOfDayUTC = (date: CalendarDate): string => {\r\n return DateTime.utc(date.year, date.month, date.day).endOf(\"day\").toISO() ?? \"\";\r\n};\r\n\r\n/**\r\n * Parse UTC ISO string to CalendarDate (preserves UTC date, no timezone shift)\r\n */\r\nconst parseUTCToCalendarDate = (isoString: string): CalendarDate | null => {\r\n try {\r\n const dt = DateTime.fromISO(isoString, { zone: \"utc\" });\r\n if (!dt.isValid) return null;\r\n return new CalendarDate(dt.year, dt.month, dt.day);\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Convert any date filter method from URL to a RangeValue for DateRangePicker\r\n * Handles: on, before, after, between, intersect\r\n * Parses UTC ISO strings as UTC to avoid timezone shifts\r\n */\r\nexport const dateFilterToRangeValue = (\r\n filters: QueryFilters | undefined,\r\n columnId: string\r\n): RangeValue<DateValue> | null => {\r\n if (!filters) return null;\r\n\r\n const filter = filters.find((f) => f.columnId === columnId);\r\n if (!filter || filter.type !== \"date\") return null;\r\n\r\n const todayDate = today(getLocalTimeZone());\r\n const epochStart = new CalendarDate(1970, 1, 1);\r\n\r\n try {\r\n switch (filter.method) {\r\n case \"on\": {\r\n // Same day range\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: day as unknown as DateValue,\r\n end: day as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"before\": {\r\n // [epochStart, selectedDay]\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: epochStart as unknown as DateValue,\r\n end: day as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"after\": {\r\n // [selectedDay, today]\r\n if (typeof filter.value !== \"string\" || !filter.value) return null;\r\n const day = parseUTCToCalendarDate(filter.value);\r\n if (!day) return null;\r\n return {\r\n start: day as unknown as DateValue,\r\n end: todayDate as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n case \"between\":\r\n case \"intersect\": {\r\n // [value, valueTo]\r\n if (typeof filter.value !== \"string\" || !filter.value || !filter.valueTo) return null;\r\n const startDate = parseUTCToCalendarDate(filter.value);\r\n const endDate = parseUTCToCalendarDate(filter.valueTo);\r\n if (!startDate || !endDate) return null;\r\n return {\r\n start: startDate as unknown as DateValue,\r\n end: endDate as unknown as DateValue,\r\n } as RangeValue<DateValue>;\r\n }\r\n default:\r\n return null;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Transform filters from backend format (QueryFilter[]) to HeroUI format (HeroUIFilter[])\r\n * Used when loading filters from URL/backend to populate HeroUI components\r\n */\r\nexport const transformFiltersToHeroUI = (\r\n filtersToTransform: QueryFilters,\r\n columnsMap: Map<\r\n string,\r\n {\r\n id: string;\r\n label: string;\r\n type?: ColumnDataType | null;\r\n options?: { label: string; value: string }[] | null;\r\n endColumnId?: string | null;\r\n periodStartColumnId?: string | null;\r\n periodEndColumnId?: string | null;\r\n }\r\n >,\r\n filterMethods: Record<ColumnDataType, FilterMethod[]>\r\n): HeroUIFilter[] => {\r\n return filtersToTransform.map((filter) => {\r\n let value: FilterValue = null;\r\n let method: FilterMethod | null = null;\r\n let columnId = filter.columnId;\r\n\r\n // Check if this intersect filter should map to Period pseudo-column\r\n if (filter.type === \"date\" && filter.method === \"intersect\" && filter.endColumnId) {\r\n const periodColumnId = `${filter.columnId}__period`;\r\n const periodColumn = columnsMap.get(periodColumnId);\r\n if (periodColumn) {\r\n // Map to Period pseudo-column\r\n columnId = periodColumnId;\r\n }\r\n }\r\n\r\n // Find the method object from the methods configuration\r\n if (filter.type) {\r\n const availableMethods = filterMethods[filter.type as ColumnDataType];\r\n const methodObj = availableMethods?.find((m: FilterMethod) => m.value === filter.method);\r\n if (methodObj) {\r\n method = methodObj;\r\n } else if (filter.method === \"isEmpty\" || filter.method === \"isNotEmpty\") {\r\n // Handle isEmpty/isNotEmpty even if not in the provided method list\r\n method = {\r\n value: filter.method,\r\n label: filter.method === \"isEmpty\" ? \"Is Empty\" : \"Is Not Empty\",\r\n component: null,\r\n };\r\n }\r\n }\r\n\r\n // Transform value based on type\r\n switch (filter.type) {\r\n case \"string\":\r\n value = filter.value as string;\r\n break;\r\n case \"number\":\r\n value = filter.value as number;\r\n break;\r\n case \"date\":\r\n // Use the shared helper for range conversion, or parse single dates as UTC\r\n if (filter.method === \"between\" || filter.method === \"intersect\") {\r\n // For range methods, use the helper function\r\n const range = dateFilterToRangeValue([filter], filter.columnId);\r\n value = range;\r\n } else {\r\n // Single date value: parse UTC ISO string and extract UTC calendar date\r\n if (typeof filter.value === \"string\" && filter.value) {\r\n const day = parseUTCToCalendarDate(filter.value);\r\n value = day ? (day as unknown as DateValue) : null;\r\n } else {\r\n value = null;\r\n }\r\n }\r\n break;\r\n case \"boolean\":\r\n value = filter.value as boolean;\r\n break;\r\n case \"enum\":\r\n if (filter.method === \"oneOf\" && Array.isArray(filter.value)) {\r\n // Multi-select: array of strings to SharedSelection (Set)\r\n value = new Set(filter.value) as SharedSelection;\r\n } else {\r\n // Single select: string to SharedSelection with currentKey\r\n const selection = new Set([filter.value as string]) as SharedSelection;\r\n // Set currentKey property\r\n Object.defineProperty(selection, \"currentKey\", {\r\n value: filter.value as string,\r\n writable: true,\r\n enumerable: false,\r\n configurable: true,\r\n });\r\n value = selection;\r\n }\r\n break;\r\n case \"jsonArray\":\r\n if (filter.method === \"oneOf\" && Array.isArray(filter.value)) {\r\n value = new Set(filter.value) as SharedSelection;\r\n } else if (Array.isArray(filter.value) && filter.value.length > 0) {\r\n const first = filter.value[0] as string;\r\n const selection = new Set([first]) as SharedSelection;\r\n Object.defineProperty(selection, \"currentKey\", {\r\n value: first,\r\n writable: true,\r\n enumerable: false,\r\n configurable: true,\r\n });\r\n value = selection;\r\n } else {\r\n value = filter.value;\r\n }\r\n break;\r\n default:\r\n value = filter.value;\r\n }\r\n\r\n const column = columnsMap.get(columnId);\r\n return {\r\n columnId,\r\n type: filter.type,\r\n value,\r\n method,\r\n options: column?.options ?? null,\r\n endColumnId: column?.endColumnId ?? null,\r\n periodStartColumnId: column?.periodStartColumnId ?? null,\r\n periodEndColumnId: column?.periodEndColumnId ?? null,\r\n };\r\n });\r\n};\r\n\r\n/**\r\n * Transform filters from HeroUI format (HeroUIFilter[]) to backend format (QueryFilter[])\r\n * Used when applying filters to send to backend/URL\r\n */\r\nexport const transformFiltersFromHeroUI = (filters: HeroUIFilter[]): QueryFilters => {\r\n const filtersToApply: QueryFilters = [];\r\n\r\n for (const filter of filters) {\r\n let value: FilterValue | undefined;\r\n let valueTo: FilterValue | undefined;\r\n\r\n // Handle isEmpty/isNotEmpty methods - they don't need a value\r\n if (filter.method?.value === \"isEmpty\" || filter.method?.value === \"isNotEmpty\") {\r\n if (filter.columnId === \"\") continue;\r\n\r\n const result: QueryFilter = {\r\n columnId: filter.columnId,\r\n type: filter.type as ColumnDataType,\r\n method: filter.method.value,\r\n value: \"\",\r\n };\r\n filtersToApply.push(result);\r\n continue;\r\n }\r\n\r\n // Handle Period pseudo-column: map to intersect on real columns\r\n const isPeriodColumn = filter.columnId.endsWith(\"__period\");\r\n const actualColumnId =\r\n isPeriodColumn && filter.periodStartColumnId ? filter.periodStartColumnId : filter.columnId;\r\n const actualEndColumnId =\r\n isPeriodColumn && filter.periodEndColumnId ? filter.periodEndColumnId : filter.endColumnId;\r\n\r\n switch (filter.type) {\r\n case \"date\":\r\n if (\r\n filter.method?.value === \"between\" ||\r\n filter.method?.value === \"intersect\" ||\r\n isPeriodColumn\r\n ) {\r\n const range = filter.value as RangeValue<DateValue>;\r\n if (range?.start && range?.end) {\r\n value = calendarDateToUTC(range.start as unknown as CalendarDate);\r\n valueTo = calendarDateToUTC(range.end as unknown as CalendarDate);\r\n }\r\n } else {\r\n const dateValue = filter.value as unknown as CalendarDate;\r\n if (dateValue?.year) {\r\n value = calendarDateToUTC(dateValue);\r\n }\r\n }\r\n break;\r\n case \"enum\": {\r\n const selection = filter.value as SharedSelection;\r\n if (selection) {\r\n value =\r\n filter.method?.value === \"oneOf\"\r\n ? Array.from(selection).map(String)\r\n : String(selection.currentKey);\r\n }\r\n break;\r\n }\r\n case \"jsonArray\": {\r\n const selection = filter.value as SharedSelection;\r\n if (selection) {\r\n value =\r\n filter.method?.value === \"oneOf\"\r\n ? Array.from(selection).map(String)\r\n : [String(selection.currentKey)];\r\n }\r\n break;\r\n }\r\n default:\r\n value = filter.value;\r\n }\r\n\r\n // Skip filters without valid values\r\n if (!value || value === \"\" || filter.columnId === \"\") continue;\r\n if (\r\n (filter.type === \"enum\" || filter.type === \"jsonArray\") &&\r\n Array.isArray(value) &&\r\n value.length === 0\r\n ) {\r\n continue;\r\n }\r\n\r\n // For Period columns, always use intersect method\r\n const actualMethod = isPeriodColumn ? \"intersect\" : (filter.method as FilterMethod).value;\r\n\r\n const result: QueryFilter = {\r\n columnId: actualColumnId,\r\n type: filter.type as ColumnDataType,\r\n method: actualMethod,\r\n value: value as string | number | boolean | string[],\r\n ...(valueTo && { valueTo: valueTo as string }),\r\n ...(actualMethod === \"intersect\" && actualEndColumnId\r\n ? { endColumnId: actualEndColumnId }\r\n : {}),\r\n };\r\n filtersToApply.push(result);\r\n }\r\n\r\n return filtersToApply;\r\n};\r\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m5kdev/web-ui",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.10",
|
|
4
4
|
"license": "GPL-3.0-only",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"zod": "4.2.1",
|
|
68
68
|
"@tanstack/react-query": "5.83.0",
|
|
69
69
|
"@trpc/tanstack-react-query": "11.4.3",
|
|
70
|
-
"@m5kdev/commons": "0.8.
|
|
71
|
-
"@m5kdev/frontend": "0.8.
|
|
70
|
+
"@m5kdev/commons": "0.8.10",
|
|
71
|
+
"@m5kdev/frontend": "0.8.10"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@tsdown/css": "0.21.7",
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"globals": "16.3.0",
|
|
81
81
|
"tsdown": "0.21.7",
|
|
82
82
|
"vite": "7.0.4",
|
|
83
|
-
"@m5kdev/backend": "0.8.
|
|
84
|
-
"@m5kdev/config": "0.8.
|
|
83
|
+
"@m5kdev/backend": "0.8.10",
|
|
84
|
+
"@m5kdev/config": "0.8.10"
|
|
85
85
|
},
|
|
86
86
|
"exports": {
|
|
87
87
|
"./components/*": {
|