@compill/admin 1.0.108 → 1.0.110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/index.cjs +2115 -0
  2. package/dist/index.d.ts +50 -565
  3. package/dist/index.js +605 -592
  4. package/dist/lib/SectionTitle.d.ts +2 -0
  5. package/dist/lib/breadcrumbs/BreadCrumbs.d.ts +15 -0
  6. package/dist/lib/buttons/DialogButton.d.ts +7 -0
  7. package/dist/lib/buttons/InvalidateButton.d.ts +6 -0
  8. package/dist/lib/buttons/NavigateButton.d.ts +4 -0
  9. package/dist/lib/buttons/PublishButton.d.ts +9 -0
  10. package/dist/lib/buttons/UpdateButton.d.ts +2 -0
  11. package/dist/lib/buttons/ViewButton.d.ts +5 -0
  12. package/dist/lib/cells/OrderCell.d.ts +11 -0
  13. package/dist/lib/json/DetailsView.d.ts +5 -0
  14. package/dist/lib/json/EditItemView.d.ts +2 -0
  15. package/dist/lib/json/MultiQueryWrapper.d.ts +5 -0
  16. package/dist/lib/json/QueryWrapper.d.ts +6 -0
  17. package/dist/lib/json/ScreenRenderer.d.ts +6 -0
  18. package/dist/lib/json/ScreenTopBar.d.ts +15 -0
  19. package/dist/lib/json/TabbedView.d.ts +3 -0
  20. package/dist/lib/json/buttons/ActionButton.d.ts +14 -0
  21. package/dist/lib/json/buttons/ConfirmationActionButton.d.ts +26 -0
  22. package/dist/lib/json/dialog/DialogRenderer.d.ts +11 -0
  23. package/dist/lib/json/dialog/ItemDeleteDialog.d.ts +17 -0
  24. package/dist/lib/json/dialog/ItemEditDialog.d.ts +32 -0
  25. package/dist/lib/json/dialog/MultiQueryWrapperDialog.d.ts +7 -0
  26. package/dist/lib/json/dialog/QueryWrapperDialog.d.ts +13 -0
  27. package/dist/lib/json/table/RefreshButton.d.ts +3 -0
  28. package/dist/lib/json/table/TableRowActionsView.d.ts +11 -0
  29. package/dist/lib/json/table/TableRowPublishPostButton.d.ts +8 -0
  30. package/dist/lib/json/table/TableView.d.ts +3 -0
  31. package/dist/lib/json/table/TableViewContext.d.ts +14 -0
  32. package/dist/lib/json/table/useTableProps.d.ts +3 -0
  33. package/dist/lib/json/types/DetailsView.d.ts +57 -0
  34. package/dist/lib/json/types/EditItemDialog.d.ts +4 -0
  35. package/dist/lib/json/types/MultiQueryWrapper.d.ts +18 -0
  36. package/dist/lib/json/types/MultiQueryWrapperDialog.d.ts +13 -0
  37. package/dist/lib/json/types/QueryWrapper.d.ts +27 -0
  38. package/dist/lib/json/types/QueryWrapperDialog.d.ts +22 -0
  39. package/dist/lib/json/types/ScreenConfig.d.ts +8 -0
  40. package/dist/lib/json/types/TabbedView.d.ts +22 -0
  41. package/dist/lib/json/types/TableView.d.ts +117 -0
  42. package/dist/lib/layout/AdminLayout.d.ts +13 -0
  43. package/dist/lib/layout/ButtonBar.d.ts +19 -0
  44. package/dist/lib/layout/Content.d.ts +9 -0
  45. package/dist/lib/layout/PageTitleBar.d.ts +6 -0
  46. package/dist/lib/layout/Sidebar.d.ts +20 -0
  47. package/dist/lib/layout/menu/Menu.d.ts +12 -0
  48. package/dist/lib/layout/menu/MenuButton.d.ts +6 -0
  49. package/dist/lib/layout/menu/MenuConfig.d.ts +13 -0
  50. package/dist/lib/layout/menu/MenuItem.d.ts +11 -0
  51. package/dist/lib/layout/menu/NextMenuItem.d.ts +11 -0
  52. package/dist/lib/layout/menu/SelectedIndicator.d.ts +3 -0
  53. package/dist/lib/layout/menu/UserBlock.d.ts +9 -0
  54. package/dist/lib/modal/AttachDialog.d.ts +30 -0
  55. package/dist/lib/modal/FormActionDialog.d.ts +23 -0
  56. package/dist/lib/page/PageContainer.d.ts +2 -0
  57. package/dist/lib/page/PageContentEditor.d.ts +4 -0
  58. package/dist/lib/page/PageMain.d.ts +2 -0
  59. package/dist/lib/page/PageQueryStateContainer.d.ts +21 -0
  60. package/dist/lib/page/PageSectionTitle.d.ts +2 -0
  61. package/dist/lib/page/PageSidebar.d.ts +2 -0
  62. package/dist/lib/page/PageSidebarSection.d.ts +4 -0
  63. package/dist/lib/page/PageStateContainer.d.ts +7 -0
  64. package/dist/lib/page/PageSubSectionTitle.d.ts +2 -0
  65. package/dist/lib/page/PageTitle.d.ts +2 -0
  66. package/dist/lib/page/PageTopBar.d.ts +13 -0
  67. package/dist/lib/status/StatusBadge.d.ts +4 -0
  68. package/dist/lib/table/TableColumnButton.d.ts +1 -0
  69. package/dist/lib/table/TableContainer.d.ts +10 -0
  70. package/dist/lib/table/TableContainerContext.d.ts +18 -0
  71. package/dist/lib/table/TableCreateButton.d.ts +4 -0
  72. package/dist/lib/table/TableFilterButton.d.ts +2 -0
  73. package/dist/lib/table/TableFilters.d.ts +9 -0
  74. package/dist/lib/table/TableMassActions.d.ts +6 -0
  75. package/dist/lib/table/TableRowActionBar.d.ts +10 -0
  76. package/dist/lib/table/TableRowActionButton.d.ts +4 -0
  77. package/dist/lib/table/TableRowActionDialogButton.d.ts +4 -0
  78. package/dist/lib/table/TableRowDeleteButton.d.ts +2 -0
  79. package/dist/lib/table/TableRowEditButton.d.ts +2 -0
  80. package/dist/lib/table/TableRowNavigateButton.d.ts +4 -0
  81. package/dist/lib/table/TableRowPublishPostButton.d.ts +8 -0
  82. package/dist/lib/table/TableRowViewButton.d.ts +4 -0
  83. package/dist/lib/table/TableTopBar.d.ts +8 -0
  84. package/package.json +17 -17
  85. package/dist/index.d.mts +0 -565
  86. package/dist/index.mjs +0 -2000
