@compill/admin 1.0.108 → 1.0.109

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