@pol-studios/features 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,769 @@
1
+ // src/comments/useComments.tsx
2
+ import moment from "moment";
3
+ import {
4
+ createContext,
5
+ useCallback,
6
+ useContext,
7
+ useMemo,
8
+ useState
9
+ } from "react";
10
+ import {
11
+ useDbDelete,
12
+ useQuery,
13
+ useDbRealtimeQuery,
14
+ useDbUpsert,
15
+ useSupabase
16
+ } from "@pol-studios/db";
17
+ import { useAuth } from "@pol-studios/auth";
18
+ import { isUsable } from "@pol-studios/utils";
19
+ import { Comment } from "@pol-studios/db";
20
+ import { jsx } from "react/jsx-runtime";
21
+ var CommentContext = createContext(null);
22
+ function timeSinceOpened(timestamp) {
23
+ if (!timestamp) {
24
+ return "";
25
+ }
26
+ const openedTime = moment(timestamp);
27
+ return preciseHumanize(moment.duration(moment().diff(openedTime))) + " ago";
28
+ }
29
+ var preciseHumanize = (duration) => {
30
+ const years = duration.years();
31
+ const months = duration.months();
32
+ const days = duration.days();
33
+ const hours = duration.hours();
34
+ const minutes = duration.minutes();
35
+ if (duration.asMinutes() < 1) {
36
+ return "a few seconds";
37
+ } else if (duration.years() > 0) {
38
+ return `${years} year${years !== 1 ? "s" : ""}`;
39
+ } else if (duration.months() > 0) {
40
+ return `${months} month${months !== 1 ? "s" : ""}`;
41
+ } else if (duration.days() > 0) {
42
+ return `${days} day${days !== 1 ? "s" : ""}`;
43
+ }
44
+ return `${hours > 0 ? `${hours} hour${hours !== 1 ? "s" : ""} ` : ""}${minutes > 0 ? `${minutes} minute${minutes !== 1 ? "s" : ""} ` : ""}`;
45
+ };
46
+ function CommentProvider({
47
+ children,
48
+ entityTableName,
49
+ entityId,
50
+ schemaName = "public"
51
+ }) {
52
+ const auth = useAuth();
53
+ const supabase = useSupabase();
54
+ const tagUpsert = useDbUpsert(
55
+ { schema: "core", table: "CommentTag" },
56
+ ["id"],
57
+ "*"
58
+ );
59
+ const upsert = useDbUpsert({ schema: "core", table: "Comment" }, ["id"], "*");
60
+ const upsertSection = useDbUpsert(
61
+ { schema: "core", table: "CommentSection" },
62
+ ["id"],
63
+ "*"
64
+ );
65
+ const reaction = useDbUpsert(
66
+ { schema: "core", table: "CommentReaction" },
67
+ ["id"],
68
+ "*"
69
+ );
70
+ const reactionDelete = useDbDelete(
71
+ { schema: "core", table: "CommentReaction" },
72
+ ["id"]
73
+ );
74
+ const readUpsert = useDbUpsert(
75
+ { schema: "core", table: "CommentRead" },
76
+ ["id"],
77
+ "*"
78
+ );
79
+ const deleteCommentMutation = useDbDelete(
80
+ { schema: "core", table: "Comment" },
81
+ ["id"]
82
+ );
83
+ const [quote, setQuote] = useState(null);
84
+ const [message, setMessage] = useState("");
85
+ const [showMore, setShowMore] = useState(false);
86
+ const [taggedUserIds, setTaggedUserIds] = useState([]);
87
+ const shouldLoadProfiles = useMemo(
88
+ () => Boolean(auth?.user?.id),
89
+ [auth?.user?.id]
90
+ );
91
+ const usersRequest = useQuery(
92
+ supabase.schema("core").from("Profile").select("*"),
93
+ { enabled: shouldLoadProfiles }
94
+ );
95
+ const commentSectionRequest = useDbRealtimeQuery(
96
+ supabase.schema("core").from("CommentSection").select("*", { count: "exact" }).eq("entityId", entityId).eq("tableName", entityTableName).eq("schemaName", schemaName).maybeSingle()
97
+ );
98
+ const commentSectionId = commentSectionRequest.data?.id;
99
+ const hasCommentSectionId = isUsable(commentSectionId);
100
+ const commentsRequest = useDbRealtimeQuery(
101
+ supabase.schema("core").from("Comment").select(
102
+ `${Comment.defaultQuery}, CommentReaction(id, value, commentId, userId), CommentRead(id, userId, commentId)`,
103
+ { count: "exact" }
104
+ ).eq("commentSectionId", commentSectionId ?? "").order("createdAt", { ascending: false }),
105
+ { enabled: hasCommentSectionId }
106
+ );
107
+ const comments = useMemo(() => {
108
+ if (!isUsable(commentsRequest?.data)) return [];
109
+ return commentsRequest.data;
110
+ }, [commentsRequest?.data]);
111
+ const sendComment = useCallback(async () => {
112
+ if (message === "") return;
113
+ let nextCommentSectionId = commentSectionId;
114
+ if (!hasCommentSectionId) {
115
+ const newSection = {
116
+ entityId,
117
+ tableName: entityTableName,
118
+ schemaName
119
+ };
120
+ try {
121
+ const sectionResponse = await upsertSection.mutateAsync(newSection);
122
+ if (!sectionResponse?.id) {
123
+ throw new Error("Failed to create comment section: No ID returned.");
124
+ }
125
+ nextCommentSectionId = sectionResponse.id;
126
+ await commentSectionRequest.refetch();
127
+ } catch (error) {
128
+ console.error(
129
+ "Error creating comment section - full error:",
130
+ JSON.stringify(error, null, 2)
131
+ );
132
+ console.error("Error creating comment section - error object:", error);
133
+ let errorMessage = "Failed to create comment section.";
134
+ let errorDetails = "";
135
+ if (error && typeof error === "object") {
136
+ const supabaseError = error;
137
+ if (supabaseError.code) {
138
+ errorDetails += `[${supabaseError.code}] `;
139
+ }
140
+ if (supabaseError.message) {
141
+ errorMessage = supabaseError.message;
142
+ }
143
+ if (supabaseError.details) {
144
+ errorDetails += `Details: ${supabaseError.details}. `;
145
+ }
146
+ if (supabaseError.hint) {
147
+ errorDetails += `Hint: ${supabaseError.hint}. `;
148
+ }
149
+ } else if (error instanceof Error) {
150
+ errorMessage = error.message;
151
+ }
152
+ const fullErrorMessage = errorDetails ? `${errorMessage} ${errorDetails}`.trim() : errorMessage;
153
+ throw new Error(fullErrorMessage);
154
+ }
155
+ }
156
+ if (!nextCommentSectionId) {
157
+ throw new Error("Comment section ID is missing. Please try again.");
158
+ }
159
+ const newComment = {
160
+ commentSectionId: nextCommentSectionId,
161
+ message
162
+ };
163
+ if (quote !== null) {
164
+ newComment.parentId = quote.id;
165
+ }
166
+ const commentResponse = await upsert.mutateAsync(newComment);
167
+ await Promise.all(
168
+ taggedUserIds.map(
169
+ (userId) => tagUpsert.mutateAsync({
170
+ userId,
171
+ commentId: commentResponse.id
172
+ })
173
+ )
174
+ );
175
+ setShowMore(true);
176
+ setTaggedUserIds([]);
177
+ setMessage("");
178
+ setQuote(null);
179
+ }, [
180
+ commentSectionId,
181
+ commentSectionRequest.refetch,
182
+ entityId,
183
+ entityTableName,
184
+ hasCommentSectionId,
185
+ message,
186
+ quote,
187
+ schemaName,
188
+ setMessage,
189
+ setShowMore,
190
+ setTaggedUserIds,
191
+ setQuote,
192
+ tagUpsert,
193
+ taggedUserIds,
194
+ upsert,
195
+ upsertSection
196
+ ]);
197
+ const tagUser = useCallback(
198
+ (userId) => {
199
+ setTaggedUserIds((prev) => {
200
+ if (prev.includes(userId)) {
201
+ return prev.filter((user) => user !== userId);
202
+ }
203
+ return [...prev, userId];
204
+ });
205
+ },
206
+ [setTaggedUserIds]
207
+ );
208
+ const tryCommentReaction = useCallback(
209
+ async (value, commentId) => {
210
+ if (!auth?.user?.id || comments.length === 0) return;
211
+ const comment = comments.find((c) => c.id === commentId);
212
+ if (!comment) return;
213
+ if (comment.CommentReaction.some(
214
+ (x) => x.userId === auth.user.id && x.value === value
215
+ ))
216
+ return;
217
+ const reactionData = {
218
+ commentId,
219
+ value
220
+ };
221
+ await reaction.mutateAsync(reactionData);
222
+ },
223
+ [auth?.user?.id, comments, reaction]
224
+ );
225
+ const deleteReaction = useCallback(
226
+ async (reactionId) => {
227
+ await reactionDelete.mutateAsync({ id: reactionId });
228
+ },
229
+ [reactionDelete]
230
+ );
231
+ const readComment = useCallback(
232
+ async (commentId) => {
233
+ if (!auth?.user?.id || comments.length === 0) return;
234
+ const comment = comments.find((c) => c.id === commentId);
235
+ const reads = comment?.CommentRead;
236
+ if (!reads || reads.some((x) => x.userId === auth.user.id)) return;
237
+ await readUpsert.mutateAsync({ commentId });
238
+ await commentsRequest.refetch();
239
+ },
240
+ [auth?.user?.id, comments, commentsRequest, readUpsert]
241
+ );
242
+ const deleteComment = useCallback(
243
+ async (commentId) => {
244
+ await deleteCommentMutation.mutateAsync({ id: commentId });
245
+ },
246
+ [deleteCommentMutation]
247
+ );
248
+ const quoteInfo = useMemo(() => {
249
+ if (quote === null) return null;
250
+ return "- replying to " + quote.userName + "'s comment created " + timeSinceOpened(quote.createdAt);
251
+ }, [quote]);
252
+ const taggableUsers = useMemo(() => {
253
+ if (!auth?.user?.id || !isUsable(usersRequest.data)) return [];
254
+ return usersRequest.data.filter((user) => {
255
+ return user.id !== auth.user.id && !taggedUserIds.includes(user.id);
256
+ });
257
+ }, [auth?.user?.id, taggedUserIds, usersRequest.data]);
258
+ const taggedUsers = useMemo(() => {
259
+ if (!isUsable(usersRequest.data)) return [];
260
+ return usersRequest.data.filter((user) => taggedUserIds.includes(user.id));
261
+ }, [taggedUserIds, usersRequest.data]);
262
+ const commentSectionExists = useMemo(() => {
263
+ return hasCommentSectionId;
264
+ }, [hasCommentSectionId]);
265
+ const unreadCommentCount = useMemo(() => {
266
+ if (!auth?.user?.id || comments.length === 0) return 0;
267
+ return comments.filter(
268
+ (c) => !c.CommentRead.some((x) => x.userId === auth.user.id)
269
+ ).length;
270
+ }, [auth?.user?.id, comments]);
271
+ const contextValue = useMemo(
272
+ () => ({
273
+ deleteComment,
274
+ deleteReaction,
275
+ tryCommentReaction,
276
+ showMore,
277
+ setShowMore,
278
+ quote,
279
+ setQuote,
280
+ setMessage,
281
+ message,
282
+ sendComment,
283
+ quoteInfo,
284
+ comments,
285
+ commentSectionExists,
286
+ taggableUsers,
287
+ tagUser,
288
+ taggedUsers,
289
+ readComment,
290
+ unreadCommentCount
291
+ }),
292
+ [
293
+ commentSectionExists,
294
+ comments,
295
+ deleteComment,
296
+ deleteReaction,
297
+ message,
298
+ quote,
299
+ quoteInfo,
300
+ readComment,
301
+ sendComment,
302
+ showMore,
303
+ tagUser,
304
+ taggableUsers,
305
+ taggedUsers,
306
+ tryCommentReaction,
307
+ unreadCommentCount
308
+ ]
309
+ );
310
+ return /* @__PURE__ */ jsx(CommentContext.Provider, { value: contextValue, children });
311
+ }
312
+ var useComments = () => {
313
+ const context = useContext(CommentContext);
314
+ if (!context) {
315
+ throw new Error(
316
+ "useComments must be used within a CommentProvider"
317
+ );
318
+ }
319
+ return context;
320
+ };
321
+
322
+ // src/ordering/useOrderHint.ts
323
+ import { isUsable as isUsable2 } from "@pol-studios/utils";
324
+ var useOrderHint = () => {
325
+ const createOrderHint = (prevOrderHint, nextOrderHint) => {
326
+ let newOrderHint;
327
+ if (isNaN(prevOrderHint)) {
328
+ return 1;
329
+ }
330
+ if (isUsable2(nextOrderHint) === false || isNaN(nextOrderHint)) {
331
+ newOrderHint = prevOrderHint + 1;
332
+ } else if (isUsable2(prevOrderHint) === false) {
333
+ newOrderHint = nextOrderHint / 2;
334
+ } else {
335
+ newOrderHint = (prevOrderHint + nextOrderHint) / 2;
336
+ }
337
+ return newOrderHint;
338
+ };
339
+ return { createOrderHint };
340
+ };
341
+ var useOrderHint_default = useOrderHint;
342
+
343
+ // src/ordering/useOrderManager.ts
344
+ import { useEffect, useState as useState2 } from "react";
345
+ import {
346
+ useDbRealtimeQuery as useDbRealtimeQuery2,
347
+ useDbUpsert as useDbUpsert2,
348
+ useSupabase as useSupabase2
349
+ } from "@pol-studios/db";
350
+ import { isUsable as isUsable3 } from "@pol-studios/utils";
351
+ var useOrderManager = (table, items, property, schema = "public") => {
352
+ const [managedItems, setManagedItems] = useState2([]);
353
+ const [originalItems, setOriginalItems] = useState2([]);
354
+ const supabase = useSupabase2();
355
+ const upsert = useDbUpsert2(schema !== "public" ? { table, schema } : table, [
356
+ "id"
357
+ ]);
358
+ const orderHintRequest = property ? useDbRealtimeQuery2(
359
+ supabase.schema(schema).from(table).select("*", { count: "exact" }).in(
360
+ property,
361
+ items.map((x) => x.id)
362
+ )
363
+ ) : null;
364
+ useEffect(() => {
365
+ if (!property) {
366
+ const res2 = [];
367
+ (async () => {
368
+ for (const [index, item] of items.entries()) {
369
+ if (item.orderHint == null) {
370
+ await updateOrderHint(
371
+ item,
372
+ index > 0 ? Number(res2[index - 1].orderHint) : null,
373
+ null
374
+ );
375
+ }
376
+ res2.push({
377
+ ...item,
378
+ orderHint: Number(item.orderHint ?? index + 1)
379
+ });
380
+ }
381
+ res2.sort((a, b) => a.orderHint - b.orderHint);
382
+ setOriginalItems(res2);
383
+ setManagedItems(res2);
384
+ })();
385
+ return;
386
+ }
387
+ if (!orderHintRequest?.data) return;
388
+ const dataWithOrderHint = orderHintRequest.data;
389
+ let currMax = dataWithOrderHint.map((x) => Number(x.orderHint)).reduce((a, b) => Math.max(a, b), 0);
390
+ const res = [];
391
+ (async () => {
392
+ for (const item of items) {
393
+ const newItem = { ...item, orderHint: void 0 };
394
+ const orderHint = dataWithOrderHint.find(
395
+ (x) => x[property] === item.id
396
+ );
397
+ if (isUsable3(orderHint)) {
398
+ newItem.orderHint = Number(orderHint.orderHint);
399
+ } else {
400
+ await upsert.mutateAsync({
401
+ orderHint: String(currMax + 1),
402
+ [property]: item.id
403
+ });
404
+ currMax += 1;
405
+ newItem.orderHint = currMax;
406
+ }
407
+ res.push(newItem);
408
+ }
409
+ res.sort((a, b) => a.orderHint - b.orderHint);
410
+ setOriginalItems(res);
411
+ setManagedItems(res);
412
+ })();
413
+ }, [orderHintRequest?.data, items, property]);
414
+ const orderHintHelper = useOrderHint_default();
415
+ const updateOrderHint = async (activeItem, prevOrderHint, nextOrderHint) => {
416
+ let newOrderHint = orderHintHelper.createOrderHint(
417
+ prevOrderHint,
418
+ nextOrderHint
419
+ );
420
+ const newActiveItem = { ...activeItem, orderHint: newOrderHint };
421
+ const newManagedItems = managedItems.map(
422
+ (x) => x.id === activeItem.id ? newActiveItem : x
423
+ );
424
+ newManagedItems.sort((a, b) => a.orderHint - b.orderHint);
425
+ setManagedItems(newManagedItems);
426
+ if (!property) {
427
+ await upsert.mutateAsync({
428
+ id: activeItem.id,
429
+ orderHint: String(newOrderHint)
430
+ });
431
+ return;
432
+ }
433
+ try {
434
+ const dataWithOrderHint = orderHintRequest?.data;
435
+ const data = dataWithOrderHint?.find(
436
+ (x) => x[property] === activeItem.id
437
+ );
438
+ await upsert.mutateAsync({ ...data, orderHint: String(newOrderHint) });
439
+ } catch (error) {
440
+ setManagedItems(originalItems);
441
+ }
442
+ };
443
+ return { managedItems, updateOrderHint };
444
+ };
445
+ var useOrderManager_default = useOrderManager;
446
+
447
+ // src/punch-list/usePunchListPage.ts
448
+ import {
449
+ useSupabase as useSupabase3
450
+ } from "@pol-studios/db";
451
+ import { useEffect as useEffect2, useState as useState3 } from "react";
452
+ import { useDbUpsert as useDbUpsert3 } from "@pol-studios/db";
453
+ import { useAuth as useAuth2 } from "@pol-studios/auth";
454
+ function usePunchListPage(relation, entityId) {
455
+ const supabase = useSupabase3();
456
+ const upsert = useDbUpsert3("PunchListPage", ["id"]);
457
+ const { user } = useAuth2();
458
+ const [punchListPageId, setPunchListPageId] = useState3(null);
459
+ const handleThis = async () => {
460
+ const punchListPage = await supabase.from("PunchListPage").select("id").eq("tableName", relation).eq("entityId", entityId).maybeSingle();
461
+ if (punchListPage.data) {
462
+ setPunchListPageId(punchListPage.data.id);
463
+ return;
464
+ }
465
+ await upsert.mutateAsync({
466
+ tableName: relation,
467
+ entityId,
468
+ createdBy: user?.id
469
+ });
470
+ const newPunchListPage = await supabase.from("PunchListPage").select("id").eq("tableName", relation).eq("entityId", entityId).maybeSingle();
471
+ if (newPunchListPage.data) {
472
+ setPunchListPageId(newPunchListPage.data.id);
473
+ }
474
+ };
475
+ useEffect2(() => {
476
+ handleThis();
477
+ }, [entityId]);
478
+ return punchListPageId;
479
+ }
480
+
481
+ // src/filter-utils/useFilterBuilder.tsx
482
+ import { createContext as createContext2, useContext as useContext2 } from "react";
483
+ import { jsx as jsx2 } from "react/jsx-runtime";
484
+ var hookOnChange = (options, onChange, curr, value, tableName, property) => {
485
+ if (!tableName) {
486
+ onChange({ ...curr, value });
487
+ return;
488
+ }
489
+ if (options) {
490
+ let filteredEntities;
491
+ switch (curr.op) {
492
+ case "=":
493
+ filteredEntities = options.filter((entity) => {
494
+ if (typeof property === "string") {
495
+ const nestedProperty = getPropertyKey(property);
496
+ return getProperty(nestedProperty, entity) === value;
497
+ }
498
+ return property.some((prop) => {
499
+ const nestedProperty = getPropertyKey(prop);
500
+ return getProperty(nestedProperty, entity) === value;
501
+ });
502
+ });
503
+ break;
504
+ case "contains":
505
+ case "ilike":
506
+ filteredEntities = options.filter((entity) => {
507
+ if (typeof property === "string") {
508
+ const nestedProperty = getPropertyKey(property);
509
+ const propValue = getProperty(nestedProperty, entity);
510
+ return propValue?.toString().toLowerCase().includes(value.toLowerCase());
511
+ }
512
+ return property.some((prop) => {
513
+ const nestedProperty = getPropertyKey(prop);
514
+ const propValue = getProperty(nestedProperty, entity);
515
+ return propValue?.toString().toLowerCase().includes(value.toLowerCase());
516
+ });
517
+ });
518
+ break;
519
+ case ">":
520
+ filteredEntities = options.filter((entity) => {
521
+ if (typeof property === "string") {
522
+ const nestedProperty = getPropertyKey(property);
523
+ return getProperty(nestedProperty, entity) > value;
524
+ }
525
+ return property.some((prop) => {
526
+ const nestedProperty = getPropertyKey(prop);
527
+ return getProperty(nestedProperty, entity) > value;
528
+ });
529
+ });
530
+ break;
531
+ case ">=":
532
+ filteredEntities = options.filter((entity) => {
533
+ if (typeof property === "string") {
534
+ const nestedProperty = getPropertyKey(property);
535
+ return getProperty(nestedProperty, entity) >= value;
536
+ }
537
+ return property.some((prop) => {
538
+ const nestedProperty = getPropertyKey(prop);
539
+ return getProperty(nestedProperty, entity) >= value;
540
+ });
541
+ });
542
+ break;
543
+ case "<":
544
+ filteredEntities = options.filter((entity) => {
545
+ if (typeof property === "string") {
546
+ const nestedProperty = getPropertyKey(property);
547
+ return getProperty(nestedProperty, entity) < value;
548
+ }
549
+ return property.some((prop) => {
550
+ const nestedProperty = getPropertyKey(prop);
551
+ return getProperty(nestedProperty, entity) < value;
552
+ });
553
+ });
554
+ break;
555
+ case "<=":
556
+ filteredEntities = options.filter((entity) => {
557
+ if (typeof property === "string") {
558
+ const nestedProperty = getPropertyKey(property);
559
+ return getProperty(nestedProperty, entity) <= value;
560
+ }
561
+ return property.some((prop) => {
562
+ const nestedProperty = getPropertyKey(prop);
563
+ return getProperty(nestedProperty, entity) <= value;
564
+ });
565
+ });
566
+ break;
567
+ case "is":
568
+ filteredEntities = options.filter((entity) => {
569
+ if (typeof property === "string") {
570
+ const nestedProperty = getPropertyKey(property);
571
+ const propValue = getProperty(nestedProperty, entity);
572
+ if (value === "null") return propValue === null || propValue === void 0;
573
+ if (value === "not null") return propValue !== null && propValue !== void 0;
574
+ return propValue === value;
575
+ }
576
+ return property.some((prop) => {
577
+ const nestedProperty = getPropertyKey(prop);
578
+ const propValue = getProperty(nestedProperty, entity);
579
+ if (value === "null") return propValue === null || propValue === void 0;
580
+ if (value === "not null") return propValue !== null && propValue !== void 0;
581
+ return propValue === value;
582
+ });
583
+ });
584
+ break;
585
+ case "in":
586
+ filteredEntities = options.filter((entity) => {
587
+ const valuesArray = Array.isArray(value) ? value : [value];
588
+ if (typeof property === "string") {
589
+ const nestedProperty = getPropertyKey(property);
590
+ const propValue = getProperty(nestedProperty, entity);
591
+ return valuesArray.includes(propValue);
592
+ }
593
+ return property.some((prop) => {
594
+ const nestedProperty = getPropertyKey(prop);
595
+ const propValue = getProperty(nestedProperty, entity);
596
+ return valuesArray.includes(propValue);
597
+ });
598
+ });
599
+ break;
600
+ case "ai_search":
601
+ filteredEntities = options;
602
+ break;
603
+ default:
604
+ console.error(`${curr.op} condition not handled`);
605
+ filteredEntities = [];
606
+ break;
607
+ }
608
+ onChange({
609
+ ...curr,
610
+ value: [
611
+ ...filteredEntities?.map((x) => {
612
+ if (curr.info.manyToOneTableInfo?.outputProperty) {
613
+ return x[curr.info.manyToOneTableInfo.outputProperty];
614
+ }
615
+ return x.id;
616
+ }) ?? []
617
+ ],
618
+ op: curr.op
619
+ });
620
+ }
621
+ };
622
+ var getDefaultValue = (filter) => {
623
+ if (filter.options && filter.propertyType !== "boolean") {
624
+ return filter.options[0].value;
625
+ } else if (filter.manyToOneTableInfo) {
626
+ if (filter.propertyType === "string") {
627
+ return "";
628
+ } else if (filter.propertyType === "number") {
629
+ return 0;
630
+ } else if (filter.propertyType === "boolean") {
631
+ return "true";
632
+ } else if (filter.propertyType === "date") {
633
+ return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
634
+ }
635
+ return "";
636
+ } else if (filter.propertyType === "string") {
637
+ return "";
638
+ } else if (filter.propertyType === "date") {
639
+ return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
640
+ } else if (filter.propertyType === "boolean") {
641
+ return "true";
642
+ } else {
643
+ return 0;
644
+ }
645
+ };
646
+ var getComparisonOptions = (filter) => {
647
+ if (filter.options) {
648
+ return [{ display: "=", value: "=" }];
649
+ }
650
+ switch (filter.propertyType) {
651
+ case "boolean":
652
+ return [
653
+ { display: "=", value: "=" },
654
+ { display: "is", value: "is" }
655
+ ];
656
+ case "string":
657
+ return [
658
+ { display: "=", value: "=" },
659
+ { display: "contains", value: "contains" },
660
+ { display: "ilike", value: "ilike" },
661
+ { display: "in", value: "in" },
662
+ { display: "is", value: "is" },
663
+ { display: "ai_search", value: "ai_search" }
664
+ ];
665
+ case "number":
666
+ return [
667
+ { display: "=", value: "=" },
668
+ { display: ">", value: ">" },
669
+ { display: "<", value: "<" },
670
+ { display: ">=", value: ">=" },
671
+ { display: "<=", value: "<=" },
672
+ { display: "in", value: "in" },
673
+ { display: "is", value: "is" }
674
+ ];
675
+ case "date":
676
+ return [
677
+ { display: "=", value: "=" },
678
+ { display: ">", value: ">" },
679
+ { display: "<", value: "<" },
680
+ { display: ">=", value: ">=" },
681
+ { display: "<=", value: "<=" },
682
+ { display: "is", value: "is" }
683
+ ];
684
+ default:
685
+ return [{ display: "=", value: "=" }];
686
+ }
687
+ };
688
+ var getDefaultCondition = (filter) => {
689
+ if (filter.options) return "=";
690
+ switch (filter.propertyType) {
691
+ case "boolean":
692
+ return "=";
693
+ case "string":
694
+ return "ilike";
695
+ // Case insensitive by default
696
+ case "number":
697
+ return "=";
698
+ case "date":
699
+ return "=";
700
+ }
701
+ };
702
+ var genId = () => {
703
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
704
+ var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
705
+ return v.toString(16);
706
+ });
707
+ };
708
+ var getPropertyKey = (val) => {
709
+ if (val.includes(".")) {
710
+ return val.split(".");
711
+ }
712
+ return val;
713
+ };
714
+ var recurseToProperty = (properties, i, entity) => {
715
+ if (i === properties.length) {
716
+ return entity;
717
+ }
718
+ return recurseToProperty(properties, i + 1, entity[properties[i]]);
719
+ };
720
+ var getProperty = (property, entity) => {
721
+ if (typeof property === "string") {
722
+ return entity[property];
723
+ }
724
+ return recurseToProperty(property, 0, entity);
725
+ };
726
+ var FilterContext = createContext2(void 0);
727
+ var FilterProvider = ({ children, value }) => {
728
+ return /* @__PURE__ */ jsx2(FilterContext.Provider, { value, children });
729
+ };
730
+ var useFilterContext = () => {
731
+ const context = useContext2(FilterContext);
732
+ if (!context) {
733
+ throw new Error("useFilterContext must be used within a FilterProvider");
734
+ }
735
+ return context;
736
+ };
737
+
738
+ // src/filter-utils/useNestedFilterOptions.ts
739
+ function useNestedFilterOptions(value, onChange) {
740
+ const setFilterValue = (val) => {
741
+ onChange({ ...value, value: val });
742
+ };
743
+ const deleteSelf = () => {
744
+ onChange(value.id);
745
+ };
746
+ return {
747
+ setFilterValue,
748
+ deleteSelf
749
+ };
750
+ }
751
+ export {
752
+ CommentContext,
753
+ CommentProvider,
754
+ FilterProvider,
755
+ genId,
756
+ getComparisonOptions,
757
+ getDefaultCondition,
758
+ getDefaultValue,
759
+ getProperty,
760
+ getPropertyKey,
761
+ hookOnChange,
762
+ recurseToProperty,
763
+ useComments,
764
+ useFilterContext,
765
+ useNestedFilterOptions,
766
+ useOrderHint_default as useOrderHint,
767
+ useOrderManager_default as useOrderManager,
768
+ usePunchListPage
769
+ };