package/dist/index.cjs ADDED
@@ -0,0 +1,2115 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('@soperio/jsx-runtime');
4
+ var api = require('@compill/api');
5
+ var components = require('@compill/components');
6
+ var js = require('@mdi/js');
7
+ var ui = require('@valerya/ui');
8
+ var Link = require('next/link');
9
+ var reactRouterDom = require('react-router-dom');
10
+ var React = require('react');
11
+ var adminApi = require('@compill/admin-api');
12
+ var formik = require('formik');
13
+ var reactToastify = require('react-toastify');
14
+ var reactHotkeysHook = require('react-hotkeys-hook');
15
+ var form = require('@compill/form');
16
+ var react = require('@soperio/react');
17
+ var formEditor = require('@compill/form-editor');
18
+ var editor = require('@compill/editor');
19
+ var reactDom = require('react-dom');
20
+ var router = require('next/router');
21
+ var table = require('@compill/table');
22
+ var esToolkit = require('es-toolkit');
23
+ var hooks = require('@compill/hooks');
24
+ var env = require('@compill/env');
25
+ var reactTable = require('@tanstack/react-table');
26
+ var reactQuery = require('@tanstack/react-query');
27
+ var Image = require('next/image.js');
28
+ var auth = require('@compill/auth');
29
+
30
+ function SectionTitle({ children, ...props }) {
31
+ return /* @__PURE__ */ jsxRuntime.jsx("h2", { textSize: "xl", fontWeight: "600", textColor: "slate-800", ...props, children });
32
+ }
33
+
34
+ function isArray(value) {
35
+ return Array.isArray(value);
36
+ }
37
+
38
+ function Breadcrumbs({ breadcrumbs, ...props }) {
39
+ if (isArray(breadcrumbs)) {
40
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { dflex: true, alignItems: "center", trait: "typo.h5", ...props, children: breadcrumbs.map((b, index) => /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbItem, { breadcrumb: b, showSeparator: index > 0 }, index)) });
41
+ }
42
+ return /* @__PURE__ */ jsxRuntime.jsx(QueryBreadcrumbs, { queryFn: breadcrumbs.queryFn, queryField: breadcrumbs.queryField, generate: breadcrumbs.generate });
43
+ }
44
+ function QueryBreadcrumbs({ queryFn, queryField, generate, ...props }) {
45
+ const params = reactRouterDom.useParams();
46
+ const id = queryField ? params[queryField] : void 0;
47
+ const { data, isLoading, isError } = api.useApiQuery([""], queryFn, id);
48
+ if (isLoading || isError) {
49
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { dflex: true, alignItems: "center", children: [
50
+ /* @__PURE__ */ jsxRuntime.jsx(components.Shimmer, { h: "8", w: "24" }),
51
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: js.mdiCircleSmall, mx: "1" }),
52
+ /* @__PURE__ */ jsxRuntime.jsx(components.Shimmer, { h: "8", w: "20" })
53
+ ] });
54
+ }
55
+ const breadcrumbs = generate(data);
56
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { dflex: true, alignItems: "center", trait: "typo.h5", ...props, children: breadcrumbs.map((b, index) => /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbItem, { breadcrumb: b, showSeparator: index > 0 }, index)) });
57
+ }
58
+ function BreadcrumbItem({ breadcrumb, showSeparator }) {
59
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
60
+ showSeparator && /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: js.mdiCircleSmall, mx: "1" }),
61
+ /* @__PURE__ */ jsxRuntime.jsx(Link, { href: `/${breadcrumb.path || "#"}`, children: /* @__PURE__ */ jsxRuntime.jsx(
62
+ "span",
63
+ {
64
+ hover_textDecoration: breadcrumb.path ? "underline" : void 0,
65
+ cursor: breadcrumb.path ? "pointer" : void 0,
66
+ children: breadcrumb.label
67
+ }
68
+ ) })
69
+ ] });
70
+ }
71
+
72
+ function DialogButton({ buildDialog, ...props }) {
73
+ const [showDialog, setShowDialog] = React.useState(false);
74
+ const onShowDialog = React.useCallback((event) => {
75
+ event?.preventDefault();
76
+ event?.stopPropagation();
77
+ setShowDialog(true);
78
+ }, [setShowDialog]);
79
+ const onCloseDialog = React.useCallback(() => {
80
+ setShowDialog(false);
81
+ }, [setShowDialog]);
82
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
83
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: onShowDialog, ...props }),
84
+ showDialog && buildDialog(onCloseDialog)
85
+ ] });
86
+ }
87
+
88
+ function ButtonBar({ children, ...props }) {
89
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { dflex: true, border: "1px", borderColor: "zinc-200", divideX: "1px", divideColor: "zinc-200", rounded: "lg", overflow: "hidden", ...props, children });
90
+ }
91
+ const ButtonBarButton = React.forwardRef(
92
+ function({ icon, children, ...props }, ref) {
93
+ return /* @__PURE__ */ jsxRuntime.jsxs(
94
+ ui.Button,
95
+ {
96
+ scheme: "dark",
97
+ size: "sm",
98
+ aspectRatio: icon && !children ? "square" : void 0,
99
+ variant: "borderless",
100
+ dflex: true,
101
+ alignItems: "center",
102
+ placeContent: "center",
103
+ corners: "square",
104
+ gap: "2",
105
+ ...props,
106
+ ref,
107
+ children: [
108
+ icon && /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icon }),
109
+ children
110
+ ]
111
+ }
112
+ );
113
+ }
114
+ );
115
+ const ButtonBarSubmitButton = React.forwardRef(
116
+ function({ useDirty, disabled, icon, children, ...props }, ref) {
117
+ const { dirty, handleSubmit } = formik.useFormikContext() ?? { dirty: false, handleSubmit: void 0};
118
+ const onSubmit = React.useCallback(() => handleSubmit(), [handleSubmit]);
119
+ return /* @__PURE__ */ jsxRuntime.jsxs(
120
+ ui.Button,
121
+ {
122
+ scheme: "dark",
123
+ size: "sm",
124
+ aspectRatio: icon && !children ? "square" : void 0,
125
+ variant: "borderless",
126
+ dflex: true,
127
+ alignItems: "center",
128
+ placeContent: "center",
129
+ corners: "square",
130
+ gap: "2",
131
+ disabled: useDirty && !dirty || disabled,
132
+ onClick: onSubmit,
133
+ ...props,
134
+ ref,
135
+ children: [
136
+ icon && /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icon }),
137
+ children
138
+ ]
139
+ }
140
+ );
141
+ }
142
+ );
143
+ function ButtonBarDialogButton({ icon, children, ...props }) {
144
+ return /* @__PURE__ */ jsxRuntime.jsxs(
145
+ DialogButton,
146
+ {
147
+ scheme: "dark",
148
+ size: "sm",
149
+ aspectRatio: icon && !children ? "square" : void 0,
150
+ variant: "borderless",
151
+ dflex: true,
152
+ alignItems: "center",
153
+ placeContent: "center",
154
+ corners: "square",
155
+ gap: "2",
156
+ ...props,
157
+ children: [
158
+ icon && /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icon }),
159
+ children
160
+ ]
161
+ }
162
+ );
163
+ }
164
+
165
+ function InvalidateButton({ pathOrPermalink, ...props }) {
166
+ const api$1 = adminApi.INVALIDATE_API.new(pathOrPermalink);
167
+ const mutation = api.useApiMutation(api$1.invalidate, api$1.queryKey);
168
+ const invalidate = api.useMutate(mutation, { successMsg: "Page successfully invalidated" });
169
+ return /* @__PURE__ */ jsxRuntime.jsx(
170
+ ButtonBarButton,
171
+ {
172
+ title: "Regenerate",
173
+ disabled: mutation.isLoading,
174
+ onClick: invalidate,
175
+ icon: js.mdiDatabaseRefreshOutline,
176
+ ...props
177
+ }
178
+ );
179
+ }
180
+
181
+ function NavigateButton({ path, ...props }) {
182
+ const navigate = reactRouterDom.useNavigate();
183
+ const handleClick = React.useCallback(() => {
184
+ navigate(path);
185
+ }, [navigate, path]);
186
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", scheme: "dark", variant: "glass", corners: "pill", w: "10", h: "10", onClick: handleClick, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: js.mdiPost }) });
187
+ }
188
+
189
+ function PublishButton({
190
+ status,
191
+ queryId,
192
+ api: api$1,
193
+ ...props
194
+ }) {
195
+ const isDraft = status == "draft";
196
+ const mutation = api.useInvalidateMutation(isDraft ? api$1.publish : api$1.unpublish, api$1.queryKey, queryId, { networkMode: "always" });
197
+ const publish = React.useCallback(() => {
198
+ mutation.reset();
199
+ mutation.mutateAsync(queryId).then(() => reactToastify.toast.success(isDraft ? "Published!" : "Unpublished!")).catch((error) => reactToastify.toast.error(`Error: ${error}`));
200
+ }, [mutation, queryId]);
201
+ return /* @__PURE__ */ jsxRuntime.jsx(
202
+ ButtonBarButton,
203
+ {
204
+ disabled: mutation.isLoading,
205
+ onClick: publish,
206
+ icon: isDraft ? js.mdiEye : js.mdiEyeOff,
207
+ ...props,
208
+ children: isDraft ? "Publish" : "Switch to draft"
209
+ }
210
+ );
211
+ }
212
+
213
+ function UpdateButton({ ...props }) {
214
+ const { dirty, handleSubmit } = formik.useFormikContext() ?? { dirty: false, handleSubmit: void 0};
215
+ reactHotkeysHook.useHotkeys("ctrl+s", () => {
216
+ if (dirty && !props.disabled) handleSubmit();
217
+ }, { preventDefault: true }, [dirty, props, handleSubmit]);
218
+ return /* @__PURE__ */ jsxRuntime.jsx(ButtonBarSubmitButton, { icon: js.mdiCloudUpload, ...props, children: "Update" });
219
+ }
220
+
221
+ function ViewButton({ label, path, icon, ...props }) {
222
+ const openPage = React.useCallback(() => {
223
+ window.open(path, "_blank");
224
+ }, [path]);
225
+ return /* @__PURE__ */ jsxRuntime.jsx(
226
+ ButtonBarButton,
227
+ {
228
+ onClick: openPage,
229
+ dflex: true,
230
+ alignItems: "center",
231
+ gap: "2",
232
+ icon: icon || js.mdiOpenInNew,
233
+ ...props,
234
+ children: label
235
+ }
236
+ );
237
+ }
238
+
239
+ function OrderCell({ api: api$1, postId, order }) {
240
+ const mutationDown = api.useInvalidateMutation(api$1.moveDown, api$1.queryKey);
241
+ const mutationUp = api.useInvalidateMutation(api$1.moveUp, api$1.queryKey);
242
+ const moveDown = React.useCallback((e) => {
243
+ e.stopPropagation();
244
+ mutationDown.mutateAsync(postId).catch((error) => {
245
+ reactToastify.toast.error(`Error: ${error}`);
246
+ });
247
+ }, [mutationDown, postId]);
248
+ const moveUp = React.useCallback((e) => {
249
+ e.stopPropagation();
250
+ mutationUp.mutateAsync(postId).catch((error) => {
251
+ reactToastify.toast.error(`Error: ${error}`);
252
+ });
253
+ }, [mutationUp, postId]);
254
+ return /* @__PURE__ */ jsxRuntime.jsxs(components.FlexCenter, { placeContent: "start", numericFontVariant: "tabular-nums", children: [
255
+ order,
256
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { ms: "3", variant: "borderless", scheme: "dark", onClick: moveUp, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: js.mdiArrowUpBoldBox }) }),
257
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "borderless", scheme: "dark", onClick: moveDown, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: js.mdiArrowDownBoldBox }) })
258
+ ] });
259
+ }
260
+
261
+ function PageContainer({ children, ...props }) {
262
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { center: true, dflex: true, flexCol: true, gap: "8", ...props, children });
263
+ }
264
+
265
+ function PageMain({ children, ...props }) {
266
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Tile, { scheme: "light", p: "5", ...props, children });
267
+ }
268
+
269
+ function PageContentEditor({ name, ...props }) {
270
+ const extensions = [editor.ImageExtension];
271
+ return /* @__PURE__ */ jsxRuntime.jsx(PageMain, { h: "min", ...props, children: /* @__PURE__ */ jsxRuntime.jsx(
272
+ formEditor.FormEditor,
273
+ {
274
+ minH: "128",
275
+ minW: "144",
276
+ maxW: props.maxW,
277
+ name,
278
+ placeHolder: "Write here...",
279
+ extensions
280
+ }
281
+ ) });
282
+ }
283
+
284
+ function PageQueryStateContainerInner({ queryId, api: api$1, apiFn, loadingStyles, errorStyles, children, ...props }) {
285
+ const { data, isLoading, isError } = apiFn == "getAll" ? api.useApiQuery(api$1.queryKey, api$1.getAll, props.apiParams) : api.useApiQuery(api$1.queryKey, api$1.get, queryId);
286
+ const invalidate = api.useInvalidateQuery(api$1.queryKey, queryId);
287
+ if (isLoading)
288
+ return /* @__PURE__ */ jsxRuntime.jsx(components.QueryLoadingState, { w: "full", h: "100%", ...loadingStyles });
289
+ if (isError)
290
+ return /* @__PURE__ */ jsxRuntime.jsx(components.RetryOnError, { p: "0", onClick: invalidate, ...errorStyles });
291
+ return /* @__PURE__ */ jsxRuntime.jsx(PageContainer, { ...props, children: apiFn == "get" ? children(data) : children(data) });
292
+ }
293
+ const PageQueryStateContainer = React.forwardRef(PageQueryStateContainerInner);
294
+
295
+ function PageSidebar({ children, ...props }) {
296
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { w: "112", minW: "112", minH: "100%", gap: "8", dflex: true, flexCol: true, ...props, children });
297
+ }
298
+
299
+ function PageSectionTitle({ children, ...props }) {
300
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { trait: "typo.h6", mb: "5", ...props, children });
301
+ }
302
+
303
+ function PageSidebarSection({ title, children, ...props }) {
304
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { w: "full", ...props, children: [
305
+ title && /* @__PURE__ */ jsxRuntime.jsx(PageSectionTitle, { children: title }),
306
+ children
307
+ ] });
308
+ }
309
+
310
+ function PageTitle({ children, ...props }) {
311
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { trait: "typo.h5", ...props, children });
312
+ }
313
+
314
+ function PageTopBar({ title, breadcrumbs, children, ...props }) {
315
+ return /* @__PURE__ */ jsxRuntime.jsxs(components.FlexCenter, { gap: "3", minH: "9", ...props, children: [
316
+ title && /* @__PURE__ */ jsxRuntime.jsx(PageTitle, { children: title }),
317
+ breadcrumbs && /* @__PURE__ */ jsxRuntime.jsx(Breadcrumbs, { breadcrumbs }),
318
+ /* @__PURE__ */ jsxRuntime.jsx("div", { flexGrow: true }),
319
+ children
320
+ ] });
321
+ }
322
+ const [CP, usePageTabbedTopBarContext] = react.createContext();
323
+ function PageTabbedTopBarProvider({ children }) {
324
+ const [containerEl, setContainerEl] = React.useState(null);
325
+ React.createRef();
326
+ return /* @__PURE__ */ jsxRuntime.jsx(CP, { value: { containerEl, setContainerEl }, children });
327
+ }
328
+ function PageTabbedTopBar({ title, breadcrumbs, children, ...props }) {
329
+ const ref = React.createRef();
330
+ const { setContainerEl } = usePageTabbedTopBarContext();
331
+ const [isSet, setIsSet] = React.useState(false);
332
+ React.useEffect(() => {
333
+ if (!isSet && ref.current) {
334
+ setContainerEl(ref.current);
335
+ setIsSet(true);
336
+ }
337
+ return () => setContainerEl(null);
338
+ }, []);
339
+ return /* @__PURE__ */ jsxRuntime.jsx(components.FlexCenter, { gap: "3", minH: "9", ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
340
+ title && /* @__PURE__ */ jsxRuntime.jsx(PageTitle, { children: title }),
341
+ breadcrumbs && /* @__PURE__ */ jsxRuntime.jsx(Breadcrumbs, { breadcrumbs }),
342
+ /* @__PURE__ */ jsxRuntime.jsx("div", { flexGrow: true }),
343
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref, dflex: true, flexRow: true, gap: "3" }),
344
+ children
345
+ ] }) });
346
+ }
347
+ function PageTopBarToolbar({ trackingRef, children }) {
348
+ const { containerEl } = usePageTabbedTopBarContext();
349
+ const [visible, setVisible] = React.useState(false);
350
+ const portal = React.useMemo(() => {
351
+ const node = containerEl;
352
+ return node;
353
+ }, [containerEl]);
354
+ const host = containerEl ?? (typeof window !== "undefined" ? document.body : void 0);
355
+ React.useLayoutEffect(() => {
356
+ if (!portal || !host)
357
+ return;
358
+ try {
359
+ if (visible)
360
+ host.appendChild(portal);
361
+ else
362
+ host.removeChild(portal);
363
+ } catch (e) {
364
+ }
365
+ return () => {
366
+ try {
367
+ host.removeChild(portal);
368
+ } catch (e) {
369
+ }
370
+ };
371
+ }, [visible, portal, host]);
372
+ const callback = React.useCallback((entries) => {
373
+ setVisible(entries[0].isVisible);
374
+ }, [children]);
375
+ React.useEffect(() => {
376
+ const opts = {
377
+ root: null,
378
+ rootMargin: "0px",
379
+ threshold: 0,
380
+ /* required options*/
381
+ trackVisibility: true,
382
+ delay: 100
383
+ };
384
+ const observerScroll = new IntersectionObserver(callback, opts);
385
+ if (trackingRef)
386
+ observerScroll.observe(trackingRef);
387
+ return () => observerScroll.disconnect();
388
+ }, [trackingRef, callback, children]);
389
+ if (host && portal)
390
+ return reactDom.createPortal(children, portal);
391
+ return null;
392
+ }
393
+
394
+ function ScreenTopBar({ tabbed, breadcrumbs, api, item, isLoading, buttonBar, trackingRef }) {
395
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
396
+ tabbed && /* @__PURE__ */ jsxRuntime.jsx(PageTopBarToolbar, { trackingRef, children: /* @__PURE__ */ jsxRuntime.jsx(Buttons$1, { api, item, isLoading, buttonBar }) }),
397
+ !tabbed && /* @__PURE__ */ jsxRuntime.jsx(PageTopBar, { breadcrumbs, children: /* @__PURE__ */ jsxRuntime.jsx(Buttons$1, { api, item, isLoading, buttonBar }) })
398
+ ] });
399
+ }
400
+ function Buttons$1({ api, item, isLoading, buttonBar }) {
401
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
402
+ buttonBar && buttonBar.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ButtonBar, { children: buttonBar.map((button, index) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
403
+ button.type === "link" && /* @__PURE__ */ jsxRuntime.jsx(ViewButton, { label: button.label, path: button.path, icon: button.icon }),
404
+ button.type === "invalidate" && /* @__PURE__ */ jsxRuntime.jsx(InvalidateButton, { pathOrPermalink: button.pathOrPermalink }),
405
+ button.type == "custom" && button.render(item)
406
+ ] }, index)) }),
407
+ /* @__PURE__ */ jsxRuntime.jsxs(ButtonBar, { children: [
408
+ api instanceof adminApi.API && /* @__PURE__ */ jsxRuntime.jsx(PublishButton, { api, queryId: item.id, status: item.status, disabled: isLoading }),
409
+ /* @__PURE__ */ jsxRuntime.jsx(UpdateButton, { disabled: isLoading })
410
+ ] })
411
+ ] });
412
+ }
413
+
414
+ function useQueryField(queryField, useNextRouter) {
415
+ if (useNextRouter) {
416
+ const router$1 = router.useRouter();
417
+ return router$1.query[queryField];
418
+ }
419
+ const { [queryField]: id } = reactRouterDom.useParams();
420
+ return id;
421
+ }
422
+ function DetailsView({ queryField, api, useNextRouter, processInput, screen, tabbed, ...props }) {
423
+ const id = useQueryField(queryField, useNextRouter);
424
+ const ref = React.useRef(null);
425
+ return /* @__PURE__ */ jsxRuntime.jsx(PageQueryStateContainer, { api, apiFn: "get", queryId: id, ref, p: "5", ...props, children: (item) => /* @__PURE__ */ jsxRuntime.jsx(Internal, { item, screen, api, tabbed, processInput, containerRef: ref }) });
426
+ }
427
+ function Internal({ item, screen, api: api$1, processInput, tabbed, containerRef }) {
428
+ const pScreen = react.runIfFn(screen, item);
429
+ const { breadcrumbs, schema, initialValues, header, sections, buttonBar, type, invalidateParentQueryKey, invalidatePage } = pScreen;
430
+ const mutation = api.useInvalidateParentMutation(api$1.update, invalidateParentQueryKey ?? api$1.queryKey, { networkMode: "always" });
431
+ const invalidatePageFn = adminApi.useInvalidatePage(invalidatePage || "");
432
+ const save = api.useMutate(mutation, {
433
+ processInput,
434
+ successMsg: (item2, values) => `${item2.title || item2.name} updated.`,
435
+ errorMsg: (error, item2) => `Error updating ${item2.title || item2.name}: ${error}`,
436
+ onSuccess: () => {
437
+ if (invalidatePage)
438
+ invalidatePageFn();
439
+ }
440
+ });
441
+ let editorMaxW = void 0;
442
+ if (!type || type == "post")
443
+ editorMaxW = "calc(1280px - 28rem)";
444
+ else if (type == "section")
445
+ editorMaxW = "calc(1280px - 22rem)";
446
+ return /* @__PURE__ */ jsxRuntime.jsxs(
447
+ form.FormProvider,
448
+ {
449
+ initialValues: react.runIfFn(initialValues, item),
450
+ validationSchema: schema,
451
+ onSubmit: save,
452
+ enableReinitialize: true,
453
+ children: [
454
+ /* @__PURE__ */ jsxRuntime.jsx(
455
+ ScreenTopBar,
456
+ {
457
+ tabbed,
458
+ api: api$1,
459
+ breadcrumbs,
460
+ buttonBar,
461
+ item,
462
+ isLoading: mutation.isLoading,
463
+ trackingRef: containerRef?.current
464
+ }
465
+ ),
466
+ type == "form" && sections?.map((section, index) => /* @__PURE__ */ jsxRuntime.jsx(Section, { section, item }, index)),
467
+ (pScreen.type == "post" || pScreen.type == "section") && /* @__PURE__ */ jsxRuntime.jsx("div", { p: "5", bgColor: "slate-100", rounded: "lg", children: /* @__PURE__ */ jsxRuntime.jsxs(PageContainer, { w: editorMaxW ? "auto" : "full", size: "x2", id: "pagecontainer", children: [
468
+ header,
469
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { dflex: true, gap: "5", children: [
470
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { dflex: true, flexCol: true, gap: "8", flexGrow: true, children: [
471
+ pScreen.editor?.type != "textarea" && // TODO Find a way to make this editor shrink in width when resizing the window...
472
+ /* @__PURE__ */ jsxRuntime.jsx(PageContentEditor, { name: "content", maxW: editorMaxW, minW: "144", shadow: true, rounded: "lg" }),
473
+ pScreen.editor?.type == "textarea" && /* @__PURE__ */ jsxRuntime.jsx(
474
+ form.TextArea,
475
+ {
476
+ name: pScreen.editor?.name,
477
+ maxW: editorMaxW,
478
+ minW: editorMaxW,
479
+ w: editorMaxW,
480
+ minH: "128",
481
+ rows: 25,
482
+ bgColor: "white",
483
+ border: "0",
484
+ shadow: true,
485
+ p: "5",
486
+ textColor: "slate-800"
487
+ }
488
+ ),
489
+ pScreen.editorFooter
490
+ ] }),
491
+ /* @__PURE__ */ jsxRuntime.jsx(PageSidebar, { children: sections?.map((section, index) => /* @__PURE__ */ jsxRuntime.jsx(Section, { section, item, cardStyle: true }, index)) })
492
+ ] })
493
+ ] }) })
494
+ ]
495
+ }
496
+ );
497
+ }
498
+ function Section({ section, item, cardStyle }) {
499
+ if (section.type === "section") {
500
+ const style = cardStyle ? {
501
+ bgColor: "white",
502
+ rounded: "lg",
503
+ p: "5",
504
+ textSize: "sm",
505
+ shadow: true
506
+ } : {};
507
+ return /* @__PURE__ */ jsxRuntime.jsx(PageSidebarSection, { title: section.title, ...style, children: /* @__PURE__ */ jsxRuntime.jsx(form.FormRenderer, { form: react.runIfFn(section.form, item) }) });
508
+ }
509
+ if (section.type === "custom")
510
+ return react.runIfFn(section.component, item);
511
+ return null;
512
+ }
513
+
514
+ function useApi(api, queryField) {
515
+ const params = reactRouterDom.useParams();
516
+ if (queryField === void 0)
517
+ return { id: void 0, api };
518
+ const { [queryField]: id } = params;
519
+ return { id, api: react.runIfFn(api, id) };
520
+ }
521
+ function QueryWrapper({
522
+ api: api$1,
523
+ queryField,
524
+ fn,
525
+ transformFn,
526
+ config,
527
+ tabbed,
528
+ ...props
529
+ }) {
530
+ const { id, api: mApi } = useApi(api$1, queryField);
531
+ const { data } = api.useApiQuery(mApi.queryKey, fn === "get" || fn === "getTransformed" ? mApi.get : mApi.getAll, react.isFunction(api$1) ? void 0 : id);
532
+ const transformedData = React.useMemo(() => {
533
+ if (data && (fn === "getTransformed" || fn === "getAllTransformed")) {
534
+ if (!transformFn)
535
+ console.warn(`QueryWrapperDialog: you forgot to pass transformFn as parameter for fn ${fn}`);
536
+ return transformFn?.(data);
537
+ }
538
+ return data;
539
+ }, [data]);
540
+ if (!data)
541
+ return null;
542
+ return /* @__PURE__ */ jsxRuntime.jsx(ScreenRenderer, { config: config(transformedData), tabbed, ...props });
543
+ }
544
+
545
+ function TabbedView({ queryField, api, screen, ...props }) {
546
+ const { [queryField]: id } = reactRouterDom.useParams();
547
+ return /* @__PURE__ */ jsxRuntime.jsx(
548
+ PageQueryStateContainer,
549
+ {
550
+ queryId: id,
551
+ api,
552
+ apiFn: "get",
553
+ p: "5",
554
+ children: (city) => {
555
+ const { breadcrumbs, tabs } = react.runIfFn(screen, city);
556
+ return /* @__PURE__ */ jsxRuntime.jsxs(PageTabbedTopBarProvider, { children: [
557
+ /* @__PURE__ */ jsxRuntime.jsx(PageTabbedTopBar, { breadcrumbs, mb: "-3" }),
558
+ /* @__PURE__ */ jsxRuntime.jsx(
559
+ components.TabContainer,
560
+ {
561
+ tabs: tabs.map((tab) => tab.label),
562
+ saveKey: `tab-${id}`,
563
+ mt: "-3",
564
+ mb: "3",
565
+ id: "fff",
566
+ children: tabs.map((tab, index) => /* @__PURE__ */ jsxRuntime.jsx(TabView, { tab }, index))
567
+ }
568
+ )
569
+ ] });
570
+ }
571
+ }
572
+ );
573
+ }
574
+ function TabView({ tab }) {
575
+ if (!tab.component && !tab.config)
576
+ throw new Error(`Screen config for tabbed view: one of your tabs does not have a component or config declared: ${tab.label}`);
577
+ if (tab.component)
578
+ return tab.component();
579
+ return /* @__PURE__ */ jsxRuntime.jsx(ScreenRenderer, { config: tab.config, tabbed: true, p: "0" });
580
+ }
581
+
582
+ const [provider$1, useContext$1] = react.createContext();
583
+ function getColId(column) {
584
+ return column.accessorKey ?? column.id;
585
+ }
586
+ function TableContainerContextProvider({ initialVisibleColumns, columns, children }) {
587
+ const [showFilters, setShowFilters] = React.useState(false);
588
+ const [showMassActions, setShowMassActions] = React.useState(false);
589
+ const [visibleColumnIds, setVisibleColumnIds] = React.useState(initialVisibleColumns ?? columns?.map((col) => getColId(col)) ?? []);
590
+ const filteredColumns = columns?.filter((col) => visibleColumnIds.includes(getColId(col))) ?? [];
591
+ const toggleColumnVisibility = React.useCallback((id) => {
592
+ const index = visibleColumnIds.indexOf(id);
593
+ if (index > -1) {
594
+ const newIds = visibleColumnIds.concat();
595
+ newIds.splice(index, 1);
596
+ setVisibleColumnIds(newIds);
597
+ } else {
598
+ setVisibleColumnIds(visibleColumnIds.concat(id));
599
+ }
600
+ }, [visibleColumnIds, setVisibleColumnIds]);
601
+ const isColumnVisible = React.useCallback((id) => {
602
+ return visibleColumnIds.includes(id);
603
+ }, [visibleColumnIds]);
604
+ const Provider = provider$1;
605
+ const value = {
606
+ showFilters,
607
+ setShowFilters,
608
+ showMassActions,
609
+ setShowMassActions,
610
+ columns: columns ?? [],
611
+ filteredColumns,
612
+ toggleColumnVisibility,
613
+ isColumnVisible
614
+ };
615
+ return /* @__PURE__ */ jsxRuntime.jsx(Provider, { value, children });
616
+ }
617
+
618
+ function TableContainer({ initialPageSize, initialVisibleColumns, columns, filtersMethod = "reactRouter", children, ...props }) {
619
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { w: "full", dflex: true, flexCol: true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(table.TableContextProvider, { initialPageSize, filtersMethod, children: /* @__PURE__ */ jsxRuntime.jsx(TableContainerContextProvider, { columns, initialVisibleColumns, children }) }) });
620
+ }
621
+
622
+ function TableCreateButton({ icon, children, ...props }) {
623
+ return /* @__PURE__ */ jsxRuntime.jsxs(ButtonBarDialogButton, { ...props, children: [
624
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icon ?? js.mdiPlusThick }),
625
+ children
626
+ ] });
627
+ }
628
+
629
+ function TableFilterButton({ ...props }) {
630
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { side: "bottom-end", modal: true, children: [
631
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { scheme: "dark", size: "sm", aspectRatio: "square", variant: "borderless", corners: "square", ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: js.mdiFilter }) }),
632
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { bgColor: "white", rounded: true, shadow: true, children: [
633
+ /* @__PURE__ */ jsxRuntime.jsx("div", { py: "3", hover_bgColor: "#ff0000", px: "5", hover_textColor: "white", children: "First Item" }),
634
+ /* @__PURE__ */ jsxRuntime.jsx("div", { py: "3", hover_bgColor: "#ff0000", px: "5", hover_textColor: "white", children: "Second Item" }),
635
+ /* @__PURE__ */ jsxRuntime.jsx("div", { py: "3", hover_bgColor: "#ff0000", px: "5", hover_textColor: "white", children: "Third Item" })
636
+ ] })
637
+ ] });
638
+ }
639
+
640
+ function TableTopBar({ title, breadcrumbs, children, ...props }) {
641
+ return /* @__PURE__ */ jsxRuntime.jsxs(
642
+ "div",
643
+ {
644
+ dflex: true,
645
+ flexRow: true,
646
+ alignItems: "center",
647
+ gap: "3",
648
+ p: "8",
649
+ ...props,
650
+ children: [
651
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
652
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { textSize: "x2", fontWeight: "600", textColor: "#3f4254", textTransform: "capitalize", children: title }),
653
+ breadcrumbs && /* @__PURE__ */ jsxRuntime.jsx(Breadcrumbs, { breadcrumbs })
654
+ ] }),
655
+ /* @__PURE__ */ jsxRuntime.jsx("div", { flexGrow: true, children: "\xA0" }),
656
+ children
657
+ ]
658
+ }
659
+ );
660
+ }
661
+
662
+ function TableFilters({ form: form$1, initialValues, schema, processInput }) {
663
+ const { showFilters } = useContext$1();
664
+ const { getFilters, setFilters } = table.useTableContext();
665
+ const handleSubmit = React.useCallback((values, actions) => {
666
+ const params = processInput?.(values) ?? values;
667
+ if (!esToolkit.isEqual(params, getFilters()))
668
+ setFilters(params);
669
+ actions.setSubmitting(false);
670
+ }, [setFilters, processInput]);
671
+ const handleReset = React.useCallback((resetForm) => {
672
+ setFilters(initialValues);
673
+ resetForm();
674
+ }, [setFilters, initialValues]);
675
+ React.useEffect(() => setFilters(initialValues), []);
676
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Collapse, { in: showFilters, style: { overflow: showFilters ? "initial" : "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { p: "8", borderT: "px", borderB: "px", borderColor: "slate-100", children: /* @__PURE__ */ jsxRuntime.jsx(
677
+ form.FormProvider,
678
+ {
679
+ initialValues: form.mergeInitialFormValues(getFilters(), initialValues),
680
+ onSubmit: handleSubmit,
681
+ validationSchema: schema,
682
+ enableReinitialize: true,
683
+ children: (props) => /* @__PURE__ */ jsxRuntime.jsxs("div", { dflex: true, gap: "3", placeContent: "start", children: [
684
+ /* @__PURE__ */ jsxRuntime.jsx(form.FormRenderer, { flexRow: true, w: "auto", form: form$1 }),
685
+ /* @__PURE__ */ jsxRuntime.jsx(Buttons, { handleReset: () => handleReset(props.resetForm) })
686
+ ] })
687
+ }
688
+ ) }) });
689
+ }
690
+ function Buttons({ handleReset }) {
691
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { dflex: true, gap: "3", children: [
692
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { dflex: true, flexCol: true, children: [
693
+ /* @__PURE__ */ jsxRuntime.jsx(form.FieldLabel, { name: "", label: "\xA0" }),
694
+ /* @__PURE__ */ jsxRuntime.jsx(form.SubmitButton, { children: "Filter" })
695
+ ] }),
696
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { dflex: true, flexCol: true, children: [
697
+ /* @__PURE__ */ jsxRuntime.jsx(form.FieldLabel, { name: "", label: "\xA0" }),
698
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { scheme: "neutral", onClick: handleReset, children: "Reset" })
699
+ ] })
700
+ ] });
701
+ }
702
+
703
+ function ActionButton$1({
704
+ label,
705
+ buttonProps,
706
+ icon,
707
+ queryKey,
708
+ queryFn,
709
+ successMsg,
710
+ errorMsg,
711
+ invalidateParent
712
+ }) {
713
+ const mutation = invalidateParent ? api.useInvalidateParentMutation(queryFn, queryKey) : api.useApiMutation(queryFn, queryKey);
714
+ const mutate = api.useMutate(
715
+ mutation,
716
+ {
717
+ successMsg,
718
+ errorMsg
719
+ }
720
+ );
721
+ return /* @__PURE__ */ jsxRuntime.jsxs(
722
+ ui.Button,
723
+ {
724
+ display: "flex",
725
+ alignItems: "center",
726
+ gap: "3",
727
+ ...buttonProps,
728
+ onClick: mutate,
729
+ disabled: mutation.isLoading,
730
+ children: [
731
+ icon && /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icon }),
732
+ label
733
+ ]
734
+ }
735
+ );
736
+ }
737
+
738
+ function TableMassActions({ actions }) {
739
+ const { ids } = table.useTableContext();
740
+ const showMassActions = ids && ids.length > 0;
741
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Collapse, { in: showMassActions, style: { overflow: showMassActions ? "initial" : "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { dflex: true, gap: "3", flexWrap: true, alignItems: "center", px: "8", pt: "5", children: actions.map((action, index) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: action.type == "button" && !action.showConfirmationDialog && /* @__PURE__ */ jsxRuntime.jsx(ActionButton$1, { label: action.label, queryFn: action.queryFn, queryKey: action.queryKey, buttonProps: action.buttonProps }) }, index)) }) });
742
+ }
743
+
744
+ const defaultErrorMsg$1 = "Oops, something went wrong...";
745
+ function nonNullValues(data) {
746
+ if (data) {
747
+ const nonNullData = { ...data };
748
+ for (const key in data)
749
+ nonNullData[key] = nonNullData[key] ?? "";
750
+ return nonNullData;
751
+ }
752
+ return data;
753
+ }
754
+ function ItemEditDialog({
755
+ initialValues,
756
+ itemLabel,
757
+ queryId = "",
758
+ api: api$1,
759
+ queryFetchOptions,
760
+ querySaveOptions,
761
+ onSuccess,
762
+ onFetchError,
763
+ fetchErrorMsg = defaultErrorMsg$1,
764
+ onSaveError,
765
+ saveErrorMsg = defaultErrorMsg$1,
766
+ fetchToFormData,
767
+ formToQueryData,
768
+ invalidateQueriesOnSuccess = true,
769
+ invalidateQueryKey,
770
+ retryText = "Retry",
771
+ cancelLabel = "Cancel",
772
+ saveLabel,
773
+ size = "lg",
774
+ title,
775
+ form: form$1,
776
+ show,
777
+ onClose,
778
+ formikProps,
779
+ ...props
780
+ }) {
781
+ const { isInitialLoading, isFetching, data, isError, error, refetch } = api.useApiQuery(api$1.queryKey, api$1.get, queryId, {
782
+ enabled: !/*queryId == 0 || */
783
+ (queryId == "" || queryId == null || queryId == void 0),
784
+ // means than this query is only enabled if the id is defined
785
+ onError: onFetchError,
786
+ ...queryFetchOptions
787
+ });
788
+ const mutation = invalidateQueriesOnSuccess ? api.useInvalidateParentMutation(api$1.upsert, invalidateQueryKey ?? api$1.queryKey, querySaveOptions) : api.useApiMutation(api$1.upsert, api$1.queryKey, queryId, querySaveOptions);
789
+ const retry = React.useCallback(() => refetch(), [refetch]);
790
+ const saveItem = React.useCallback(async (item, actions) => {
791
+ mutation.reset();
792
+ const formItem = formToQueryData ? formToQueryData(item) : { ...item };
793
+ await mutation.mutateAsync(formItem).then((response) => {
794
+ if (onSuccess)
795
+ onSuccess(formItem, response);
796
+ else
797
+ reactToastify.toast.success(`${title ? title(formItem) : formItem.name ?? formItem.title} ${queryId ? "saved" : "created"}`);
798
+ onClose?.();
799
+ }).catch((error2) => {
800
+ console.error("on error", error2);
801
+ if (onSaveError)
802
+ onSaveError(item);
803
+ else
804
+ reactToastify.toast.error(`Couldn't save ${title ? title(formItem) : formItem.name ?? formItem.title}`);
805
+ actions.setSubmitting(false);
806
+ });
807
+ }, [mutation, formToQueryData, onSuccess, onSaveError, onClose]);
808
+ return /* @__PURE__ */ jsxRuntime.jsxs(
809
+ ui.Modal,
810
+ {
811
+ size,
812
+ show,
813
+ onClose,
814
+ scheme: "light",
815
+ transition: true,
816
+ ...props,
817
+ children: [
818
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Modal.Header, { children: [
819
+ !isInitialLoading && queryId && `Edit ${title ? title(data) : data?.["name"] ?? data?.["title"] ?? data?.["name"] ?? ""}`,
820
+ !queryId && `Create new ${itemLabel ?? "item"}`,
821
+ Array.isArray(form$1) && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {})
822
+ ] }),
823
+ isInitialLoading && /* @__PURE__ */ jsxRuntime.jsx(ui.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(components.QueryLoadingState, { minW: "72" }) }),
824
+ isError && /* @__PURE__ */ jsxRuntime.jsx(ui.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(components.RetryOnError, { label: `${fetchErrorMsg} ${error}`, onClick: retry }) }),
825
+ !isInitialLoading && !isError && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
826
+ formik.Formik,
827
+ {
828
+ initialValues: fetchToFormData && queryId && data ? fetchToFormData(nonNullValues(data)) : nonNullValues(initialValues(data)) ?? {},
829
+ onSubmit: saveItem,
830
+ ...formikProps,
831
+ children: ({ setFieldValue, dirty, handleSubmit, isValid, values }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
832
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Modal.Body, { pb: "6", children: /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
833
+ React.isValidElement(form$1) && form$1,
834
+ Array.isArray(form$1) && /* @__PURE__ */ jsxRuntime.jsx(form.FormRenderer, { form: form$1 }),
835
+ react.isFunction(form$1) && /* @__PURE__ */ jsxRuntime.jsx(form.FormRenderer, { form: form$1(data ?? values) })
836
+ ] }) }),
837
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Modal.Footer, { dflex: true, placeContent: "end", spaceX: "3", children: [
838
+ /* @__PURE__ */ jsxRuntime.jsx(
839
+ ui.Button,
840
+ {
841
+ disabled: mutation.isLoading,
842
+ onClick: onClose,
843
+ variant: "borderless",
844
+ me: "2",
845
+ children: cancelLabel
846
+ }
847
+ ),
848
+ /* @__PURE__ */ jsxRuntime.jsx(
849
+ ui.Button,
850
+ {
851
+ type: "submit",
852
+ disabled: !dirty || mutation.isLoading,
853
+ onClick: () => handleSubmit(),
854
+ children: saveLabel ? saveLabel : queryId ? "Update" : "Create"
855
+ }
856
+ )
857
+ ] })
858
+ ] })
859
+ }
860
+ ) }),
861
+ mutation.isLoading && /* @__PURE__ */ jsxRuntime.jsx(components.ModalLoadingOverlay, {})
862
+ ]
863
+ }
864
+ );
865
+ }
866
+
867
+ function QueryWrapperDialog({ api: api$1, fn, transformFn, config, onClose, queryId, invalidateQueryKey }) {
868
+ const { data, isFetching } = api.useApiQuery(
869
+ api$1.queryKey,
870
+ fn === "get" || fn === "getTransformed" ? api$1.get : api$1.getAll,
871
+ void 0,
872
+ { retryOnMount: false, refetchOnMount: false, refetchOnWindowFocus: false }
873
+ );
874
+ const transformedData = React.useMemo(() => {
875
+ if (data && (fn === "getTransformed" || fn === "getAllTransformed")) {
876
+ if (!transformFn)
877
+ console.warn(`QueryWrapperDialog: you forgot to pass transformFn as parameter for fn ${fn}`);
878
+ return transformFn?.(data);
879
+ }
880
+ return data;
881
+ }, [data, fn, transformFn]);
882
+ if (isFetching)
883
+ return null;
884
+ return /* @__PURE__ */ jsxRuntime.jsx(ItemEditDialog, { ...config(transformedData), queryId, invalidateQueryKey, show: true, onClose });
885
+ }
886
+
887
+ function MultiQueryWrapperDialog({ queries, config, onClose, queryId, invalidateQueryKey }) {
888
+ const { data, isFetching, isError } = api.useApiQueries(queries.map((q) => ({
889
+ queryKey: q.api.queryKey,
890
+ queryFn: q.fn == "get" ? q.api.get : q.api.getAll,
891
+ queryOptions: {
892
+ cacheTime: q.cache === false ? 0 : void 0,
893
+ staleTime: q.cache === false ? 0 : void 0
894
+ }
895
+ })));
896
+ const transformedData = React.useMemo(() => {
897
+ return data?.map((d, index) => queries[index]?.transformFn ? queries[index]?.transformFn?.(d) : d);
898
+ }, [data, queries]);
899
+ return /* @__PURE__ */ jsxRuntime.jsx(ItemEditDialog, { isPreloading: isFetching, ...config(...transformedData), queryId, invalidateQueryKey, show: true, onClose });
900
+ }
901
+
902
+ function DialogRenderer({ config, onClose, invalidateQueryKey, queryId }) {
903
+ const { type, ...props } = config;
904
+ if (config.type === "dialog")
905
+ return /* @__PURE__ */ jsxRuntime.jsx(ItemEditDialog, { ...props, queryId, invalidateQueryKey, show: true, onClose });
906
+ if (config.type === "query")
907
+ return /* @__PURE__ */ jsxRuntime.jsx(QueryWrapperDialog, { ...props, queryId, invalidateQueryKey, onClose });
908
+ if (config.type === "multiQuery")
909
+ return /* @__PURE__ */ jsxRuntime.jsx(MultiQueryWrapperDialog, { ...props, queryId, invalidateQueryKey, onClose });
910
+ return null;
911
+ }
912
+
913
+ function RefreshButton({ queryKey }) {
914
+ const invalidate = api.useInvalidateQuery(queryKey);
915
+ reactHotkeysHook.useHotkeys("ctrl+r", () => invalidate(), { preventDefault: true }, [invalidate]);
916
+ return /* @__PURE__ */ jsxRuntime.jsx(ButtonBarButton, { scheme: "dark", size: "sm", aspectRatio: "square", variant: "borderless", onClick: invalidate, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: js.mdiRefresh }) });
917
+ }
918
+
919
+ function ItemDeleteDialog({
920
+ title,
921
+ actionButtonLabel,
922
+ closeActionButtonLabel = "Cancel",
923
+ itemLabel,
924
+ queryId = "",
925
+ api: api$1,
926
+ apiFn,
927
+ invalidateQueriesOnSuccess = true,
928
+ invalidateQueryKey,
929
+ size = "lg",
930
+ md_boxSizing,
931
+ msg,
932
+ show,
933
+ onClose,
934
+ onSuccess,
935
+ ...props
936
+ }) {
937
+ const fn = apiFn ? api$1[apiFn] : api$1.delete;
938
+ const mutation = invalidateQueriesOnSuccess ? api.useInvalidateParentMutation(fn, invalidateQueryKey ?? api$1.queryKey) : api.useApiMutation(fn, api$1.queryKey);
939
+ const mutate = api.useMutate(mutation, { onSuccess: () => {
940
+ onClose?.();
941
+ onSuccess?.();
942
+ } });
943
+ const handleDelete = React.useCallback(() => mutate(queryId), [mutate, queryId]);
944
+ return /* @__PURE__ */ jsxRuntime.jsxs(
945
+ ui.Modal,
946
+ {
947
+ size,
948
+ show,
949
+ onClose,
950
+ scheme: "danger",
951
+ variant: "glass",
952
+ transition: true,
953
+ ...props,
954
+ children: [
955
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Modal.Header, { children: title || `Delete ${itemLabel}` }),
956
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Modal.Body, { pb: "6", children: [
957
+ !msg && `Do you really want to delete ${itemLabel}?`,
958
+ msg && react.runIfFn(msg, itemLabel)
959
+ ] }),
960
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Modal.Footer, { dflex: true, placeContent: "end", spaceX: "3", children: [
961
+ /* @__PURE__ */ jsxRuntime.jsx(
962
+ ui.Button,
963
+ {
964
+ disabled: mutation.isPending,
965
+ onClick: onClose,
966
+ variant: "borderless",
967
+ scheme: "dark",
968
+ me: "2",
969
+ children: closeActionButtonLabel
970
+ }
971
+ ),
972
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { scheme: "danger", disabled: mutation.isPending, onClick: handleDelete, children: actionButtonLabel || "Delete" })
973
+ ] }),
974
+ mutation.isPending && /* @__PURE__ */ jsxRuntime.jsx(components.ModalLoadingOverlay, {})
975
+ ]
976
+ }
977
+ );
978
+ }
979
+
980
+ const [provider, useContext] = react.createContext();
981
+ function TableViewProvider({ editView, deleteItem, queryKey, children }) {
982
+ const openLink = hooks.useOpenLink();
983
+ const navigate = reactRouterDom.useNavigate();
984
+ const [dialog, setDialog] = React.useState(null);
985
+ const onCloseDialog = React.useCallback(() => setDialog(null), [setDialog]);
986
+ const onAction = React.useCallback((action, item) => {
987
+ switch (action.type) {
988
+ case "view": {
989
+ navigate(react.runIfFn(action.path, item));
990
+ break;
991
+ }
992
+ case "link": {
993
+ openLink(`${env.AppEnv.websiteUrl()}/${react.runIfFn(action.path, item)}`);
994
+ break;
995
+ }
996
+ case "edit": {
997
+ const editConfig = react.runIfFn(editView, item);
998
+ if (editConfig) {
999
+ if (editConfig.type == "customDialog") {
1000
+ setDialog(editConfig.render({ show: true, onClose: onCloseDialog }));
1001
+ } else {
1002
+ setDialog(
1003
+ /* @__PURE__ */ jsxRuntime.jsx(
1004
+ DialogRenderer,
1005
+ {
1006
+ onClose: onCloseDialog,
1007
+ config: editConfig,
1008
+ queryId: item.id,
1009
+ invalidateQueryKey: queryKey
1010
+ }
1011
+ )
1012
+ );
1013
+ }
1014
+ }
1015
+ break;
1016
+ }
1017
+ case "delete": {
1018
+ const deleteConfig = react.runIfFn(deleteItem, item);
1019
+ setDialog(
1020
+ /* @__PURE__ */ jsxRuntime.jsx(
1021
+ ItemDeleteDialog,
1022
+ {
1023
+ show: true,
1024
+ onClose: onCloseDialog,
1025
+ queryId: item.id,
1026
+ invalidateQueryKey: queryKey,
1027
+ msg: item.msg,
1028
+ ...deleteConfig,
1029
+ itemLabel: react.runIfFn(deleteConfig.itemLabel, item)
1030
+ }
1031
+ )
1032
+ );
1033
+ break;
1034
+ }
1035
+ }
1036
+ }, [navigate, editView, deleteItem]);
1037
+ const Provider = provider;
1038
+ const value = {
1039
+ dialog,
1040
+ onAction
1041
+ };
1042
+ return /* @__PURE__ */ jsxRuntime.jsx(Provider, { value, children });
1043
+ }
1044
+
1045
+ function TableRowPublishPostButton$1({ id, api: api$1, status, invalidateQueryKey, ...props }) {
1046
+ const isDraft = status == "draft";
1047
+ const mutation = api.useInvalidateParentMutation(isDraft ? api$1.publish : api$1.unpublish, invalidateQueryKey ?? api$1.queryKey, { networkMode: "always" });
1048
+ const publish = React.useCallback((event) => {
1049
+ event?.preventDefault();
1050
+ event?.stopPropagation();
1051
+ mutation.reset();
1052
+ mutation.mutateAsync(id).then(() => reactToastify.toast.success(isDraft ? "Published!" : "Unpublished!")).catch((error) => reactToastify.toast.error(`Error: ${error}`));
1053
+ }, [mutation, id]);
1054
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "borderless", corners: "square", scheme: "dark", onClick: publish, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: isDraft ? js.mdiPublish : js.mdiPublishOff, size: "sm" }) });
1055
+ }
1056
+
1057
+ function TableRowActionButton({ icon, children, ...props }) {
1058
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1059
+ ui.Button,
1060
+ {
1061
+ dflex: true,
1062
+ alignContent: "center",
1063
+ placeContent: "center",
1064
+ py: "2.5",
1065
+ px: "3",
1066
+ h: "full",
1067
+ size: "lg",
1068
+ variant: "borderless",
1069
+ corners: "square",
1070
+ gap: "2",
1071
+ ...props,
1072
+ children: [
1073
+ icon && /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icon, size: "sm" }),
1074
+ children
1075
+ ]
1076
+ }
1077
+ );
1078
+ }
1079
+
1080
+ function TableRowActionsView({ row, onAction, rowActions, api, queryKey }) {
1081
+ const item = row.original;
1082
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { dflex: true, w: "full", alignItems: "stretch", placeContent: "end", h: "full", children: react.runIfFn(rowActions, item)?.map(
1083
+ (action, index) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
1084
+ action.type === "publish" && /* @__PURE__ */ jsxRuntime.jsx(TableRowPublishPostButton$1, { id: item.id, api: action.api ?? api, status: item.status, invalidateQueryKey: queryKey }),
1085
+ action.type == "custom" && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: action.component(item, queryKey, action.icon, action.label) }),
1086
+ !["publish", "custom"].includes(action.type) && /* @__PURE__ */ jsxRuntime.jsx(ActionButton, { onClick: () => onAction(action, item), scheme: schemes$1[action.type], children: /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icons[action.type], size: "sm" }) })
1087
+ ] }, index)
1088
+ ) });
1089
+ }
1090
+ function ActionButton({ onClick, ...props }) {
1091
+ const handleClick = React.useCallback((event) => {
1092
+ event?.preventDefault();
1093
+ event?.stopPropagation();
1094
+ onClick?.(event);
1095
+ }, [onClick]);
1096
+ return /* @__PURE__ */ jsxRuntime.jsx(
1097
+ TableRowActionButton,
1098
+ {
1099
+ onClick: handleClick,
1100
+ ...props
1101
+ }
1102
+ );
1103
+ }
1104
+ const icons = {
1105
+ "link": js.mdiOpenInNew,
1106
+ "view": js.mdiEye,
1107
+ "edit": js.mdiPencil,
1108
+ "delete": js.mdiDelete,
1109
+ "publish": js.mdiDelete,
1110
+ "custom": ""
1111
+ };
1112
+ const schemes$1 = {
1113
+ "link": "dark",
1114
+ "view": "dark",
1115
+ "edit": "dark",
1116
+ "delete": "dark",
1117
+ "publish": "dark",
1118
+ "custom": "dark"
1119
+ };
1120
+
1121
+ function useTableProps(api, table, rowActions, queryParams) {
1122
+ const navigate = reactRouterDom.useNavigate();
1123
+ const nextRouter = router.useRouter();
1124
+ const openLink = hooks.useOpenLink();
1125
+ const { onAction } = useContext();
1126
+ const { onRowClick, columns: c, ...props } = table;
1127
+ const onRowClickHandler = React.useCallback((item) => {
1128
+ const config = react.runIfFn(onRowClick, item);
1129
+ if (config) {
1130
+ switch (config.type) {
1131
+ case "navigate": {
1132
+ navigate(react.runIfFn(config.path, item) ?? "");
1133
+ break;
1134
+ }
1135
+ case "nextpush": {
1136
+ nextRouter.push(react.runIfFn(config.path, item));
1137
+ break;
1138
+ }
1139
+ case "link": {
1140
+ openLink(`${env.AppEnv.websiteUrl()}/${react.runIfFn(config.path, item)}`);
1141
+ break;
1142
+ }
1143
+ }
1144
+ }
1145
+ }, [navigate, onRowClick]);
1146
+ const columns = React.useMemo(() => {
1147
+ const columns2 = table.columns.concat([]);
1148
+ if (rowActions) {
1149
+ columns2.push(
1150
+ reactTable.createColumnHelper().display(
1151
+ {
1152
+ id: "actions",
1153
+ header: "Actions",
1154
+ cell: (props2) => /* @__PURE__ */ jsxRuntime.jsx(TableRowActionsView, { row: props2.row, onAction, rowActions, api, queryKey: api.queryKey })
1155
+ }
1156
+ )
1157
+ );
1158
+ }
1159
+ return columns2;
1160
+ }, [table, onAction, rowActions, api]);
1161
+ const tableProps = { ...props };
1162
+ tableProps.columns = columns;
1163
+ tableProps.onRowClick = onRowClickHandler;
1164
+ tableProps.queryKey = api.queryKey;
1165
+ tableProps.queryFilters = queryParams;
1166
+ tableProps.queryFn = api.search;
1167
+ return tableProps;
1168
+ }
1169
+
1170
+ function useId(queryField) {
1171
+ const params = reactRouterDom.useParams();
1172
+ if (queryField === void 0)
1173
+ return void 0;
1174
+ const { [queryField]: id } = params;
1175
+ return id;
1176
+ }
1177
+ function TableView({ queryField, title, subtitle, screen, ...props }) {
1178
+ const id = useId(queryField);
1179
+ const _screen = react.runIfFn(screen, id);
1180
+ return /* @__PURE__ */ jsxRuntime.jsx(PageContainer, { bgColor: "white", ...props, children: /* @__PURE__ */ jsxRuntime.jsx(TableContainer, { columns: _screen.table.columns, initialVisibleColumns: _screen.table.initialVisibleColumns, filtersMethod: _screen.table.filtersMethod, children: /* @__PURE__ */ jsxRuntime.jsx(TT, { id, title, subtitle, screen: _screen }) }) });
1181
+ }
1182
+ function TT({ id, title, subtitle, screen }) {
1183
+ const { setRowSelection } = table.useTableContext();
1184
+ const { api, table: table$1, filters, massActions, buttonBar, rowActions, createView, editView, deleteItem, breadcrumbs } = screen;
1185
+ const tableApi = react.runIfFn(api, id ?? "");
1186
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1187
+ /* @__PURE__ */ jsxRuntime.jsx(TableTopBar, { title, breadcrumbs, children: /* @__PURE__ */ jsxRuntime.jsx(TableButtonBar, { buttonBar, createView, editView, api: tableApi, queryKey: tableApi.queryKey, children: filters && /* @__PURE__ */ jsxRuntime.jsx(TableFilterButton, {}) }) }),
1188
+ filters && /* @__PURE__ */ jsxRuntime.jsx(
1189
+ TableFilters,
1190
+ {
1191
+ form: filters.form,
1192
+ initialValues: filters.initialValues,
1193
+ schema: filters.schema,
1194
+ processInput: filters.processInput
1195
+ }
1196
+ ),
1197
+ massActions && /* @__PURE__ */ jsxRuntime.jsx(TableMassActions, { actions: massActions.items }),
1198
+ /* @__PURE__ */ jsxRuntime.jsxs(TableViewProvider, { queryKey: tableApi.queryKey, editView, deleteItem, children: [
1199
+ /* @__PURE__ */ jsxRuntime.jsx(TableWrapper, { table: { ...table$1, onSelectionChange: setRowSelection }, rowActions, api: tableApi, subtitle, queryParams: screen.queryParams }),
1200
+ /* @__PURE__ */ jsxRuntime.jsx(TableDialogManager, {})
1201
+ ] })
1202
+ ] });
1203
+ }
1204
+ function TableButtonBar({ buttonBar, queryKey, createView, editView, api, children }) {
1205
+ const createDialogFn = React.useCallback((data) => {
1206
+ return (onClose) => {
1207
+ const view = react.runIfFn(createView, data) ?? react.runIfFn(editView, null);
1208
+ if (view.type == "customDialog")
1209
+ return view.render({ show: true, onClose });
1210
+ else
1211
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogRenderer, { config: view, onClose, invalidateQueryKey: api.queryKey });
1212
+ };
1213
+ }, [createView, editView, api]);
1214
+ return /* @__PURE__ */ jsxRuntime.jsxs(ButtonBar, { children: [
1215
+ /* @__PURE__ */ jsxRuntime.jsx(RefreshButton, { queryKey }),
1216
+ buttonBar && buttonBar.map(
1217
+ (button, index) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
1218
+ button.type === "create" && editView && /* @__PURE__ */ jsxRuntime.jsx(
1219
+ TableCreateButton,
1220
+ {
1221
+ buildDialog: createDialogFn(button.data),
1222
+ icon: button.icon,
1223
+ children: button.label
1224
+ }
1225
+ ),
1226
+ button.type === "invalidate" && /* @__PURE__ */ jsxRuntime.jsx(InvalidateButton, { pathOrPermalink: button.pathOrPermalink }),
1227
+ button.type === "custom" && button.render()
1228
+ ] }, index)
1229
+ ),
1230
+ children
1231
+ ] });
1232
+ }
1233
+ function TableWrapper({ table: table$1, subtitle, rowActions, api, queryParams }) {
1234
+ const tableProps = useTableProps(api, table$1, rowActions, queryParams);
1235
+ const _subtitle = React.useMemo(() => {
1236
+ if (!subtitle)
1237
+ return void 0;
1238
+ return (data) => {
1239
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { textSize: "lg", textColor: "#475569", fontWeight: "600", children: react.isFunction(subtitle) ? subtitle(data) : subtitle });
1240
+ };
1241
+ }, [subtitle]);
1242
+ return /* @__PURE__ */ jsxRuntime.jsx(table.Table, { ...tableProps, p: "8", title: _subtitle });
1243
+ }
1244
+ function TableDialogManager() {
1245
+ const { dialog } = useContext();
1246
+ return dialog;
1247
+ }
1248
+
1249
+ function useQueries(queries) {
1250
+ const params = reactRouterDom.useParams();
1251
+ const { data, isFetching, isError } = api.useApiQueries(queries.map((q) => {
1252
+ if (!q.queryField) {
1253
+ const api2 = react.runIfFn(q.api);
1254
+ return {
1255
+ queryKey: api2.queryKey,
1256
+ queryFn: q.fn == "get" ? api2.get : api2.getAll,
1257
+ queryParam: q.params
1258
+ };
1259
+ }
1260
+ const id = params[q.queryField];
1261
+ const api = react.runIfFn(q.api, id);
1262
+ return {
1263
+ queryKey: api.queryKey,
1264
+ queryFn: q.fn == "get" ? api.get : api.getAll,
1265
+ queryParam: q.fn == "getAll" ? q.params : react.isFunction(q.api) ? void 0 : id
1266
+ };
1267
+ }));
1268
+ let transformedData = void 0;
1269
+ if (!isFetching && !isError) {
1270
+ transformedData = data?.map((d, index) => queries[index].transformFn ? queries[index].transformFn?.(d) : d);
1271
+ }
1272
+ return { data: transformedData, isFetching, isError };
1273
+ }
1274
+ function useInvalidate(queries) {
1275
+ const queryClient = reactQuery.useQueryClient();
1276
+ const params = reactRouterDom.useParams();
1277
+ const invalidate = React.useCallback(
1278
+ () => {
1279
+ const queryKeys = [];
1280
+ queries.forEach((q) => {
1281
+ if (!q.queryField || !react.isFunction(q.api)) {
1282
+ queryKeys.push(q.api.queryKey);
1283
+ } else {
1284
+ const id = params[q.queryField];
1285
+ const api = react.runIfFn(q.api, id);
1286
+ queryKeys.push(api.queryKey);
1287
+ }
1288
+ });
1289
+ queryClient.invalidateQueries({ predicate: (query) => queryKeys.includes(query.queryKey) });
1290
+ },
1291
+ [queries, queryClient, params]
1292
+ );
1293
+ return invalidate;
1294
+ }
1295
+ function MultiQueryWrapper({
1296
+ queries,
1297
+ config,
1298
+ tabbed,
1299
+ ...props
1300
+ }) {
1301
+ const { data, isFetching, isError } = useQueries(queries);
1302
+ const invalidate = useInvalidate(queries);
1303
+ if (isFetching)
1304
+ return /* @__PURE__ */ jsxRuntime.jsx(components.QueryLoadingState, { w: "full", h: "100vh" });
1305
+ if (isError || !data)
1306
+ return /* @__PURE__ */ jsxRuntime.jsx(components.RetryOnError, { p: "0", w: "full", h: "100vh", onClick: invalidate });
1307
+ return /* @__PURE__ */ jsxRuntime.jsx(ScreenRenderer, { config: config(...data), tabbed, ...props });
1308
+ }
1309
+
1310
+ function ScreenRenderer({ config, tabbed, ...props }) {
1311
+ if (config.type === "table")
1312
+ return /* @__PURE__ */ jsxRuntime.jsx(TableView, { ...config, ...props });
1313
+ if (config.type === "tabbed")
1314
+ return /* @__PURE__ */ jsxRuntime.jsx(TabbedView, { ...config, ...props });
1315
+ if (config.type === "details")
1316
+ return /* @__PURE__ */ jsxRuntime.jsx(DetailsView, { ...config, tabbed, ...props });
1317
+ if (config.type === "query")
1318
+ return /* @__PURE__ */ jsxRuntime.jsx(QueryWrapper, { ...config, tabbed, ...props });
1319
+ if (config.type === "multiQuery")
1320
+ return /* @__PURE__ */ jsxRuntime.jsx(MultiQueryWrapper, { ...config, tabbed, ...props });
1321
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
1322
+ }
1323
+
1324
+ function Content({ ...props }) {
1325
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { w: "100%", h: "100%", overflowY: "auto", ...props, children: /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Outlet, {}) });
1326
+ }
1327
+
1328
+ function SelectedIndicator({ darkMode }) {
1329
+ return /* @__PURE__ */ jsxRuntime.jsx(
1330
+ "div",
1331
+ {
1332
+ position: "absolute",
1333
+ bgColor: darkMode ? "white" : "black",
1334
+ bgOpacity: "90",
1335
+ w: "0.5",
1336
+ h: "6",
1337
+ top: "1.5",
1338
+ start: "-4"
1339
+ }
1340
+ );
1341
+ }
1342
+
1343
+ function MenuButton({ depth, darkMode, icon, selected, children, ...props }) {
1344
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1345
+ ui.Button,
1346
+ {
1347
+ as: "li",
1348
+ minH: "8",
1349
+ ms: `${(depth ?? 0) * 2}`,
1350
+ p: "2",
1351
+ font: "title",
1352
+ textColor: darkMode ? "white" : "black",
1353
+ fontWeight: "600",
1354
+ rounded: "lg",
1355
+ textSize: "sm",
1356
+ variant: "borderless",
1357
+ hover_bgColor: darkMode ? "white" : "black",
1358
+ hover_bgOpacity: "10",
1359
+ hover_textColor: darkMode ? "white" : "zinc-800",
1360
+ cursor: "pointer",
1361
+ dflex: true,
1362
+ alignItems: "center",
1363
+ gap: "3",
1364
+ ...props,
1365
+ children: [
1366
+ icon && /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icon, opacity: selected ? "100" : "60" }),
1367
+ children
1368
+ ]
1369
+ }
1370
+ );
1371
+ }
1372
+
1373
+ function MenuItem$1({ icon, path, depth, darkMode, subMenu, ...props }) {
1374
+ const location = reactRouterDom.useLocation();
1375
+ const selected = path == "/" ? location.pathname == "/" : location.pathname.startsWith(path.startsWith("/") ? path : `/${path}`);
1376
+ const match = reactRouterDom.useMatch("/" + path) != null;
1377
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1378
+ /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to: path, style: { position: "relative" }, children: [
1379
+ /* @__PURE__ */ jsxRuntime.jsx(
1380
+ MenuButton,
1381
+ {
1382
+ depth,
1383
+ darkMode,
1384
+ icon,
1385
+ selected,
1386
+ ...props
1387
+ }
1388
+ ),
1389
+ match && /* @__PURE__ */ jsxRuntime.jsx(SelectedIndicator, { darkMode })
1390
+ ] }),
1391
+ subMenu?.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
1392
+ MenuItem$1,
1393
+ {
1394
+ icon: item.icon,
1395
+ path: item.path,
1396
+ depth: (depth ?? 0) + 1,
1397
+ darkMode,
1398
+ subMenu: item.children,
1399
+ children: item.label
1400
+ },
1401
+ index
1402
+ ))
1403
+ ] });
1404
+ }
1405
+
1406
+ function NextMenuItem({ icon, path, depth, darkMode, subMenu, ...props }) {
1407
+ const { pathname } = router.useRouter();
1408
+ const selected = path == "/" ? pathname == "/" : pathname.startsWith(path.startsWith("/") ? path : `/${path}`);
1409
+ const match = path == "/" ? pathname == "/" : pathname == (path.startsWith("/") ? path : `/${path}`);
1410
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1411
+ /* @__PURE__ */ jsxRuntime.jsxs(Link, { href: path, style: { position: "relative" }, children: [
1412
+ /* @__PURE__ */ jsxRuntime.jsx(
1413
+ MenuButton,
1414
+ {
1415
+ depth,
1416
+ darkMode,
1417
+ icon,
1418
+ selected,
1419
+ ...props
1420
+ }
1421
+ ),
1422
+ match && /* @__PURE__ */ jsxRuntime.jsx(SelectedIndicator, { darkMode })
1423
+ ] }),
1424
+ subMenu?.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
1425
+ NextMenuItem,
1426
+ {
1427
+ icon: item.icon,
1428
+ path: item.path,
1429
+ depth: (depth ?? 0) + 1,
1430
+ darkMode,
1431
+ subMenu: item.children,
1432
+ children: item.label
1433
+ },
1434
+ index
1435
+ ))
1436
+ ] });
1437
+ }
1438
+
1439
+ function Menu({ darkMode, config, useNextRouter, ...props }) {
1440
+ const Comp = useNextRouter ? NextMenuItem : MenuItem$1;
1441
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { ...props, children: config.map((item, index) => {
1442
+ if (item.type == "divider")
1443
+ return /* @__PURE__ */ jsxRuntime.jsx(Divider, { title: item.label }, index);
1444
+ if (item.type == "item") {
1445
+ return /* @__PURE__ */ jsxRuntime.jsx(
1446
+ Comp,
1447
+ {
1448
+ icon: item.icon,
1449
+ path: item.path,
1450
+ depth: 0,
1451
+ darkMode,
1452
+ subMenu: item.children,
1453
+ children: item.label
1454
+ },
1455
+ index
1456
+ );
1457
+ }
1458
+ }) });
1459
+ }
1460
+ function Divider({ title }) {
1461
+ return /* @__PURE__ */ jsxRuntime.jsx(
1462
+ "div",
1463
+ {
1464
+ px: "2",
1465
+ mt: "5",
1466
+ mb: "2",
1467
+ opacity: "75",
1468
+ textTransform: "capitalize",
1469
+ letterSpacing: "widest",
1470
+ fontWeight: "700",
1471
+ textSize: "xs",
1472
+ children: title
1473
+ }
1474
+ );
1475
+ }
1476
+
1477
+ function UserBlock({ color, darkMode, menuConfig, path }) {
1478
+ const { isLoading, user } = auth.useSessionUser();
1479
+ const navigate = reactRouterDom.useNavigate();
1480
+ const handleClick = React.useCallback(() => navigate(path), [navigate, path]);
1481
+ if (isLoading)
1482
+ return null;
1483
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1484
+ "div",
1485
+ {
1486
+ dflex: true,
1487
+ alignItems: "center",
1488
+ border: "0.5",
1489
+ borderColor: `${color}-${darkMode ? "800" : "200"}`,
1490
+ ps: "3",
1491
+ py: "1.5",
1492
+ textSize: "md",
1493
+ rounded: "lg",
1494
+ hover_bgColor: `${color}-${darkMode ? "800" : "200"}`,
1495
+ cursor: "pointer",
1496
+ textColor: darkMode ? "white" : "slate-800",
1497
+ onClick: handleClick,
1498
+ children: [
1499
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Avatar, { size: "sm", src: user?.media?.url ?? "", name: `${user?.firstname} ${user?.lastname}` }),
1500
+ /* @__PURE__ */ jsxRuntime.jsx("span", { flexGrow: true, ms: "2", children: `${esToolkit.capitalize(user?.firstname || user?.lastname || "")}` }),
1501
+ /* @__PURE__ */ jsxRuntime.jsx(
1502
+ ui.IconButton,
1503
+ {
1504
+ variant: "borderless",
1505
+ corners: "pill",
1506
+ scheme: "dark",
1507
+ textColor: darkMode ? "white" : "slate-800",
1508
+ hover_textColor: darkMode ? "white" : "slate-800",
1509
+ hover_bgColor: `${color}-${darkMode ? "900" : "200"}`,
1510
+ icon: js.mdiCog,
1511
+ onClick: handleClick
1512
+ }
1513
+ ),
1514
+ /* @__PURE__ */ jsxRuntime.jsx(OverflowMenu, { color, darkMode, menuConfig })
1515
+ ]
1516
+ }
1517
+ );
1518
+ }
1519
+ function OverflowMenu({ color, darkMode, menuConfig }) {
1520
+ const [showPopup, setShowPopup] = React.useState(false);
1521
+ const navigate = reactRouterDom.useNavigate();
1522
+ const logout = auth.useSessionLogout(false);
1523
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1524
+ ui.Popup,
1525
+ {
1526
+ show: showPopup,
1527
+ position: "relative",
1528
+ side: "bottom-end",
1529
+ onClick: (e) => {
1530
+ e.preventDefault();
1531
+ e.stopPropagation();
1532
+ setShowPopup((show) => !show);
1533
+ },
1534
+ onHide: () => setShowPopup(false),
1535
+ children: [
1536
+ /* @__PURE__ */ jsxRuntime.jsx(
1537
+ ui.IconButton,
1538
+ {
1539
+ icon: js.mdiDotsVertical,
1540
+ variant: "borderless",
1541
+ corners: "pill",
1542
+ scheme: "dark",
1543
+ textColor: darkMode ? "white" : "slate-800",
1544
+ hover_textColor: darkMode ? "white" : "slate-800",
1545
+ hover_bgColor: `${color}-${darkMode ? "900" : "200"}`
1546
+ }
1547
+ ),
1548
+ /* @__PURE__ */ jsxRuntime.jsxs(
1549
+ "div",
1550
+ {
1551
+ bgColor: "white",
1552
+ rounded: "sm",
1553
+ overflow: "hidden",
1554
+ shadow: true,
1555
+ mt: "1",
1556
+ border: "px",
1557
+ borderColor: "gray-200",
1558
+ divideColor: "gray-200",
1559
+ divideY: "px",
1560
+ minW: "40",
1561
+ children: [
1562
+ menuConfig && menuConfig.length > 0 && menuConfig.map((item, index) => {
1563
+ if (item.type == "item") {
1564
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuItem, { icon: item.icon, onClick: () => navigate(item.path), children: item.label }, index);
1565
+ }
1566
+ return null;
1567
+ }),
1568
+ /* @__PURE__ */ jsxRuntime.jsx(MenuItem, { icon: js.mdiLogout, onClick: logout, children: "Logout" })
1569
+ ]
1570
+ }
1571
+ )
1572
+ ]
1573
+ }
1574
+ ) });
1575
+ }
1576
+ function MenuItem({ icon, onClick, children, ...props }) {
1577
+ const handleClick = React.useCallback((e) => {
1578
+ e.preventDefault();
1579
+ e.stopPropagation();
1580
+ onClick?.(e);
1581
+ }, []);
1582
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1583
+ ui.Button,
1584
+ {
1585
+ variant: "borderless",
1586
+ scheme: "dark",
1587
+ size: "sm",
1588
+ alignItems: "center",
1589
+ dflex: true,
1590
+ gap: "2",
1591
+ px: "2",
1592
+ py: "1.5",
1593
+ w: "full",
1594
+ onClick: handleClick,
1595
+ textColor: "slate-700",
1596
+ ...props,
1597
+ children: [
1598
+ icon && /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icon, size: "md" }),
1599
+ children
1600
+ ]
1601
+ }
1602
+ );
1603
+ }
1604
+
1605
+ function Sidebar({ show, logo, title, menuConfig, userMenuConfig, userSettingsPath, color, darkMode, ...props }) {
1606
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1607
+ "div",
1608
+ {
1609
+ dflex: true,
1610
+ flexCol: true,
1611
+ w: "full",
1612
+ md_w: "64",
1613
+ minH: "screen",
1614
+ p: "0",
1615
+ textColor: darkMode ? "white" : "slate-800",
1616
+ ...props,
1617
+ children: [
1618
+ /* @__PURE__ */ jsxRuntime.jsxs(
1619
+ components.FlexCenter,
1620
+ {
1621
+ placeContent: "start",
1622
+ p: "4",
1623
+ font: "title",
1624
+ gap: "3",
1625
+ borderB: "px",
1626
+ borderBColor: "slate-900",
1627
+ borderOpacity: "5",
1628
+ children: [
1629
+ logo ?? /* @__PURE__ */ jsxRuntime.jsx(Logo, { width: 40, height: 40, darkMode }),
1630
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { textSize: "md", children: title || env.AppEnv.appName() })
1631
+ ]
1632
+ }
1633
+ ),
1634
+ /* @__PURE__ */ jsxRuntime.jsx(Menu, { overflowY: "auto", flexGrow: "1", p: "4", darkMode, config: menuConfig }),
1635
+ /* @__PURE__ */ jsxRuntime.jsx("div", { p: "2", children: /* @__PURE__ */ jsxRuntime.jsx(UserBlock, { darkMode, color, menuConfig: userMenuConfig, path: userSettingsPath }) })
1636
+ ]
1637
+ }
1638
+ );
1639
+ }
1640
+ function Logo({ width, height, darkMode, ...props }) {
1641
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ...props, children: /* @__PURE__ */ jsxRuntime.jsx(
1642
+ Image,
1643
+ {
1644
+ src: `/logo_${darkMode ? "light" : "dark"}.png`,
1645
+ alt: env.AppEnv.appName() || "",
1646
+ width,
1647
+ height,
1648
+ priority: true,
1649
+ unoptimized: true
1650
+ }
1651
+ ) });
1652
+ }
1653
+
1654
+ function AdminLayout({ color, darkMode, logo, title, menuConfig, userMenuConfig, userSettingsPath, ...props }) {
1655
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1656
+ "div",
1657
+ {
1658
+ w: "full",
1659
+ h: "screen",
1660
+ dflex: true,
1661
+ flexRow: true,
1662
+ bgColor: `${color}-${darkMode ? "900" : "100"}`,
1663
+ ...props,
1664
+ children: [
1665
+ /* @__PURE__ */ jsxRuntime.jsx(
1666
+ LeftPanel,
1667
+ {
1668
+ color,
1669
+ darkMode,
1670
+ logo,
1671
+ title,
1672
+ menuConfig,
1673
+ userMenuConfig,
1674
+ userSettingsPath
1675
+ }
1676
+ ),
1677
+ /* @__PURE__ */ jsxRuntime.jsx("div", { w: "screen", py: "2", pe: "2", children: /* @__PURE__ */ jsxRuntime.jsx(Content, { bgColor: "white", rounded: "lg", shadow: true }) })
1678
+ ]
1679
+ }
1680
+ );
1681
+ }
1682
+ function LeftPanel({ color, darkMode, logo, title, menuConfig, userMenuConfig, userSettingsPath }) {
1683
+ const [isOpen, __, toggle] = hooks.useBoolean(true);
1684
+ reactHotkeysHook.useHotkeys("ctrl+t", () => toggle(), [toggle]);
1685
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1686
+ "div",
1687
+ {
1688
+ ms: isOpen ? "0" : "-14.5rem",
1689
+ transition: "all",
1690
+ duration: "500",
1691
+ transform: true,
1692
+ children: [
1693
+ /* @__PURE__ */ jsxRuntime.jsx(
1694
+ Sidebar,
1695
+ {
1696
+ flexShrink: "0",
1697
+ color,
1698
+ darkMode,
1699
+ logo,
1700
+ title,
1701
+ menuConfig,
1702
+ userMenuConfig,
1703
+ userSettingsPath
1704
+ }
1705
+ ),
1706
+ /* @__PURE__ */ jsxRuntime.jsx(
1707
+ ui.IconButton,
1708
+ {
1709
+ icon: js.mdiArrowLeft,
1710
+ transition: "all",
1711
+ duration: "500",
1712
+ transform: true,
1713
+ rotate: isOpen ? "0" : "180",
1714
+ position: "absolute",
1715
+ bottom: "14",
1716
+ end: "-5",
1717
+ size: "lg",
1718
+ corners: "pill",
1719
+ onClick: toggle,
1720
+ z: "100"
1721
+ }
1722
+ )
1723
+ ]
1724
+ }
1725
+ );
1726
+ }
1727
+
1728
+ const defaultErrorMsg = "Oops, something went wrong...";
1729
+ function AttachDialog({
1730
+ queryId,
1731
+ queryKey,
1732
+ queryFetchFn,
1733
+ queryFetchAllKey,
1734
+ queryFetchAllFn,
1735
+ querySaveFn,
1736
+ matchKey,
1737
+ size = "lg",
1738
+ show,
1739
+ onClose,
1740
+ itemLabel,
1741
+ onSuccess,
1742
+ onFetchError,
1743
+ fetchErrorMsg = defaultErrorMsg,
1744
+ onSaveError,
1745
+ saveErrorMsg = defaultErrorMsg,
1746
+ invalidateQueriesOnSuccess = true,
1747
+ retryText = "Retry",
1748
+ cancelLabel = "Cancel",
1749
+ saveLabel,
1750
+ formikProps,
1751
+ getItemName,
1752
+ ...props
1753
+ }) {
1754
+ const queryClient = reactQuery.useQueryClient();
1755
+ const { data: attached, isInitialLoading: fetchLoading, isError: fetchError, refetch, error } = api.useApiQuery(queryKey, queryFetchFn);
1756
+ const { data, isInitialLoading: fetchAllLoading, isError: fetchAllError, refetch: refetchAll, error: errorAll } = api.useApiQuery(queryFetchAllKey, queryFetchAllFn);
1757
+ const [selectedResources, setSelectedResources] = React.useState([]);
1758
+ const isLoading = fetchLoading || fetchAllLoading;
1759
+ const isError = fetchError || fetchAllError;
1760
+ const mutation = api.useApiMutation(querySaveFn, queryKey, queryId);
1761
+ const handleClick = React.useCallback((event) => {
1762
+ const id = event?.currentTarget.dataset.id ?? "";
1763
+ const arr = selectedResources.concat([]);
1764
+ const i = selectedResources.indexOf(id);
1765
+ if (i != -1)
1766
+ arr.splice(i, 1);
1767
+ else
1768
+ arr.push(id);
1769
+ setSelectedResources(arr);
1770
+ }, [selectedResources, setSelectedResources]);
1771
+ const retry = React.useCallback(() => {
1772
+ if (fetchError)
1773
+ refetch();
1774
+ if (fetchAllError)
1775
+ refetchAll();
1776
+ }, [refetch, refetchAll, fetchError, fetchAllError]);
1777
+ const saveItem = React.useCallback(() => {
1778
+ mutation.reset();
1779
+ mutation.mutateAsync({ resources: selectedResources }).then((response) => {
1780
+ if (onSuccess)
1781
+ onSuccess(response);
1782
+ else
1783
+ reactToastify.toast.success(`${itemLabel} saved`);
1784
+ if (invalidateQueriesOnSuccess)
1785
+ queryClient.invalidateQueries({ queryKey });
1786
+ onClose?.();
1787
+ }).catch((error2) => {
1788
+ console.error("on error", error2);
1789
+ if (onSaveError)
1790
+ onSaveError();
1791
+ else
1792
+ reactToastify.toast.error(`Error adding ${itemLabel}`);
1793
+ });
1794
+ }, [mutation, queryId, onSuccess, queryClient, onSaveError, onClose]);
1795
+ const resources = React.useMemo(() => {
1796
+ let r = [];
1797
+ if (attached && data) {
1798
+ r = [].concat(data);
1799
+ attached.forEach((attachedItem) => r.splice(r.findIndex((item) => item.id == attachedItem[matchKey]), 1));
1800
+ if (getItemName)
1801
+ r = r.map((item) => {
1802
+ return { ...item, name: getItemName(item) };
1803
+ });
1804
+ r = esToolkit.sortBy(r, ["name"]);
1805
+ }
1806
+ return r;
1807
+ }, [attached, data]);
1808
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1809
+ ui.Modal,
1810
+ {
1811
+ size,
1812
+ show,
1813
+ onClose,
1814
+ scheme: "light",
1815
+ transition: true,
1816
+ ...props,
1817
+ children: [
1818
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Modal.Header, { children: `Add ${itemLabel}` }),
1819
+ isLoading && /* @__PURE__ */ jsxRuntime.jsx(ui.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(components.QueryLoadingState, { minW: "72" }) }),
1820
+ isError && /* @__PURE__ */ jsxRuntime.jsx(ui.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(components.RetryOnError, { label: `${fetchErrorMsg} ${error}`, onClick: retry }) }),
1821
+ !isLoading && !isError && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1822
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Modal.Body, { px: "0", pb: "6", maxH: "750px", overflow: "auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { dflex: true, flexCol: true, overflow: "auto", children: resources.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1823
+ ListItem,
1824
+ {
1825
+ label: item.name,
1826
+ value: item.id,
1827
+ "data-id": item.id,
1828
+ checked: selectedResources.includes(`${item.id}`),
1829
+ onClick: handleClick
1830
+ },
1831
+ item.id
1832
+ )) }) }),
1833
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Modal.Footer, { dflex: true, placeContent: "end", spaceX: "3", children: [
1834
+ /* @__PURE__ */ jsxRuntime.jsx(
1835
+ ui.Button,
1836
+ {
1837
+ disabled: mutation.isLoading,
1838
+ onClick: onClose,
1839
+ variant: "borderless",
1840
+ me: "2",
1841
+ children: cancelLabel
1842
+ }
1843
+ ),
1844
+ /* @__PURE__ */ jsxRuntime.jsx(
1845
+ ui.Button,
1846
+ {
1847
+ type: "submit",
1848
+ disabled: selectedResources.length == 0 || mutation.isLoading,
1849
+ onClick: saveItem,
1850
+ children: saveLabel ? saveLabel : queryId ? "Update" : "Create"
1851
+ }
1852
+ )
1853
+ ] })
1854
+ ] }),
1855
+ mutation.isLoading && /* @__PURE__ */ jsxRuntime.jsx(components.ModalLoadingOverlay, {})
1856
+ ]
1857
+ }
1858
+ );
1859
+ }
1860
+ function ListItem({ label, value, checked, ...props }) {
1861
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1862
+ "div",
1863
+ {
1864
+ dflex: true,
1865
+ alignItems: "center",
1866
+ hover_bgColor: "slate-100",
1867
+ px: "5",
1868
+ py: "2",
1869
+ cursor: "pointer",
1870
+ ...props,
1871
+ children: [
1872
+ /* @__PURE__ */ jsxRuntime.jsx("span", { flexGrow: true, children: label }),
1873
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { name: `resources.${value}`, value, checked })
1874
+ ]
1875
+ }
1876
+ );
1877
+ }
1878
+
1879
+ function FormActionDialog({
1880
+ initialValues,
1881
+ itemLabel,
1882
+ queryId = "",
1883
+ queryKey,
1884
+ queryFn,
1885
+ queryOptions,
1886
+ onSuccess,
1887
+ successMsg,
1888
+ showSuccessMsg,
1889
+ onError,
1890
+ errorMsg,
1891
+ showErrorMsg,
1892
+ processInput,
1893
+ invalidateQueriesOnSuccess = true,
1894
+ cancelLabel = "Cancel",
1895
+ saveLabel = "Send",
1896
+ size = "lg",
1897
+ title,
1898
+ form: form$1,
1899
+ show,
1900
+ onClose,
1901
+ formikProps,
1902
+ ...props
1903
+ }) {
1904
+ const mutation = invalidateQueriesOnSuccess ? api.useInvalidateParentMutation(queryFn, queryKey, queryOptions) : api.useApiMutation(queryFn, queryKey, queryId, queryOptions);
1905
+ const mutate = api.useMutate(mutation, {
1906
+ onSuccess,
1907
+ successMsg,
1908
+ showSuccessMsg,
1909
+ onError,
1910
+ errorMsg,
1911
+ showErrorMsg,
1912
+ processInput
1913
+ });
1914
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1915
+ ui.Modal,
1916
+ {
1917
+ size,
1918
+ show,
1919
+ onClose,
1920
+ scheme: "light",
1921
+ transition: true,
1922
+ ...props,
1923
+ children: [
1924
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Modal.Header, { children: title }),
1925
+ /* @__PURE__ */ jsxRuntime.jsxs(
1926
+ form.FormProvider,
1927
+ {
1928
+ initialValues: initialValues ?? {},
1929
+ onSubmit: mutate,
1930
+ ...formikProps,
1931
+ children: [
1932
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Modal.Body, { pb: "6", children: [
1933
+ React.isValidElement(form$1) && form$1,
1934
+ Array.isArray(form$1) && /* @__PURE__ */ jsxRuntime.jsx(form.FormRenderer, { form: form$1 })
1935
+ ] }),
1936
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Modal.Footer, { dflex: true, placeContent: "end", spaceX: "3", children: [
1937
+ /* @__PURE__ */ jsxRuntime.jsx(
1938
+ ui.Button,
1939
+ {
1940
+ disabled: mutation.isLoading,
1941
+ onClick: onClose,
1942
+ variant: "borderless",
1943
+ me: "2",
1944
+ children: cancelLabel
1945
+ }
1946
+ ),
1947
+ /* @__PURE__ */ jsxRuntime.jsx(form.SubmitButton, { disabled: mutation.isLoading, children: saveLabel })
1948
+ ] })
1949
+ ]
1950
+ }
1951
+ ),
1952
+ mutation.isLoading && /* @__PURE__ */ jsxRuntime.jsx(components.ModalLoadingOverlay, {})
1953
+ ]
1954
+ }
1955
+ );
1956
+ }
1957
+
1958
+ const PageStateContainer = React.forwardRef(({ loading = false, children, ...props }, ref) => {
1959
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1960
+ loading && /* @__PURE__ */ jsxRuntime.jsx(components.QueryLoadingState, { w: "full", h: "100%" }),
1961
+ !loading && /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { ref, center: true, size: "x2", dflex: true, flexCol: true, gap: "8", ...props, children })
1962
+ ] });
1963
+ });
1964
+
1965
+ function PageSubSectionTitle({ children, ...props }) {
1966
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { trait: "typo.h6", mb: "3", ...props, children });
1967
+ }
1968
+
1969
+ const labels = {
1970
+ draft: "Draft",
1971
+ published: "Published",
1972
+ pending: "Pending",
1973
+ approved: "Approved",
1974
+ partially_approved: "Partially Approved",
1975
+ rejected: "Rejected"
1976
+ };
1977
+ const schemes = {
1978
+ draft: "warning",
1979
+ published: "success",
1980
+ pending: "secondary",
1981
+ approved: "success",
1982
+ partially_approved: "warning",
1983
+ rejected: "danger"
1984
+ };
1985
+ function StatusBadge({ status, ...props }) {
1986
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "sm", variant: "glass", whiteSpace: "nowrap", rounded: "full", px: "3", scheme: schemes[status], ...props, children: labels[status] });
1987
+ }
1988
+
1989
+ function TableRowViewButton({ path, ...props }) {
1990
+ const openPage = React.useCallback((event) => {
1991
+ event?.preventDefault();
1992
+ event?.stopPropagation();
1993
+ window.open(`${env.AppEnv.websiteUrl()}/${path}`, "_blank");
1994
+ }, [path]);
1995
+ return /* @__PURE__ */ jsxRuntime.jsx(TableRowActionButton, { icon: js.mdiOpenInNew, onClick: openPage, ...props });
1996
+ }
1997
+
1998
+ function TableRowNavigateButton({ path, ...props }) {
1999
+ const navigate = reactRouterDom.useNavigate();
2000
+ const handleClick = React.useCallback((event) => {
2001
+ event?.preventDefault();
2002
+ event?.stopPropagation();
2003
+ navigate(`${path}`);
2004
+ }, [navigate, path]);
2005
+ return /* @__PURE__ */ jsxRuntime.jsx(TableRowActionButton, { icon: js.mdiEye, onClick: handleClick, ...props });
2006
+ }
2007
+
2008
+ function TableRowActionDialogButton({ icon, children, ...props }) {
2009
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2010
+ DialogButton,
2011
+ {
2012
+ dflex: true,
2013
+ alignContent: "center",
2014
+ placeContent: "center",
2015
+ py: "2.5",
2016
+ px: "3",
2017
+ h: "full",
2018
+ size: "lg",
2019
+ variant: "borderless",
2020
+ corners: "square",
2021
+ gap: "2",
2022
+ ...props,
2023
+ children: [
2024
+ icon && /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { path: icon, size: "sm" }),
2025
+ children
2026
+ ]
2027
+ }
2028
+ );
2029
+ }
2030
+
2031
+ function TableRowEditButton({ children, ...props }) {
2032
+ return /* @__PURE__ */ jsxRuntime.jsx(TableRowActionDialogButton, { icon: js.mdiPencil, ...props, children });
2033
+ }
2034
+
2035
+ function TableRowDeleteButton({ children, ...props }) {
2036
+ return /* @__PURE__ */ jsxRuntime.jsx(TableRowActionDialogButton, { icon: js.mdiDelete, ...props, children });
2037
+ }
2038
+
2039
+ function TableRowActionBar({
2040
+ publishId,
2041
+ viewPath,
2042
+ navigatePath,
2043
+ editDialog,
2044
+ deleteDialog,
2045
+ children,
2046
+ ...props
2047
+ }) {
2048
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { dflex: true, spaceX: "1", placeContent: "end", ...props, children: [
2049
+ viewPath && /* @__PURE__ */ jsxRuntime.jsx(TableRowViewButton, { path: viewPath }),
2050
+ navigatePath && /* @__PURE__ */ jsxRuntime.jsx(TableRowNavigateButton, { path: navigatePath }),
2051
+ editDialog && /* @__PURE__ */ jsxRuntime.jsx(TableRowEditButton, { buildDialog: editDialog }),
2052
+ deleteDialog && /* @__PURE__ */ jsxRuntime.jsx(TableRowDeleteButton, { buildDialog: deleteDialog }),
2053
+ children
2054
+ ] });
2055
+ }
2056
+
2057
+ function TableRowPublishPostButton({ id, api: api$1, status, invalidateQueryKey, ...props }) {
2058
+ const isDraft = status == "draft";
2059
+ const mutation = api.useInvalidateParentMutation(isDraft ? api$1.publish : api$1.unpublish, invalidateQueryKey ?? api$1.queryKey, { networkMode: "always" });
2060
+ const publish = React.useCallback((event) => {
2061
+ event?.preventDefault();
2062
+ event?.stopPropagation();
2063
+ mutation.reset();
2064
+ mutation.mutateAsync(id).then(() => reactToastify.toast.success(isDraft ? "Published!" : "Unpublished!")).catch((error) => reactToastify.toast.error(`Error: ${error}`));
2065
+ }, [mutation, id]);
2066
+ return /* @__PURE__ */ jsxRuntime.jsx(TableRowActionButton, { icon: isDraft ? js.mdiPublish : js.mdiPublishOff, onClick: publish, ...props });
2067
+ }
2068
+
2069
+ exports.AdminLayout = AdminLayout;
2070
+ exports.AttachDialog = AttachDialog;
2071
+ exports.Breadcrumbs = Breadcrumbs;
2072
+ exports.ButtonBar = ButtonBar;
2073
+ exports.ButtonBarButton = ButtonBarButton;
2074
+ exports.ButtonBarDialogButton = ButtonBarDialogButton;
2075
+ exports.ButtonBarSubmitButton = ButtonBarSubmitButton;
2076
+ exports.DialogButton = DialogButton;
2077
+ exports.FormActionDialog = FormActionDialog;
2078
+ exports.InvalidateButton = InvalidateButton;
2079
+ exports.ItemDeleteDialog = ItemDeleteDialog;
2080
+ exports.ItemEditDialog = ItemEditDialog;
2081
+ exports.Menu = Menu;
2082
+ exports.NavigateButton = NavigateButton;
2083
+ exports.OrderCell = OrderCell;
2084
+ exports.PageContainer = PageContainer;
2085
+ exports.PageContentEditor = PageContentEditor;
2086
+ exports.PageMain = PageMain;
2087
+ exports.PageQueryStateContainer = PageQueryStateContainer;
2088
+ exports.PageSectionTitle = PageSectionTitle;
2089
+ exports.PageSidebar = PageSidebar;
2090
+ exports.PageSidebarSection = PageSidebarSection;
2091
+ exports.PageStateContainer = PageStateContainer;
2092
+ exports.PageSubSectionTitle = PageSubSectionTitle;
2093
+ exports.PageTabbedTopBar = PageTabbedTopBar;
2094
+ exports.PageTabbedTopBarProvider = PageTabbedTopBarProvider;
2095
+ exports.PageTitle = PageTitle;
2096
+ exports.PageTopBar = PageTopBar;
2097
+ exports.PageTopBarToolbar = PageTopBarToolbar;
2098
+ exports.PublishButton = PublishButton;
2099
+ exports.ScreenRenderer = ScreenRenderer;
2100
+ exports.SectionTitle = SectionTitle;
2101
+ exports.StatusBadge = StatusBadge;
2102
+ exports.TableContainer = TableContainer;
2103
+ exports.TableCreateButton = TableCreateButton;
2104
+ exports.TableFilterButton = TableFilterButton;
2105
+ exports.TableRowActionBar = TableRowActionBar;
2106
+ exports.TableRowActionButton = TableRowActionButton;
2107
+ exports.TableRowActionDialogButton = TableRowActionDialogButton;
2108
+ exports.TableRowDeleteButton = TableRowDeleteButton;
2109
+ exports.TableRowEditButton = TableRowEditButton;
2110
+ exports.TableRowNavigateButton = TableRowNavigateButton;
2111
+ exports.TableRowPublishPostButton = TableRowPublishPostButton;
2112
+ exports.TableRowViewButton = TableRowViewButton;
2113
+ exports.TableTopBar = TableTopBar;
2114
+ exports.UpdateButton = UpdateButton;
2115
+ exports.ViewButton = ViewButton;