@infuro/cms-core 1.0.15 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin.cjs +1840 -741
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +4 -0
- package/dist/admin.d.ts +4 -0
- package/dist/admin.js +1795 -681
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +577 -29
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.js +572 -26
- package/dist/api.js.map +1 -1
- package/dist/hooks.cjs +159 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +24 -1
- package/dist/hooks.d.ts +24 -1
- package/dist/hooks.js +165 -0
- package/dist/hooks.js.map +1 -1
- package/dist/{index-BiagwMjV.d.ts → index-C85X7cc7.d.ts} +14 -2
- package/dist/{index-BQnqJ7EO.d.cts → index-h42MoUNq.d.cts} +14 -2
- package/dist/index.cjs +5225 -4305
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +89 -11
- package/dist/index.d.ts +89 -11
- package/dist/index.js +5220 -4317
- package/dist/index.js.map +1 -1
- package/dist/migrations/1775200000000-MediaDriveFolders.ts +38 -0
- package/package.json +10 -12
package/dist/admin.cjs
CHANGED
|
@@ -73,13 +73,14 @@ __export(admin_exports, {
|
|
|
73
73
|
module.exports = __toCommonJS(admin_exports);
|
|
74
74
|
|
|
75
75
|
// src/admin/pages/AdminLayout.tsx
|
|
76
|
-
var
|
|
77
|
-
var
|
|
76
|
+
var import_react7 = __toESM(require("react"), 1);
|
|
77
|
+
var import_react8 = require("next-auth/react");
|
|
78
78
|
var import_navigation3 = require("next/navigation");
|
|
79
79
|
var import_sonner = require("sonner");
|
|
80
80
|
|
|
81
81
|
// src/components/Admin/Header.tsx
|
|
82
82
|
var import_react2 = require("next-auth/react");
|
|
83
|
+
var import_react3 = require("react");
|
|
83
84
|
|
|
84
85
|
// src/components/ui/button.tsx
|
|
85
86
|
var React = __toESM(require("react"), 1);
|
|
@@ -301,25 +302,44 @@ function useIsMobile() {
|
|
|
301
302
|
return !!isMobile;
|
|
302
303
|
}
|
|
303
304
|
|
|
305
|
+
// src/lib/infuro-favicon.ts
|
|
306
|
+
var INFURO_FAVICON_BASE64 = "data:image/x-icon;base64,AAABAAMAEBAAAAEAIABoBAAANgAAACAgAAABACAAKBEAAJ4EAAAwMAAAAQAgAGgmAADGFQAAKAAAABAAAAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8V////bv///7D////R////0f///7D///9u////FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wL///9s0qun7q9qYv/DkYv/6tfV///+/v///////////////+7///9r////AgAAAAAAAAAAAAAAAP///wL///+Q/////sqcl/+WOzH/ljsx/5c9M//AiYP/+/j4/////////////////v///5D///8CAAAAAAAAAAD///9s/////v/////Oo5//lz00/5Y7Mf+WOzH/ljsx/7Z3cP/9+/v////////////////+////bAAAAAD///8V////7v///////////v39//Tq6f/QqKP/m0U8/5Y7Mf+WOzH/z6ah/////////////////////+7///8V////bv///////////////////////////////+XOy/+ZQTf/ljsx/59MQ//69fX/////////////////////bv///7D/////////////////////////////////////wYyG/5Y7Mf+WOzH/4MTC/////////////////////7D////R//////////////////7+//79/f/+/f3//v39/+DGw/+WOzH/ljsx/82inf/////////////////////R////0f///////////////9Svq/+mWVH/pllR/6ZZUf+iUUj/ljsx/5Y7Mf/KnJf/////////////////////0f///7D////////////////KnJf/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/062p/////////////////////7D///9u////////////////0amk/6FQSP+hUEj/oVBI/6JRSP+mWVH/plpS/+7g3v////////////////////9u////Ff///+7///////////7+/v/9/Pz/9u7t/8SSjP/Dj4r/9ezr//79/f/////////////////////u////FQAAAAD///9s/////v///////////////8OPif+WOzH/ljsx/7+Jgv/////////////////////+////bAAAAAAAAAAA////Av///5D////+//////////+9hH7/ljsx/5Y7Mf+8g3z////////////////+////kP///wIAAAAAAAAAAAAAAAD///8C////bP///+7/////8OTi/7R0bP+zcmr/8OLh///////////u////bP///wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8V////bv///7D////R////0f///7D///9u////FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAAAABAAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8C////Hf///0n///95////mf///67///+u////mf///3n///9J////Hf///wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8I////Tf///7D////p/////v////////////////////////////////////7////p////sP///03///8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8C////Pfjz8r7HlpH7wY2H/86lof/iysf/9e3s///+/v//////////////////////////////////////////+////77///89////AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////Cf///37////z9Ovq/6BORf+WOzH/ljsx/5Y8Mv+hUEf/v4iC/+rY1v/+/f3///////////////////////////////////////////H///99////CQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wr///+d/////P/////06+r/oE5F/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/m0Q7/8WTjf/38PD///////////////////////////////////////////z///+d////CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8J////nf////3///////////Tr6v+gTkX/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/61mX//w4+L///////////////////////////////////////////3///+d////CQAAAAAAAAAAAAAAAAAAAAAAAAAA////Av///37////8////////////////9Ovq/6BORf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6daUv/v4uD///////////////////////////////////////////z///9+////AgAAAAAAAAAAAAAAAAAAAAD///89////8//////////////////////48fD/rGRc/5pCOf+YPjT/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6xkXf/37+////////////////////////////////////////////P///89AAAAAAAAAAAAAAAA////CP///77////////////////////////////////7+Pf/8eXj/+DGw/++hn//m0U8/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/8GLhf/9/Pz//////////////////////////////////////////77///8IAAAAAAAAAAD///9N////+/////////////////////////////////////////////////7+/v/p1tP/rGRd/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/mkI4/+XPzf//////////////////////////////////////////+////00AAAAA////Av///7D////////////////////////////////////////////////////////////////06+r/r2pi/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/tndw//38+///////////////////////////////////////////sP///wL///8d////6f/////////////////////////////////////////////////////////////////////x5eP/olJJ/5Y7Mf+WOzH/ljsx/5Y7Mf+aQjn/7dza///////////////////////////////////////////p////Hf///0n////+///////////////////////////////////////////////////////////////////////////Ur6v/ljwy/5Y7Mf+WOzH/ljsx/5Y7Mf/Oo5////////////////////////////////////////////7///9J////ef////////////////////////////////////////////////////////////////////////////////fw7/+jVEv/ljsx/5Y7Mf+WOzH/ljsx/7Nxav///////////////////////////////////////////////3n///+Z/////////////////////////////////////////////////////////////////////////////////////7yCfP+WOzH/ljsx/5Y7Mf+WOzH/pllQ//r29f//////////////////////////////////////////mf///67///////////////////////////////////////////79/f/9/Pz//fz8//38/P/9/Pz//fz8//38/P/9/Pz/yZuW/5Y7Mf+WOzH/ljsx/5Y7Mf+gT0b/9evr//////////////////////////////////////////+u////rv/////////////////////////////////////69vb/wo2I/7Z3cf+2d3H/tndx/7Z3cf+2d3H/tndx/7Z3cf+lV0//ljsx/5Y7Mf+WOzH/ljsx/6BORf/06+r//////////////////////////////////////////67///+Z//////////////////////////////////////Tr6v+gTkX/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/oE5F//Tr6v//////////////////////////////////////////mf///3n/////////////////////////////////////9Ovq/6BORf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+lVk7/+fPz//////////////////////////////////////////95////Sf////7////////////////////////////////06+r/oE5F/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/7FuZ////v7//////////////////////////////////////v///0n///8d////6f////////////////////////////////Tr6v+gTkX/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/zKCb///////////////////////////////////////////p////Hf///wL///+w////////////////////////////////+PLx/7d4cf+tZl//rWZf/61mX/+tZl//rWZf/61mX/+tZl//rmdg/7Z3cP+2d3H/tndx/7h7df/w4uH//////////////////////////////////////////7D///8CAAAAAP///03////7/////////////////////////////////Pv6//z6+f/8+vn//Pr5//z6+f/z6un/48zJ/+LKx//y5+b//fz8//38/P/9/Pz//fz8///////////////////////////////////////////7////TQAAAAAAAAAA////CP///77/////////////////////////////////////////////////////4MXC/6VXTv+WPDL/ljwy/6JRSP/aubb///7+/////////////////////////////////////////////////////77///8IAAAAAAAAAAAAAAAA////Pf////P///////////////////////////////////////////Xs6/+jU0r/ljsx/5Y7Mf+WOzH/ljsx/59MQv/w5OL////////////////////////////////////////////////z////PQAAAAAAAAAAAAAAAAAAAAD///8C////fv////z/////////////////////////////////////3sK//5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/9m5tf///////////////////////////////////////////P///37///8CAAAAAAAAAAAAAAAAAAAAAAAAAAD///8J////nf////3////////////////////////////////ZuLX/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/17Sw//////////////////////////////////////3///+d////CQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8K////nf////z//////////////////////////+zc2v+aQzn/ljsx/5Y7Mf+WOzH/ljsx/5pDOf/r2tj////////////////////////////////8////nf///woAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8J////fv////P//////////////////////v39/8eYkv+YPjT/ljsx/5Y7Mf+YPjT/xpSP//79/f//////////////////////////8////37///8JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8C////Pf///77////7/////////////////fv6/+DEwf/Ekoz/wY2H/97Bvv/8+vr/////////////////////+////77///89////AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CP///03///+w////6f////7////////////////////////////////////+////6f///7D///9N////CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wL///8d////Sf///3n///+Z////rv///67///+Z////ef///0n///8d////AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAADAAAABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8E////DP///xr///80////Rv///1n///9q////gP///4D///9q////Wf///0b///80////Gv///wz///8EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CP///y7///9g////lP///7v////V////6P////r////8/////P////z////8////+v///+j////V////u////5T///9g////Lv///wgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wf///81////k////8/////v////+v////////////////////////////////////////////////////////////////////r////v////z////5P///81////BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8G////Kv37+3zt3Nrd27y5/Nm6t//fxMH/59LQ//Dk4v/48vH//fv6//////////////////////////////////////////////////////////////////////z////d////fP///yr///8GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///xH///9g////wvz5+ffNop3+m0U8/5c+NP+cRz7/pFVN/65oYP+8gnv/0qun/+jU0v/59fT//v7+///////////////////////////////////////////////////////////+////9////8L///9f////EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////GP///4n////m/////fv4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+XPTT/m0Q6/6ZaUf/BjIX/6NXT//z5+f////////////////////////////////////////////////////////////////3////k////if///xgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wH///8i////pP////f///////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+XPjT/oVFI/8yhnP/x5OP//vz8////////////////////////////////////////////////////////////////9////6T///8i////AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///yL///+d////8/////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5tEOv+3eHL/48rH//37+/////////////////////////////////////////////////////////////////P///+d////IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////GP///6T////z//////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+YPjT/qFxT/9y+uv/9+vr////////////////////////////////////////////////////////////////z////pP///xgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8R////if////f///////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsy/6NUS//Yt7P//Pn4////////////////////////////////////////////////////////////////9////4n///8RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wb///9g////5v////////////////////////////////v4+P/KnZj/mUI4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5c8Mv+pXlb/38PA//38/P///////////////////////////////////////////////////////////////+b///9g////BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///yr////C/////f////////////////////////////////38+//dwLz/qF1V/51JP/+bRDv/mD40/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+XPTP/qWBY/+vZ2P///v7///////////////////////////////////////////////////////////3////C////KgAAAAAAAAAAAAAAAAAAAAAAAAAA////B////3z////3///////////////////////////////////////////9+/r/9/Dv/+zc2f/dwLz/x5iT/7BrY/+eS0H/lz0z/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/lzwy/7d6c//06un////////////////////////////////////////////////////////////////3////fP///wcAAAAAAAAAAAAAAAAAAAAA////Nf///93////+//////////////////////////////////////////////////////7+/v/+/v7//fz8//Hm5f/XtLH/s3Fq/5lCOP+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/51JP//Sq6b//Pn5///////////////////////////////////////////////////////////+////3f///zUAAAAAAAAAAAAAAAD///8I////k/////z////////////////////////////////////////////////////////////////////////////////9+/v/8eTj/8aVkP+dRz7/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5c8Mv+vamL/7uDf/////////////////////////////////////////////////////////////////P///5P///8IAAAAAAAAAAD///8u////z/////////////////////////////////////////////////////////////////////////////////////////////////fx8P/ImZP/nUg//5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+ZQTj/0qyo//38/P///////////////////////////////////////////////////////////////8////8uAAAAAP///wT///9g////7//////////////////////////////////////////////////////////////////////////////////////////////////////07Or/xJGL/5hAN/+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/rGRd//Tq6P///////////////////////////////////////////////////////////////+////9g////BP///wz///+U////+v////////////////////////////////////////////////////////////////////////////////////////////////////////7/8+jm/7Nya/+WPDP/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/mkQ7/9m3s////v7///////////////////////////////////////////////////////////r///+U////DP///xr///+7/////////////////////////////////////////////////////////////////////////////////////////////////////////////////v7+/+HHxP+hUEf/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljwy/7yBe//69/f///////////////////////////////////////////////////////////////+7////Gv///zT////V//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bu7f+7gHr/mD40/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6xkXP/u4N/////////////////////////////////////////////////////////////////V////NP///0b////o//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////38/P/XtK//nEY9/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6BNRP/iycb////////////////////////////////////////////////////////////////o////Rv///1n////6///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////o1NL/pVhQ/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5xGPP/Yt7L//v39///////////////////////////////////////////////////////////6////Wf///2r////8///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////06un/sW1m/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5pDOf/PpKD//Pr5///////////////////////////////////////////////////////////8////av///4D////8/////////////////////////////////////////////////////////////v7//fv7//37+v/9+/r//fv6//37+v/9+/r//fv6//37+v/9+/r//fv6//37+v/06un/snBp/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5lBOP/KnJj/+/j4///////////////////////////////////////////////////////////8////gP///4D////8//////////////////////////////////////////////////////79/f/s3Nr/z6ej/8uemv/Lnpr/y56a/8uemv/Lnpr/y56a/8uemv/Lnpr/y56a/8uemv/GlI//o1VM/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5lBOP/KnJf/+/j4///////////////////////////////////////////////////////////8////gP///2r////8//////////////////////////////////////////////////////z5+f/Nop3/m0Q7/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5lBOP/KnJf/+/j4///////////////////////////////////////////////////////////8////av///1n////6//////////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5lCOP/KnZj/+/j4///////////////////////////////////////////////////////////6////Wf///0b////o//////////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5pDOv/Qp6P//Pr6///////////////////////////////////////////////////////////o////Rv///zT////V//////////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/51IP//bvbr//v7+///////////////////////////////////////////////////////////V////NP///xr///+7//////////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6RVTf/n0c////////////////////////////////////////////////////////////////+7////Gv///wz///+U////+v////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/7FuZ//z6ej///////////////////////////////////////////////////////////r///+U////DP///wT///9g////7/////////////////////////////////////////////////z4+P/LnZj/mkI5/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/mUE3/8mblf/9+/r//////////////////////////////////////////////////////////+////9g////BAAAAAD///8u////z/////////////////////////////////////////////////38/P/iycb/v4iC/7yCfP+8gnz/vIJ8/7yCfP+8gnz/vIJ8/7yCfP+8gnz/vIJ8/7yCfP+8gnz/voR+/8qcl//Lnpr/y56a/8uemv/Lnpr/zqOf//Hl5P///v7//////////////////////////////////////////////////////////8////8uAAAAAAAAAAD///8I////k/////z////////////////////////////////////////////////9/Pz/+vf2//r39v/69/b/+vf2//r39v/69/b/+vf2//j08//07Ov/7+Df/+7f3v/z6+n/+PPy//z6+v/9+/r//fv6//37+v/9+/r//fv7///+/v///////////////////////////////////////////////////////////P///5P///8IAAAAAAAAAAAAAAAA////Nf///93////+/////////////////////////////////////////////////////////////////////////////v7/9u7t/9i3s/++hn//sW1m/7BsZf+7gnv/066q//Ln5v/+/v7////////////////////////////////////////////////////////////////////////////////+////3f///zUAAAAAAAAAAAAAAAAAAAAA////B////3z////3///////////////////////////////////////////////////////////////////////////17Ov/wo6I/55KQf+XPjT/ljsx/5Y7Mf+XPTP/nEY9/7uBe//x5eP////////////////////////////////////////////////////////////////////////////////3////fP///wcAAAAAAAAAAAAAAAAAAAAAAAAAAP///yr////C/////f////////////////////////////////////////////////////////////////37+//UsKz/nUg//5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5tEO//No57/+/j4//////////////////////////////////////////////////////////////////////3////C////KgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wb///9g////5v////////////////////////////////////////////////////////////////bv7/+5fHb/lz0z/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y8Mv+ycGj/8ujm/////////////////////////////////////////////////////////////////////+b///9g////BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8R////if////f//////////////////////////////////////////////////////////+3e3P+qYlr/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+oXVT/6tnX////////////////////////////////////////////////////////////////9////4n///8RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////GP///6T////z/////////////////////////////////////////////////////+vZ1/+oXVT/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+nWlL/6dbU///////////////////////////////////////////////////////////z////pP///xgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///yL///+d////8/////////////////////////////////////////////////Hm5f+wa2T/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+uaGD/8OPh//////////////////////////////////////////////////////P///+d////IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wH///8i////pP////f///////////////////////////////////////////r19P/CjYf/mD81/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5g/Nf/BjIb/+fTz////////////////////////////////////////////////9////6T///8i////AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////GP///4n////m/////f////////////////////////////////7+/v/m0M7/qmFZ/5c9M/+WOzH/ljsx/5Y7Mf+WOzH/lz0z/6leV//lz8z//v7+//////////////////////////////////////3////m////if///xgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///xH///9g////wv////f////+///////////////////////////8+vr/4snG/7d4cf+iUUj/mUA3/5c+NP+gTkT/tXVu/+DFw//8+fn////////////////////////////////+////9////8L///9g////EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8G////Kv///3z////d/////P///////////////////////////v38//Tr6v/kzcv/2726/9m6t//jysf/8uno//78/P////////////////////////////////z////d////fP///yr///8GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wf///81////k////8/////v////+v////////////////////////////////////////////////////////////////////r////v////z////5P///81////BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CP///y7///9g////lP///7v////V////6P////r////8/////P////z////8////+v///+j////V////u////5T///9g////Lv///wgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8E////DP///xr///80////Rv///1n///9q////gP///4D///9q////Wf///0b///80////Gv///wz///8EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
|
|
307
|
+
|
|
304
308
|
// src/components/Admin/Header.tsx
|
|
305
309
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
310
|
+
var DEFAULT_ADMIN_LOGO = "/images/logo/logo.png";
|
|
306
311
|
function AdminHeader() {
|
|
307
312
|
const { data: session } = (0, import_react2.useSession)();
|
|
308
313
|
const isMobile = useIsMobile();
|
|
314
|
+
const configuredLogo = process.env.NEXT_PUBLIC_ADMIN_LOGO_URL || DEFAULT_ADMIN_LOGO;
|
|
315
|
+
const [logoSrc, setLogoSrc] = (0, import_react3.useState)(configuredLogo);
|
|
316
|
+
const [logoFailed, setLogoFailed] = (0, import_react3.useState)(false);
|
|
317
|
+
const isDataLogo = (0, import_react3.useMemo)(() => logoSrc.startsWith("data:"), [logoSrc]);
|
|
309
318
|
const handleLogout = () => {
|
|
310
319
|
(0, import_react2.signOut)({ callbackUrl: "/admin/signin" });
|
|
311
320
|
};
|
|
312
321
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("header", { className: "bg-white border-b border-gray-200 px-4 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
313
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex items-center max-h-9 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
322
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex items-center max-h-9 shrink-0", children: !logoFailed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
314
323
|
import_image.default,
|
|
315
324
|
{
|
|
316
|
-
src:
|
|
325
|
+
src: logoSrc,
|
|
317
326
|
alt: "Admin",
|
|
318
327
|
width: 120,
|
|
319
328
|
height: 34,
|
|
320
|
-
className: "max-h-9 w-auto object-contain object-left"
|
|
329
|
+
className: "max-h-9 w-auto object-contain object-left",
|
|
330
|
+
unoptimized: isDataLogo,
|
|
331
|
+
onError: () => {
|
|
332
|
+
if (logoSrc !== DEFAULT_ADMIN_LOGO) {
|
|
333
|
+
setLogoSrc(DEFAULT_ADMIN_LOGO);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
setLogoFailed(true);
|
|
337
|
+
}
|
|
321
338
|
}
|
|
322
|
-
)
|
|
339
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
340
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_image.default, { src: INFURO_FAVICON_BASE64, alt: "Infuro", width: 18, height: 18, unoptimized: true }),
|
|
341
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-sm font-semibold text-gray-800", children: "Infuro" })
|
|
342
|
+
] }) }),
|
|
323
343
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex items-center space-x-3", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(DropdownMenu, { children: [
|
|
324
344
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
325
345
|
Button,
|
|
@@ -368,23 +388,20 @@ function AdminHeader() {
|
|
|
368
388
|
var import_link2 = __toESM(require("next/link"), 1);
|
|
369
389
|
var import_image2 = __toESM(require("next/image"), 1);
|
|
370
390
|
var import_navigation = require("next/navigation");
|
|
371
|
-
var
|
|
391
|
+
var import_react5 = require("react");
|
|
372
392
|
var import_lucide_react3 = require("lucide-react");
|
|
373
393
|
|
|
374
394
|
// src/admin/admin-config-context.tsx
|
|
375
|
-
var
|
|
395
|
+
var import_react4 = require("react");
|
|
376
396
|
var defaultValue = {
|
|
377
397
|
customNavItems: [],
|
|
378
398
|
customNavSections: [],
|
|
379
399
|
customCrudConfigs: {}
|
|
380
400
|
};
|
|
381
|
-
var AdminConfigContext = (0,
|
|
382
|
-
|
|
383
|
-
// src/lib/infuro-favicon.ts
|
|
384
|
-
var INFURO_FAVICON_BASE64 = "data:image/x-icon;base64,AAABAAMAEBAAAAEAIABoBAAANgAAACAgAAABACAAKBEAAJ4EAAAwMAAAAQAgAGgmAADGFQAAKAAAABAAAAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8V////bv///7D////R////0f///7D///9u////FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wL///9s0qun7q9qYv/DkYv/6tfV///+/v///////////////+7///9r////AgAAAAAAAAAAAAAAAP///wL///+Q/////sqcl/+WOzH/ljsx/5c9M//AiYP/+/j4/////////////////v///5D///8CAAAAAAAAAAD///9s/////v/////Oo5//lz00/5Y7Mf+WOzH/ljsx/7Z3cP/9+/v////////////////+////bAAAAAD///8V////7v///////////v39//Tq6f/QqKP/m0U8/5Y7Mf+WOzH/z6ah/////////////////////+7///8V////bv///////////////////////////////+XOy/+ZQTf/ljsx/59MQ//69fX/////////////////////bv///7D/////////////////////////////////////wYyG/5Y7Mf+WOzH/4MTC/////////////////////7D////R//////////////////7+//79/f/+/f3//v39/+DGw/+WOzH/ljsx/82inf/////////////////////R////0f///////////////9Svq/+mWVH/pllR/6ZZUf+iUUj/ljsx/5Y7Mf/KnJf/////////////////////0f///7D////////////////KnJf/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/062p/////////////////////7D///9u////////////////0amk/6FQSP+hUEj/oVBI/6JRSP+mWVH/plpS/+7g3v////////////////////9u////Ff///+7///////////7+/v/9/Pz/9u7t/8SSjP/Dj4r/9ezr//79/f/////////////////////u////FQAAAAD///9s/////v///////////////8OPif+WOzH/ljsx/7+Jgv/////////////////////+////bAAAAAAAAAAA////Av///5D////+//////////+9hH7/ljsx/5Y7Mf+8g3z////////////////+////kP///wIAAAAAAAAAAAAAAAD///8C////bP///+7/////8OTi/7R0bP+zcmr/8OLh///////////u////bP///wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8V////bv///7D////R////0f///7D///9u////FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAAAABAAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8C////Hf///0n///95////mf///67///+u////mf///3n///9J////Hf///wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8I////Tf///7D////p/////v////////////////////////////////////7////p////sP///03///8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8C////Pfjz8r7HlpH7wY2H/86lof/iysf/9e3s///+/v//////////////////////////////////////////+////77///89////AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////Cf///37////z9Ovq/6BORf+WOzH/ljsx/5Y8Mv+hUEf/v4iC/+rY1v/+/f3///////////////////////////////////////////H///99////CQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wr///+d/////P/////06+r/oE5F/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/m0Q7/8WTjf/38PD///////////////////////////////////////////z///+d////CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8J////nf////3///////////Tr6v+gTkX/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/61mX//w4+L///////////////////////////////////////////3///+d////CQAAAAAAAAAAAAAAAAAAAAAAAAAA////Av///37////8////////////////9Ovq/6BORf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6daUv/v4uD///////////////////////////////////////////z///9+////AgAAAAAAAAAAAAAAAAAAAAD///89////8//////////////////////48fD/rGRc/5pCOf+YPjT/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6xkXf/37+////////////////////////////////////////////P///89AAAAAAAAAAAAAAAA////CP///77////////////////////////////////7+Pf/8eXj/+DGw/++hn//m0U8/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/8GLhf/9/Pz//////////////////////////////////////////77///8IAAAAAAAAAAD///9N////+/////////////////////////////////////////////////7+/v/p1tP/rGRd/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/mkI4/+XPzf//////////////////////////////////////////+////00AAAAA////Av///7D////////////////////////////////////////////////////////////////06+r/r2pi/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/tndw//38+///////////////////////////////////////////sP///wL///8d////6f/////////////////////////////////////////////////////////////////////x5eP/olJJ/5Y7Mf+WOzH/ljsx/5Y7Mf+aQjn/7dza///////////////////////////////////////////p////Hf///0n////+///////////////////////////////////////////////////////////////////////////Ur6v/ljwy/5Y7Mf+WOzH/ljsx/5Y7Mf/Oo5////////////////////////////////////////////7///9J////ef////////////////////////////////////////////////////////////////////////////////fw7/+jVEv/ljsx/5Y7Mf+WOzH/ljsx/7Nxav///////////////////////////////////////////////3n///+Z/////////////////////////////////////////////////////////////////////////////////////7yCfP+WOzH/ljsx/5Y7Mf+WOzH/pllQ//r29f//////////////////////////////////////////mf///67///////////////////////////////////////////79/f/9/Pz//fz8//38/P/9/Pz//fz8//38/P/9/Pz/yZuW/5Y7Mf+WOzH/ljsx/5Y7Mf+gT0b/9evr//////////////////////////////////////////+u////rv/////////////////////////////////////69vb/wo2I/7Z3cf+2d3H/tndx/7Z3cf+2d3H/tndx/7Z3cf+lV0//ljsx/5Y7Mf+WOzH/ljsx/6BORf/06+r//////////////////////////////////////////67///+Z//////////////////////////////////////Tr6v+gTkX/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/oE5F//Tr6v//////////////////////////////////////////mf///3n/////////////////////////////////////9Ovq/6BORf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+lVk7/+fPz//////////////////////////////////////////95////Sf////7////////////////////////////////06+r/oE5F/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/7FuZ////v7//////////////////////////////////////v///0n///8d////6f////////////////////////////////Tr6v+gTkX/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/zKCb///////////////////////////////////////////p////Hf///wL///+w////////////////////////////////+PLx/7d4cf+tZl//rWZf/61mX/+tZl//rWZf/61mX/+tZl//rmdg/7Z3cP+2d3H/tndx/7h7df/w4uH//////////////////////////////////////////7D///8CAAAAAP///03////7/////////////////////////////////Pv6//z6+f/8+vn//Pr5//z6+f/z6un/48zJ/+LKx//y5+b//fz8//38/P/9/Pz//fz8///////////////////////////////////////////7////TQAAAAAAAAAA////CP///77/////////////////////////////////////////////////////4MXC/6VXTv+WPDL/ljwy/6JRSP/aubb///7+/////////////////////////////////////////////////////77///8IAAAAAAAAAAAAAAAA////Pf////P///////////////////////////////////////////Xs6/+jU0r/ljsx/5Y7Mf+WOzH/ljsx/59MQv/w5OL////////////////////////////////////////////////z////PQAAAAAAAAAAAAAAAAAAAAD///8C////fv////z/////////////////////////////////////3sK//5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/9m5tf///////////////////////////////////////////P///37///8CAAAAAAAAAAAAAAAAAAAAAAAAAAD///8J////nf////3////////////////////////////////ZuLX/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/17Sw//////////////////////////////////////3///+d////CQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8K////nf////z//////////////////////////+zc2v+aQzn/ljsx/5Y7Mf+WOzH/ljsx/5pDOf/r2tj////////////////////////////////8////nf///woAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8J////fv////P//////////////////////v39/8eYkv+YPjT/ljsx/5Y7Mf+YPjT/xpSP//79/f//////////////////////////8////37///8JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8C////Pf///77////7/////////////////fv6/+DEwf/Ekoz/wY2H/97Bvv/8+vr/////////////////////+////77///89////AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CP///03///+w////6f////7////////////////////////////////////+////6f///7D///9N////CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wL///8d////Sf///3n///+Z////rv///67///+Z////ef///0n///8d////AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAADAAAABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8E////DP///xr///80////Rv///1n///9q////gP///4D///9q////Wf///0b///80////Gv///wz///8EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CP///y7///9g////lP///7v////V////6P////r////8/////P////z////8////+v///+j////V////u////5T///9g////Lv///wgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wf///81////k////8/////v////+v////////////////////////////////////////////////////////////////////r////v////z////5P///81////BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8G////Kv37+3zt3Nrd27y5/Nm6t//fxMH/59LQ//Dk4v/48vH//fv6//////////////////////////////////////////////////////////////////////z////d////fP///yr///8GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///xH///9g////wvz5+ffNop3+m0U8/5c+NP+cRz7/pFVN/65oYP+8gnv/0qun/+jU0v/59fT//v7+///////////////////////////////////////////////////////////+////9////8L///9f////EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////GP///4n////m/////fv4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+XPTT/m0Q6/6ZaUf/BjIX/6NXT//z5+f////////////////////////////////////////////////////////////////3////k////if///xgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wH///8i////pP////f///////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+XPjT/oVFI/8yhnP/x5OP//vz8////////////////////////////////////////////////////////////////9////6T///8i////AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///yL///+d////8/////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5tEOv+3eHL/48rH//37+/////////////////////////////////////////////////////////////////P///+d////IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////GP///6T////z//////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+YPjT/qFxT/9y+uv/9+vr////////////////////////////////////////////////////////////////z////pP///xgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8R////if////f///////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsy/6NUS//Yt7P//Pn4////////////////////////////////////////////////////////////////9////4n///8RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wb///9g////5v////////////////////////////////v4+P/KnZj/mUI4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5c8Mv+pXlb/38PA//38/P///////////////////////////////////////////////////////////////+b///9g////BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///yr////C/////f////////////////////////////////38+//dwLz/qF1V/51JP/+bRDv/mD40/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+XPTP/qWBY/+vZ2P///v7///////////////////////////////////////////////////////////3////C////KgAAAAAAAAAAAAAAAAAAAAAAAAAA////B////3z////3///////////////////////////////////////////9+/r/9/Dv/+zc2f/dwLz/x5iT/7BrY/+eS0H/lz0z/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/lzwy/7d6c//06un////////////////////////////////////////////////////////////////3////fP///wcAAAAAAAAAAAAAAAAAAAAA////Nf///93////+//////////////////////////////////////////////////////7+/v/+/v7//fz8//Hm5f/XtLH/s3Fq/5lCOP+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/51JP//Sq6b//Pn5///////////////////////////////////////////////////////////+////3f///zUAAAAAAAAAAAAAAAD///8I////k/////z////////////////////////////////////////////////////////////////////////////////9+/v/8eTj/8aVkP+dRz7/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5c8Mv+vamL/7uDf/////////////////////////////////////////////////////////////////P///5P///8IAAAAAAAAAAD///8u////z/////////////////////////////////////////////////////////////////////////////////////////////////fx8P/ImZP/nUg//5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+ZQTj/0qyo//38/P///////////////////////////////////////////////////////////////8////8uAAAAAP///wT///9g////7//////////////////////////////////////////////////////////////////////////////////////////////////////07Or/xJGL/5hAN/+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/rGRd//Tq6P///////////////////////////////////////////////////////////////+////9g////BP///wz///+U////+v////////////////////////////////////////////////////////////////////////////////////////////////////////7/8+jm/7Nya/+WPDP/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/mkQ7/9m3s////v7///////////////////////////////////////////////////////////r///+U////DP///xr///+7/////////////////////////////////////////////////////////////////////////////////////////////////////////////////v7+/+HHxP+hUEf/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljwy/7yBe//69/f///////////////////////////////////////////////////////////////+7////Gv///zT////V//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bu7f+7gHr/mD40/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6xkXP/u4N/////////////////////////////////////////////////////////////////V////NP///0b////o//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////38/P/XtK//nEY9/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6BNRP/iycb////////////////////////////////////////////////////////////////o////Rv///1n////6///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////o1NL/pVhQ/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5xGPP/Yt7L//v39///////////////////////////////////////////////////////////6////Wf///2r////8///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////06un/sW1m/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5pDOf/PpKD//Pr5///////////////////////////////////////////////////////////8////av///4D////8/////////////////////////////////////////////////////////////v7//fv7//37+v/9+/r//fv6//37+v/9+/r//fv6//37+v/9+/r//fv6//37+v/06un/snBp/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5lBOP/KnJj/+/j4///////////////////////////////////////////////////////////8////gP///4D////8//////////////////////////////////////////////////////79/f/s3Nr/z6ej/8uemv/Lnpr/y56a/8uemv/Lnpr/y56a/8uemv/Lnpr/y56a/8uemv/GlI//o1VM/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5lBOP/KnJf/+/j4///////////////////////////////////////////////////////////8////gP///2r////8//////////////////////////////////////////////////////z5+f/Nop3/m0Q7/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5lBOP/KnJf/+/j4///////////////////////////////////////////////////////////8////av///1n////6//////////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5lCOP/KnZj/+/j4///////////////////////////////////////////////////////////6////Wf///0b////o//////////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5pDOv/Qp6P//Pr6///////////////////////////////////////////////////////////o////Rv///zT////V//////////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/51IP//bvbr//v7+///////////////////////////////////////////////////////////V////NP///xr///+7//////////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/6RVTf/n0c////////////////////////////////////////////////////////////////+7////Gv///wz///+U////+v////////////////////////////////////////////////v4+P/KnJf/mUE4/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/7FuZ//z6ej///////////////////////////////////////////////////////////r///+U////DP///wT///9g////7/////////////////////////////////////////////////z4+P/LnZj/mkI5/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/ljwy/5Y8Mv+WPDL/mUE3/8mblf/9+/r//////////////////////////////////////////////////////////+////9g////BAAAAAD///8u////z/////////////////////////////////////////////////38/P/iycb/v4iC/7yCfP+8gnz/vIJ8/7yCfP+8gnz/vIJ8/7yCfP+8gnz/vIJ8/7yCfP+8gnz/voR+/8qcl//Lnpr/y56a/8uemv/Lnpr/zqOf//Hl5P///v7//////////////////////////////////////////////////////////8////8uAAAAAAAAAAD///8I////k/////z////////////////////////////////////////////////9/Pz/+vf2//r39v/69/b/+vf2//r39v/69/b/+vf2//j08//07Ov/7+Df/+7f3v/z6+n/+PPy//z6+v/9+/r//fv6//37+v/9+/r//fv7///+/v///////////////////////////////////////////////////////////P///5P///8IAAAAAAAAAAAAAAAA////Nf///93////+/////////////////////////////////////////////////////////////////////////////v7/9u7t/9i3s/++hn//sW1m/7BsZf+7gnv/066q//Ln5v/+/v7////////////////////////////////////////////////////////////////////////////////+////3f///zUAAAAAAAAAAAAAAAAAAAAA////B////3z////3///////////////////////////////////////////////////////////////////////////17Ov/wo6I/55KQf+XPjT/ljsx/5Y7Mf+XPTP/nEY9/7uBe//x5eP////////////////////////////////////////////////////////////////////////////////3////fP///wcAAAAAAAAAAAAAAAAAAAAAAAAAAP///yr////C/////f////////////////////////////////////////////////////////////////37+//UsKz/nUg//5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5tEO//No57/+/j4//////////////////////////////////////////////////////////////////////3////C////KgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wb///9g////5v////////////////////////////////////////////////////////////////bv7/+5fHb/lz0z/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y8Mv+ycGj/8ujm/////////////////////////////////////////////////////////////////////+b///9g////BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8R////if////f//////////////////////////////////////////////////////////+3e3P+qYlr/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+oXVT/6tnX////////////////////////////////////////////////////////////////9////4n///8RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////GP///6T////z/////////////////////////////////////////////////////+vZ1/+oXVT/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+nWlL/6dbU///////////////////////////////////////////////////////////z////pP///xgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///yL///+d////8/////////////////////////////////////////////////Hm5f+wa2T/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5Y7Mf+uaGD/8OPh//////////////////////////////////////////////////////P///+d////IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wH///8i////pP////f///////////////////////////////////////////r19P/CjYf/mD81/5Y7Mf+WOzH/ljsx/5Y7Mf+WOzH/ljsx/5g/Nf/BjIb/+fTz////////////////////////////////////////////////9////6T///8i////AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////GP///4n////m/////f////////////////////////////////7+/v/m0M7/qmFZ/5c9M/+WOzH/ljsx/5Y7Mf+WOzH/lz0z/6leV//lz8z//v7+//////////////////////////////////////3////m////if///xgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///xH///9g////wv////f////+///////////////////////////8+vr/4snG/7d4cf+iUUj/mUA3/5c+NP+gTkT/tXVu/+DFw//8+fn////////////////////////////////+////9////8L///9g////EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8G////Kv///3z////d/////P///////////////////////////v38//Tr6v/kzcv/2726/9m6t//jysf/8uno//78/P////////////////////////////////z////d////fP///yr///8GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wf///81////k////8/////v////+v////////////////////////////////////////////////////////////////////r////v////z////5P///81////BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CP///y7///9g////lP///7v////V////6P////r////8/////P////z////8////+v///+j////V////u////5T///9g////Lv///wgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8E////DP///xr///80////Rv///1n///9q////gP///4D///9q////Wf///0b///80////Gv///wz///8EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
|
|
401
|
+
var AdminConfigContext = (0, import_react4.createContext)(defaultValue);
|
|
385
402
|
|
|
386
403
|
// src/lib/cms-version.ts
|
|
387
|
-
var CMS_VERSION = true ? "1.0.
|
|
404
|
+
var CMS_VERSION = true ? "1.0.16" : "0.0.0";
|
|
388
405
|
|
|
389
406
|
// src/components/Admin/Sidebar.tsx
|
|
390
407
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -404,7 +421,7 @@ function getIconForItem(iconName) {
|
|
|
404
421
|
}
|
|
405
422
|
function AdminSidebar({ variant = "sidebar" }) {
|
|
406
423
|
const pathname = (0, import_navigation.usePathname)();
|
|
407
|
-
const { customNavItems, customNavSections = [], storeEnabled } = (0,
|
|
424
|
+
const { customNavItems, customNavSections = [], storeEnabled } = (0, import_react5.useContext)(AdminConfigContext);
|
|
408
425
|
const isDrawer = variant === "drawer";
|
|
409
426
|
const isActive = (path) => {
|
|
410
427
|
if (path === "/admin/dashboard") {
|
|
@@ -565,12 +582,12 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
565
582
|
// src/components/Admin/MobileBottomNav.tsx
|
|
566
583
|
var import_link3 = __toESM(require("next/link"), 1);
|
|
567
584
|
var import_navigation2 = require("next/navigation");
|
|
568
|
-
var
|
|
585
|
+
var import_react6 = require("react");
|
|
569
586
|
var import_lucide_react4 = require("lucide-react");
|
|
570
587
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
571
588
|
function MobileBottomNav({ onOpenMore }) {
|
|
572
589
|
const pathname = (0, import_navigation2.usePathname)();
|
|
573
|
-
const { storeEnabled } = (0,
|
|
590
|
+
const { storeEnabled } = (0, import_react6.useContext)(AdminConfigContext);
|
|
574
591
|
const isActive = (path) => {
|
|
575
592
|
if (path === "/admin/dashboard") return pathname === path;
|
|
576
593
|
return pathname.startsWith(path);
|
|
@@ -770,7 +787,7 @@ var PUBLIC_ADMIN_PATHS = [
|
|
|
770
787
|
];
|
|
771
788
|
var AdminStyle = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { dangerouslySetInnerHTML: { __html: ADMIN_THEME_CSS } });
|
|
772
789
|
function useAdminViewSettings() {
|
|
773
|
-
(0,
|
|
790
|
+
(0, import_react7.useEffect)(() => {
|
|
774
791
|
fetch("/api/settings/admin_view").then((r) => r.ok ? r.json() : null).then((data) => {
|
|
775
792
|
if (!data) return;
|
|
776
793
|
const root = document.getElementById("admin-root");
|
|
@@ -781,18 +798,18 @@ function useAdminViewSettings() {
|
|
|
781
798
|
}, []);
|
|
782
799
|
}
|
|
783
800
|
function AdminLayoutInner({ children }) {
|
|
784
|
-
const { data: session, status } = (0,
|
|
801
|
+
const { data: session, status } = (0, import_react8.useSession)();
|
|
785
802
|
const router = (0, import_navigation3.useRouter)();
|
|
786
803
|
const pathname = (0, import_navigation3.usePathname)();
|
|
787
|
-
const [loadingTimeout, setLoadingTimeout] = (0,
|
|
788
|
-
const [moreSheetOpen, setMoreSheetOpen] = (0,
|
|
804
|
+
const [loadingTimeout, setLoadingTimeout] = (0, import_react7.useState)(false);
|
|
805
|
+
const [moreSheetOpen, setMoreSheetOpen] = (0, import_react7.useState)(false);
|
|
789
806
|
const isMobile = useIsMobile();
|
|
790
807
|
useAdminViewSettings();
|
|
791
808
|
const isPublicPath = PUBLIC_ADMIN_PATHS.includes(pathname);
|
|
792
|
-
(0,
|
|
809
|
+
(0, import_react7.useEffect)(() => {
|
|
793
810
|
if (isMobile) setMoreSheetOpen(false);
|
|
794
811
|
}, [isMobile, pathname]);
|
|
795
|
-
(0,
|
|
812
|
+
(0, import_react7.useEffect)(() => {
|
|
796
813
|
if (isPublicPath) return;
|
|
797
814
|
if (status === "loading") {
|
|
798
815
|
const timeout = setTimeout(() => setLoadingTimeout(true), 1e4);
|
|
@@ -847,8 +864,8 @@ function AdminLayoutInner({ children }) {
|
|
|
847
864
|
] });
|
|
848
865
|
}
|
|
849
866
|
function useResolvedTheme(theme, themeRegistry) {
|
|
850
|
-
const [activeThemeId, setActiveThemeId] = (0,
|
|
851
|
-
(0,
|
|
867
|
+
const [activeThemeId, setActiveThemeId] = (0, import_react7.useState)(null);
|
|
868
|
+
(0, import_react7.useEffect)(() => {
|
|
852
869
|
if (!themeRegistry || themeRegistry.length === 0) return;
|
|
853
870
|
fetch("/api/settings/theme").then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
854
871
|
const id2 = data?.activeThemeId?.trim();
|
|
@@ -862,8 +879,8 @@ function useResolvedTheme(theme, themeRegistry) {
|
|
|
862
879
|
return found?.config ?? theme ?? themeRegistry[0]?.config;
|
|
863
880
|
}
|
|
864
881
|
function useStoreEnabled() {
|
|
865
|
-
const [storeEnabled, setStoreEnabled] = (0,
|
|
866
|
-
(0,
|
|
882
|
+
const [storeEnabled, setStoreEnabled] = (0, import_react7.useState)(false);
|
|
883
|
+
(0, import_react7.useEffect)(() => {
|
|
867
884
|
fetch("/api/settings/store").then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
868
885
|
setStoreEnabled(data?.enabled === "true");
|
|
869
886
|
}).catch(() => {
|
|
@@ -874,7 +891,7 @@ function useStoreEnabled() {
|
|
|
874
891
|
function AdminLayout({ children, customNavItems = [], customNavSections = [], customCrudConfigs = {}, theme, themeRegistry, pluginDescriptors = [] }) {
|
|
875
892
|
const resolvedTheme = useResolvedTheme(theme, themeRegistry);
|
|
876
893
|
const storeEnabled = useStoreEnabled();
|
|
877
|
-
const configValue =
|
|
894
|
+
const configValue = import_react7.default.useMemo(
|
|
878
895
|
() => ({
|
|
879
896
|
customNavItems,
|
|
880
897
|
customNavSections,
|
|
@@ -904,10 +921,10 @@ function AdminShell({ children }) {
|
|
|
904
921
|
}
|
|
905
922
|
|
|
906
923
|
// src/components/Admin/CRUD.tsx
|
|
907
|
-
var
|
|
924
|
+
var import_react13 = require("react");
|
|
908
925
|
|
|
909
926
|
// src/components/Admin/CreateEditForm.tsx
|
|
910
|
-
var
|
|
927
|
+
var import_react11 = require("react");
|
|
911
928
|
var import_lucide_react8 = require("lucide-react");
|
|
912
929
|
|
|
913
930
|
// src/components/ui/input.tsx
|
|
@@ -1105,7 +1122,7 @@ var Label3 = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ *
|
|
|
1105
1122
|
Label3.displayName = LabelPrimitive.Root.displayName;
|
|
1106
1123
|
|
|
1107
1124
|
// src/components/ui/file-upload.tsx
|
|
1108
|
-
var
|
|
1125
|
+
var import_react9 = require("react");
|
|
1109
1126
|
|
|
1110
1127
|
// src/components/ui/progress.tsx
|
|
1111
1128
|
var React11 = __toESM(require("react"), 1);
|
|
@@ -1134,10 +1151,10 @@ Progress.displayName = ProgressPrimitive.Root.displayName;
|
|
|
1134
1151
|
// src/components/ui/file-upload.tsx
|
|
1135
1152
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1136
1153
|
function FileUpload({ onUploadSuccess }) {
|
|
1137
|
-
const [selectedFile, setSelectedFile] = (0,
|
|
1138
|
-
const [uploading, setUploading] = (0,
|
|
1139
|
-
const [progress, setProgress] = (0,
|
|
1140
|
-
const [fileUrl, setFileUrl] = (0,
|
|
1154
|
+
const [selectedFile, setSelectedFile] = (0, import_react9.useState)(null);
|
|
1155
|
+
const [uploading, setUploading] = (0, import_react9.useState)(false);
|
|
1156
|
+
const [progress, setProgress] = (0, import_react9.useState)(0);
|
|
1157
|
+
const [fileUrl, setFileUrl] = (0, import_react9.useState)("");
|
|
1141
1158
|
const handleFileChange = (event) => {
|
|
1142
1159
|
setSelectedFile(event.target.files[0]);
|
|
1143
1160
|
};
|
|
@@ -1178,7 +1195,7 @@ function FileUpload({ onUploadSuccess }) {
|
|
|
1178
1195
|
}
|
|
1179
1196
|
|
|
1180
1197
|
// src/components/Admin/RelationAutocomplete.tsx
|
|
1181
|
-
var
|
|
1198
|
+
var import_react10 = require("react");
|
|
1182
1199
|
var import_lucide_react7 = require("lucide-react");
|
|
1183
1200
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1184
1201
|
var DEBOUNCE_MS = 300;
|
|
@@ -1192,21 +1209,21 @@ function RelationAutocomplete({
|
|
|
1192
1209
|
placeholder = "Select\u2026",
|
|
1193
1210
|
disabled = false
|
|
1194
1211
|
}) {
|
|
1195
|
-
const [open, setOpen] = (0,
|
|
1196
|
-
const [search, setSearch] = (0,
|
|
1197
|
-
const [searchInput, setSearchInput] = (0,
|
|
1198
|
-
const [items, setItems] = (0,
|
|
1199
|
-
const [total, setTotal] = (0,
|
|
1200
|
-
const [page, setPage] = (0,
|
|
1201
|
-
const [loading, setLoading] = (0,
|
|
1202
|
-
const [loadingMore, setLoadingMore] = (0,
|
|
1203
|
-
const [selectedLabel, setSelectedLabel] = (0,
|
|
1204
|
-
const [initialLabelLoaded, setInitialLabelLoaded] = (0,
|
|
1205
|
-
const containerRef = (0,
|
|
1206
|
-
const listRef = (0,
|
|
1207
|
-
const debounceRef = (0,
|
|
1212
|
+
const [open, setOpen] = (0, import_react10.useState)(false);
|
|
1213
|
+
const [search, setSearch] = (0, import_react10.useState)("");
|
|
1214
|
+
const [searchInput, setSearchInput] = (0, import_react10.useState)("");
|
|
1215
|
+
const [items, setItems] = (0, import_react10.useState)([]);
|
|
1216
|
+
const [total, setTotal] = (0, import_react10.useState)(0);
|
|
1217
|
+
const [page, setPage] = (0, import_react10.useState)(1);
|
|
1218
|
+
const [loading, setLoading] = (0, import_react10.useState)(false);
|
|
1219
|
+
const [loadingMore, setLoadingMore] = (0, import_react10.useState)(false);
|
|
1220
|
+
const [selectedLabel, setSelectedLabel] = (0, import_react10.useState)(null);
|
|
1221
|
+
const [initialLabelLoaded, setInitialLabelLoaded] = (0, import_react10.useState)(false);
|
|
1222
|
+
const containerRef = (0, import_react10.useRef)(null);
|
|
1223
|
+
const listRef = (0, import_react10.useRef)(null);
|
|
1224
|
+
const debounceRef = (0, import_react10.useRef)(null);
|
|
1208
1225
|
const hasMore = items.length < total;
|
|
1209
|
-
const fetchPage = (0,
|
|
1226
|
+
const fetchPage = (0, import_react10.useCallback)(
|
|
1210
1227
|
async (pageNum, searchQ, append) => {
|
|
1211
1228
|
const params = new URLSearchParams({
|
|
1212
1229
|
page: String(pageNum),
|
|
@@ -1227,13 +1244,13 @@ function RelationAutocomplete({
|
|
|
1227
1244
|
},
|
|
1228
1245
|
[apiEndpoint]
|
|
1229
1246
|
);
|
|
1230
|
-
(0,
|
|
1247
|
+
(0, import_react10.useEffect)(() => {
|
|
1231
1248
|
if (!open) return;
|
|
1232
1249
|
setPage(1);
|
|
1233
1250
|
setLoading(true);
|
|
1234
1251
|
fetchPage(1, search, false).finally(() => setLoading(false));
|
|
1235
1252
|
}, [open, search, fetchPage]);
|
|
1236
|
-
(0,
|
|
1253
|
+
(0, import_react10.useEffect)(() => {
|
|
1237
1254
|
if (!open) return;
|
|
1238
1255
|
const onSearchInput = () => {
|
|
1239
1256
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
@@ -1248,7 +1265,13 @@ function RelationAutocomplete({
|
|
|
1248
1265
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
1249
1266
|
};
|
|
1250
1267
|
}, [searchInput, open]);
|
|
1251
|
-
|
|
1268
|
+
(0, import_react10.useEffect)(() => {
|
|
1269
|
+
if (open) return;
|
|
1270
|
+
setSearchInput("");
|
|
1271
|
+
setSearch("");
|
|
1272
|
+
setPage(1);
|
|
1273
|
+
}, [open]);
|
|
1274
|
+
const loadInitialLabel = (0, import_react10.useCallback)(() => {
|
|
1252
1275
|
if (initialLabelLoaded || value == null || value === "") return;
|
|
1253
1276
|
setInitialLabelLoaded(true);
|
|
1254
1277
|
fetch(`${apiEndpoint}/${value}`).then((r) => r.ok ? r.json() : null).then((item) => {
|
|
@@ -1258,14 +1281,14 @@ function RelationAutocomplete({
|
|
|
1258
1281
|
}).catch(() => {
|
|
1259
1282
|
});
|
|
1260
1283
|
}, [apiEndpoint, value, labelField, initialLabelLoaded]);
|
|
1261
|
-
(0,
|
|
1284
|
+
(0, import_react10.useEffect)(() => {
|
|
1262
1285
|
if (value != null && value !== "") loadInitialLabel();
|
|
1263
1286
|
else {
|
|
1264
1287
|
setSelectedLabel(null);
|
|
1265
1288
|
setInitialLabelLoaded(false);
|
|
1266
1289
|
}
|
|
1267
1290
|
}, [value, loadInitialLabel]);
|
|
1268
|
-
(0,
|
|
1291
|
+
(0, import_react10.useEffect)(() => {
|
|
1269
1292
|
if (!open) return;
|
|
1270
1293
|
const el = listRef.current;
|
|
1271
1294
|
if (!el) return;
|
|
@@ -1281,7 +1304,7 @@ function RelationAutocomplete({
|
|
|
1281
1304
|
el.addEventListener("scroll", onScroll);
|
|
1282
1305
|
return () => el.removeEventListener("scroll", onScroll);
|
|
1283
1306
|
}, [open, hasMore, page, search, loadingMore, fetchPage]);
|
|
1284
|
-
(0,
|
|
1307
|
+
(0, import_react10.useEffect)(() => {
|
|
1285
1308
|
if (!open) return;
|
|
1286
1309
|
const onPointerDown = (e) => {
|
|
1287
1310
|
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
@@ -1375,9 +1398,9 @@ var import_sonner3 = require("sonner");
|
|
|
1375
1398
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1376
1399
|
function CreateEditForm({ isOpen, onClose, apiEndpoint, columns, existingData }) {
|
|
1377
1400
|
const isMobile = useIsMobile();
|
|
1378
|
-
const [formData, setFormData] = (0,
|
|
1379
|
-
const [errors, setErrors] = (0,
|
|
1380
|
-
(0,
|
|
1401
|
+
const [formData, setFormData] = (0, import_react11.useState)({});
|
|
1402
|
+
const [errors, setErrors] = (0, import_react11.useState)({});
|
|
1403
|
+
(0, import_react11.useEffect)(() => {
|
|
1381
1404
|
if (existingData) {
|
|
1382
1405
|
setFormData(existingData);
|
|
1383
1406
|
} else {
|
|
@@ -1664,7 +1687,7 @@ var DialogContent = React14.forwardRef(({ className, children, ...props }, ref)
|
|
|
1664
1687
|
{
|
|
1665
1688
|
ref,
|
|
1666
1689
|
className: cn(
|
|
1667
|
-
"fixed left-[50%] top-[50%] z-50 grid w-
|
|
1690
|
+
"fixed left-[50%] top-[50%] z-50 grid w-[calc(100vw-1rem)] max-w-lg max-h-[calc(100vh-1rem)] translate-x-[-50%] translate-y-[-50%] gap-4 overflow-y-auto rounded-lg border bg-background p-4 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:max-h-[calc(100vh-2rem)] sm:p-6",
|
|
1668
1691
|
className
|
|
1669
1692
|
),
|
|
1670
1693
|
...props,
|
|
@@ -1700,7 +1723,7 @@ var DialogFooter = ({
|
|
|
1700
1723
|
"div",
|
|
1701
1724
|
{
|
|
1702
1725
|
className: cn(
|
|
1703
|
-
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
1726
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:space-x-2 sm:gap-0 [&>button]:w-full sm:[&>button]:w-auto",
|
|
1704
1727
|
className
|
|
1705
1728
|
),
|
|
1706
1729
|
...props
|
|
@@ -1732,9 +1755,10 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
|
1732
1755
|
// src/components/Admin/CRUD.tsx
|
|
1733
1756
|
var import_lucide_react12 = require("lucide-react");
|
|
1734
1757
|
var import_link4 = __toESM(require("next/link"), 1);
|
|
1758
|
+
var import_navigation4 = require("next/navigation");
|
|
1735
1759
|
|
|
1736
1760
|
// src/components/Admin/BulkUploadDialog.tsx
|
|
1737
|
-
var
|
|
1761
|
+
var import_react12 = require("react");
|
|
1738
1762
|
var import_lucide_react11 = require("lucide-react");
|
|
1739
1763
|
var import_papaparse = __toESM(require("papaparse"), 1);
|
|
1740
1764
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
@@ -1749,18 +1773,18 @@ var AUTO_GENERATED_COLS = /* @__PURE__ */ new Set([
|
|
|
1749
1773
|
"deleted"
|
|
1750
1774
|
]);
|
|
1751
1775
|
function BulkUploadDialog({ apiEndpoint, onClose }) {
|
|
1752
|
-
const [columns, setColumns] = (0,
|
|
1753
|
-
const [uniqueColumns, setUniqueColumns] = (0,
|
|
1754
|
-
const [loading, setLoading] = (0,
|
|
1755
|
-
const [importing, setImporting] = (0,
|
|
1756
|
-
const [error, setError] = (0,
|
|
1757
|
-
const [success, setSuccess] = (0,
|
|
1758
|
-
const [parsedData, setParsedData] = (0,
|
|
1759
|
-
const [parseErrors, setParseErrors] = (0,
|
|
1760
|
-
const [upsertKey, setUpsertKey] = (0,
|
|
1761
|
-
const [fileName, setFileName] = (0,
|
|
1762
|
-
const fileInputRef = (0,
|
|
1763
|
-
(0,
|
|
1776
|
+
const [columns, setColumns] = (0, import_react12.useState)([]);
|
|
1777
|
+
const [uniqueColumns, setUniqueColumns] = (0, import_react12.useState)([]);
|
|
1778
|
+
const [loading, setLoading] = (0, import_react12.useState)(true);
|
|
1779
|
+
const [importing, setImporting] = (0, import_react12.useState)(false);
|
|
1780
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
1781
|
+
const [success, setSuccess] = (0, import_react12.useState)(null);
|
|
1782
|
+
const [parsedData, setParsedData] = (0, import_react12.useState)([]);
|
|
1783
|
+
const [parseErrors, setParseErrors] = (0, import_react12.useState)([]);
|
|
1784
|
+
const [upsertKey, setUpsertKey] = (0, import_react12.useState)("id");
|
|
1785
|
+
const [fileName, setFileName] = (0, import_react12.useState)("");
|
|
1786
|
+
const fileInputRef = (0, import_react12.useRef)(null);
|
|
1787
|
+
(0, import_react12.useEffect)(() => {
|
|
1764
1788
|
fetchMetadata();
|
|
1765
1789
|
}, [apiEndpoint]);
|
|
1766
1790
|
const fetchMetadata = async () => {
|
|
@@ -2002,6 +2026,7 @@ function BulkUploadDialog({ apiEndpoint, onClose }) {
|
|
|
2002
2026
|
}
|
|
2003
2027
|
|
|
2004
2028
|
// src/components/Admin/CRUD.tsx
|
|
2029
|
+
var import_sonner4 = require("sonner");
|
|
2005
2030
|
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2006
2031
|
function getNestedValue(obj, path) {
|
|
2007
2032
|
return path.split(".").reduce((current, key) => {
|
|
@@ -2026,38 +2051,55 @@ function AdminCRUD({
|
|
|
2026
2051
|
extraListParams,
|
|
2027
2052
|
manageUserGroups
|
|
2028
2053
|
}) {
|
|
2029
|
-
const
|
|
2030
|
-
const [
|
|
2031
|
-
const [
|
|
2032
|
-
const [
|
|
2033
|
-
const [
|
|
2034
|
-
const [
|
|
2035
|
-
const [
|
|
2036
|
-
const [
|
|
2037
|
-
const [
|
|
2038
|
-
const [
|
|
2039
|
-
const [
|
|
2040
|
-
const [
|
|
2041
|
-
const [
|
|
2042
|
-
const [
|
|
2043
|
-
const [
|
|
2044
|
-
const [
|
|
2045
|
-
const [
|
|
2046
|
-
const [
|
|
2047
|
-
const [
|
|
2054
|
+
const router = (0, import_navigation4.useRouter)();
|
|
2055
|
+
const [data, setData] = (0, import_react13.useState)([]);
|
|
2056
|
+
const [loading, setLoading] = (0, import_react13.useState)(true);
|
|
2057
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
2058
|
+
const [page, setPage] = (0, import_react13.useState)(1);
|
|
2059
|
+
const [totalPages, setTotalPages] = (0, import_react13.useState)(1);
|
|
2060
|
+
const [sortField, setSortField] = (0, import_react13.useState)(defaultSortField);
|
|
2061
|
+
const [sortOrder, setSortOrder] = (0, import_react13.useState)(defaultSortOrder);
|
|
2062
|
+
const [searchQuery, setSearchQuery] = (0, import_react13.useState)("");
|
|
2063
|
+
const [searchInput, setSearchInput] = (0, import_react13.useState)("");
|
|
2064
|
+
const [filterValues, setFilterValues] = (0, import_react13.useState)({});
|
|
2065
|
+
const [filterApplyKey, setFilterApplyKey] = (0, import_react13.useState)(0);
|
|
2066
|
+
const [isFormOpen, setIsFormOpen] = (0, import_react13.useState)(false);
|
|
2067
|
+
const [editingItem, setEditingItem] = (0, import_react13.useState)(null);
|
|
2068
|
+
const [deleteDialogOpen, setDeleteDialogOpen] = (0, import_react13.useState)(false);
|
|
2069
|
+
const [itemToDelete, setItemToDelete] = (0, import_react13.useState)(null);
|
|
2070
|
+
const [deleteLoading, setDeleteLoading] = (0, import_react13.useState)(false);
|
|
2071
|
+
const [refreshKey, setRefreshKey] = (0, import_react13.useState)(0);
|
|
2072
|
+
const [bulkDialogOpen, setBulkDialogOpen] = (0, import_react13.useState)(false);
|
|
2073
|
+
const [showFilters, setShowFilters] = (0, import_react13.useState)(false);
|
|
2074
|
+
const [isRefetching, setIsRefetching] = (0, import_react13.useState)(false);
|
|
2075
|
+
const [roleOptions, setRoleOptions] = (0, import_react13.useState)([]);
|
|
2076
|
+
const hasLoadedRef = (0, import_react13.useRef)(false);
|
|
2048
2077
|
const isMobile = useIsMobile();
|
|
2049
2078
|
const showGroupColumn = !!manageUserGroups && roleOptions.length > 0;
|
|
2050
|
-
(0,
|
|
2079
|
+
(0, import_react13.useEffect)(() => {
|
|
2080
|
+
const timeoutId = setTimeout(() => {
|
|
2081
|
+
if (searchInput !== searchQuery) {
|
|
2082
|
+
setPage(1);
|
|
2083
|
+
setSearchQuery(searchInput);
|
|
2084
|
+
}
|
|
2085
|
+
}, 300);
|
|
2086
|
+
return () => clearTimeout(timeoutId);
|
|
2087
|
+
}, [searchInput, searchQuery]);
|
|
2088
|
+
(0, import_react13.useEffect)(() => {
|
|
2051
2089
|
if (!manageUserGroups) return;
|
|
2052
2090
|
fetch("/api/admin/roles").then((r) => r.ok ? r.json() : null).then((data2) => {
|
|
2053
2091
|
if (data2?.groups?.length) setRoleOptions(data2.groups.map((g) => ({ id: g.id, name: g.name })));
|
|
2054
2092
|
}).catch(() => {
|
|
2055
2093
|
});
|
|
2056
2094
|
}, [manageUserGroups]);
|
|
2057
|
-
(0,
|
|
2095
|
+
(0, import_react13.useEffect)(() => {
|
|
2058
2096
|
async function loadData() {
|
|
2059
2097
|
try {
|
|
2060
|
-
|
|
2098
|
+
if (!hasLoadedRef.current) {
|
|
2099
|
+
setLoading(true);
|
|
2100
|
+
} else {
|
|
2101
|
+
setIsRefetching(true);
|
|
2102
|
+
}
|
|
2061
2103
|
setError(null);
|
|
2062
2104
|
const params = new URLSearchParams({
|
|
2063
2105
|
page: page.toString(),
|
|
@@ -2097,6 +2139,8 @@ function AdminCRUD({
|
|
|
2097
2139
|
setTotalPages(1);
|
|
2098
2140
|
} finally {
|
|
2099
2141
|
setLoading(false);
|
|
2142
|
+
setIsRefetching(false);
|
|
2143
|
+
hasLoadedRef.current = true;
|
|
2100
2144
|
}
|
|
2101
2145
|
}
|
|
2102
2146
|
loadData();
|
|
@@ -2107,30 +2151,67 @@ function AdminCRUD({
|
|
|
2107
2151
|
};
|
|
2108
2152
|
const handleSearch = () => {
|
|
2109
2153
|
setPage(1);
|
|
2154
|
+
setSearchQuery(searchInput);
|
|
2110
2155
|
};
|
|
2111
2156
|
const handleApplyFilters = () => {
|
|
2112
2157
|
setPage(1);
|
|
2113
2158
|
setFilterApplyKey((k) => k + 1);
|
|
2114
2159
|
};
|
|
2160
|
+
const closeDeleteDialog = () => {
|
|
2161
|
+
console.debug("[CRUD][delete] closeDeleteDialog", {
|
|
2162
|
+
open: deleteDialogOpen,
|
|
2163
|
+
itemId: itemToDelete?.id,
|
|
2164
|
+
loading: deleteLoading
|
|
2165
|
+
});
|
|
2166
|
+
setDeleteDialogOpen(false);
|
|
2167
|
+
setItemToDelete(null);
|
|
2168
|
+
setDeleteLoading(false);
|
|
2169
|
+
};
|
|
2115
2170
|
const handleDeleteClick = (item) => {
|
|
2171
|
+
console.debug("[CRUD][delete] handleDeleteClick", {
|
|
2172
|
+
itemId: item?.id,
|
|
2173
|
+
resource: resourceName
|
|
2174
|
+
});
|
|
2175
|
+
const active = typeof document !== "undefined" ? document.activeElement : null;
|
|
2176
|
+
if (active instanceof HTMLElement) {
|
|
2177
|
+
active.blur();
|
|
2178
|
+
}
|
|
2179
|
+
setDeleteLoading(false);
|
|
2116
2180
|
setItemToDelete(item);
|
|
2117
|
-
|
|
2181
|
+
window.setTimeout(() => {
|
|
2182
|
+
setDeleteDialogOpen(true);
|
|
2183
|
+
}, 0);
|
|
2118
2184
|
};
|
|
2119
2185
|
const handleDelete = async () => {
|
|
2120
|
-
if (!itemToDelete)
|
|
2186
|
+
if (!itemToDelete) {
|
|
2187
|
+
console.debug("[CRUD][delete] handleDelete blocked: no itemToDelete");
|
|
2188
|
+
return;
|
|
2189
|
+
}
|
|
2190
|
+
console.debug("[CRUD][delete] handleDelete start", {
|
|
2191
|
+
itemId: itemToDelete.id,
|
|
2192
|
+
resource: resourceName
|
|
2193
|
+
});
|
|
2121
2194
|
setDeleteLoading(true);
|
|
2122
2195
|
try {
|
|
2123
2196
|
const res = await fetch(`${apiEndpoint}/${itemToDelete.id}`, { method: "DELETE" });
|
|
2197
|
+
console.debug("[CRUD][delete] handleDelete response", {
|
|
2198
|
+
itemId: itemToDelete.id,
|
|
2199
|
+
ok: res.ok,
|
|
2200
|
+
status: res.status
|
|
2201
|
+
});
|
|
2124
2202
|
if (res.ok) {
|
|
2203
|
+
setData((prev) => prev.filter((row) => String(row.id) !== String(itemToDelete.id)));
|
|
2125
2204
|
setRefreshKey((k) => k + 1);
|
|
2126
|
-
|
|
2127
|
-
setItemToDelete(null);
|
|
2205
|
+
closeDeleteDialog();
|
|
2128
2206
|
} else {
|
|
2129
2207
|
console.error("Failed to delete item");
|
|
2130
2208
|
}
|
|
2131
2209
|
} catch (err) {
|
|
2132
2210
|
console.error("Error deleting item:", err);
|
|
2133
2211
|
} finally {
|
|
2212
|
+
console.debug("[CRUD][delete] handleDelete finally", {
|
|
2213
|
+
itemId: itemToDelete?.id
|
|
2214
|
+
});
|
|
2134
2215
|
setDeleteLoading(false);
|
|
2135
2216
|
}
|
|
2136
2217
|
};
|
|
@@ -2165,18 +2246,33 @@ function AdminCRUD({
|
|
|
2165
2246
|
}
|
|
2166
2247
|
const result = await res.json();
|
|
2167
2248
|
if (result.inviteLink) {
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
Note: ${result.note}`);
|
|
2249
|
+
const note = result.note ? ` ${result.note}` : "";
|
|
2250
|
+
import_sonner4.toast.success(`New invite link generated.${note}`);
|
|
2171
2251
|
}
|
|
2172
2252
|
} catch (error2) {
|
|
2173
2253
|
console.error("Error regenerating invite:", error2);
|
|
2174
|
-
|
|
2254
|
+
import_sonner4.toast.error(error2 instanceof Error ? error2.message : "Failed to regenerate invite");
|
|
2175
2255
|
}
|
|
2176
2256
|
};
|
|
2177
2257
|
const addEditPage = addEditPageUrl && addEditPageUrl.length > 0;
|
|
2178
2258
|
const hasCustomView = customViewPageUrl && customViewPageUrl.length > 0;
|
|
2179
2259
|
const resourceName = apiEndpoint.replace("/api/", "");
|
|
2260
|
+
const hasDetailViewPage = (/* @__PURE__ */ new Set(["contacts", "form-submissions", "orders", "payments"])).has(resourceName);
|
|
2261
|
+
const getRowDestination = (item) => {
|
|
2262
|
+
if (item.id == null) return "modal";
|
|
2263
|
+
if (addEditPage) return `${addEditPageUrl}/${item.id}`;
|
|
2264
|
+
if (hasCustomView) return `${customViewPageUrl}/${item.id}`;
|
|
2265
|
+
if (hasDetailViewPage) return `/admin/${resourceName}/${item.id}/view`;
|
|
2266
|
+
return "modal";
|
|
2267
|
+
};
|
|
2268
|
+
const handleRowClick = (item) => {
|
|
2269
|
+
const destination = getRowDestination(item);
|
|
2270
|
+
if (destination === "modal") {
|
|
2271
|
+
handleEdit(item);
|
|
2272
|
+
return;
|
|
2273
|
+
}
|
|
2274
|
+
router.push(destination);
|
|
2275
|
+
};
|
|
2180
2276
|
const handleExport = async () => {
|
|
2181
2277
|
try {
|
|
2182
2278
|
const res = await fetch(`${apiEndpoint}/export?format=csv`);
|
|
@@ -2190,7 +2286,7 @@ Note: ${result.note}`);
|
|
|
2190
2286
|
URL.revokeObjectURL(url);
|
|
2191
2287
|
} catch (err) {
|
|
2192
2288
|
console.error("Export error:", err);
|
|
2193
|
-
|
|
2289
|
+
import_sonner4.toast.error("Failed to export data");
|
|
2194
2290
|
}
|
|
2195
2291
|
};
|
|
2196
2292
|
if (loading) {
|
|
@@ -2330,8 +2426,8 @@ Note: ${result.note}`);
|
|
|
2330
2426
|
{
|
|
2331
2427
|
type: "text",
|
|
2332
2428
|
placeholder: "Search...",
|
|
2333
|
-
value:
|
|
2334
|
-
onChange: (e) =>
|
|
2429
|
+
value: searchInput,
|
|
2430
|
+
onChange: (e) => setSearchInput(e.target.value),
|
|
2335
2431
|
onKeyDown: (e) => e.key === "Enter" && handleSearch(),
|
|
2336
2432
|
className: "border-0 focus-visible:ring-0 focus-visible:ring-offset-0 rounded-l-md rounded-r-none flex-1 min-w-0"
|
|
2337
2433
|
}
|
|
@@ -2425,6 +2521,10 @@ Note: ${result.note}`);
|
|
|
2425
2521
|
}),
|
|
2426
2522
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Button, { variant: "outline", size: "sm", className: "h-8", onClick: handleApplyFilters, children: "Apply filters" })
|
|
2427
2523
|
] }),
|
|
2524
|
+
isRefetching && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mb-3 flex items-center text-xs text-gray-500", children: [
|
|
2525
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "animate-spin rounded-full h-3.5 w-3.5 border-2 border-gray-300 border-t-gray-600" }),
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ml-2", children: "Refreshing list..." })
|
|
2527
|
+
] }),
|
|
2428
2528
|
isMobile ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-col gap-2 min-w-0", children: data && data.length > 0 ? data.map((item, index) => {
|
|
2429
2529
|
const displayCols = columns?.slice(0, 4) ?? [];
|
|
2430
2530
|
const primary = displayCols[0];
|
|
@@ -2432,27 +2532,17 @@ Note: ${result.note}`);
|
|
|
2432
2532
|
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2433
2533
|
"div",
|
|
2434
2534
|
{
|
|
2435
|
-
className: "min-w-0 rounded-md border border-gray-200 bg-gray-50/50 p-2.5 flex flex-col gap-1",
|
|
2535
|
+
className: "min-w-0 rounded-md border border-gray-200 bg-gray-50/50 p-2.5 flex flex-col gap-1 cursor-pointer",
|
|
2536
|
+
onClick: () => handleRowClick(item),
|
|
2436
2537
|
children: [
|
|
2437
2538
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
2438
2539
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "min-w-0 break-words flex-1 leading-tight", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "font-medium", children: primaryVal != null ? String(primaryVal) : "\u2014" }) }),
|
|
2439
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenu, { children: [
|
|
2540
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenu, { children: [
|
|
2440
2541
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Button, { variant: "ghost", size: "icon", className: "h-8 w-8 shrink-0", children: [
|
|
2441
2542
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.MoreVertical, { className: "h-4 w-4" }),
|
|
2442
2543
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Actions" })
|
|
2443
2544
|
] }) }),
|
|
2444
2545
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
2445
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2446
|
-
import_link4.default,
|
|
2447
|
-
{
|
|
2448
|
-
href: hasCustomView ? `${customViewPageUrl}/${item.id}` : `/admin/${resourceName}/${item.id}/view`,
|
|
2449
|
-
className: "flex items-center gap-2",
|
|
2450
|
-
children: [
|
|
2451
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.Eye, { className: "h-4 w-4" }),
|
|
2452
|
-
"View"
|
|
2453
|
-
]
|
|
2454
|
-
}
|
|
2455
|
-
) }),
|
|
2456
2546
|
!addEditPage && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenuItem, { onClick: () => handleEdit(item), children: [
|
|
2457
2547
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.Edit, { className: "h-4 w-4 mr-2" }),
|
|
2458
2548
|
"Edit"
|
|
@@ -2477,7 +2567,7 @@ Note: ${result.note}`);
|
|
|
2477
2567
|
}
|
|
2478
2568
|
)
|
|
2479
2569
|
] })
|
|
2480
|
-
] })
|
|
2570
|
+
] }, `mobile-actions-${String(item.id ?? index)}-${refreshKey}`) })
|
|
2481
2571
|
] }),
|
|
2482
2572
|
displayCols.slice(1).map((col) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "text-sm text-gray-600 flex gap-1 min-w-0 leading-tight", children: [
|
|
2483
2573
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "shrink-0", children: [
|
|
@@ -2486,7 +2576,7 @@ Note: ${result.note}`);
|
|
|
2486
2576
|
] }),
|
|
2487
2577
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "min-w-0 break-words", children: formatCellValue(getNestedValue(item, col.field || col.key), col) })
|
|
2488
2578
|
] }, col.field || col.key)),
|
|
2489
|
-
showGroupColumn && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "text-sm text-gray-600 flex gap-1 items-center min-w-0", children: [
|
|
2579
|
+
showGroupColumn && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "text-sm text-gray-600 flex gap-1 items-center min-w-0", onClick: (e) => e.stopPropagation(), children: [
|
|
2490
2580
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "shrink-0", children: "Group:" }),
|
|
2491
2581
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2492
2582
|
"select",
|
|
@@ -2526,70 +2616,94 @@ Note: ${result.note}`);
|
|
|
2526
2616
|
showGroupColumn && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableHead, { className: "min-w-[140px]", children: "Group" }),
|
|
2527
2617
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableHead, { className: "w-12 text-center", children: "Actions" })
|
|
2528
2618
|
] }) }),
|
|
2529
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableBody, { children: data && data.length > 0 ? data.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
if (v) handleUserGroupChange(Number(item.id), Number(v));
|
|
2543
|
-
},
|
|
2544
|
-
children: [
|
|
2545
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: "", children: "\u2014" }),
|
|
2546
|
-
roleOptions.map((g) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: g.id, children: g.name }, g.id))
|
|
2547
|
-
]
|
|
2548
|
-
}
|
|
2549
|
-
) }),
|
|
2550
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableCell, { className: "text-center", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenu, { children: [
|
|
2551
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Button, { variant: "ghost", size: "icon", className: "h-8 w-8", children: [
|
|
2552
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.MoreVertical, { className: "h-4 w-4" }),
|
|
2553
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Actions" })
|
|
2554
|
-
] }) }),
|
|
2555
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
2556
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2557
|
-
import_link4.default,
|
|
2619
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableBody, { children: data && data.length > 0 ? data.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2620
|
+
TableRow,
|
|
2621
|
+
{
|
|
2622
|
+
className: "cursor-pointer",
|
|
2623
|
+
onClick: () => handleRowClick(item),
|
|
2624
|
+
children: [
|
|
2625
|
+
columns && columns.map((col, colIndex) => {
|
|
2626
|
+
const fieldKey = col.field || col.key;
|
|
2627
|
+
const value = getNestedValue(item, fieldKey);
|
|
2628
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableCell, { children: formatCellValue(value, col) }, `${item.id}-${colIndex}-${fieldKey}`);
|
|
2629
|
+
}),
|
|
2630
|
+
showGroupColumn && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableCell, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2631
|
+
"select",
|
|
2558
2632
|
{
|
|
2559
|
-
|
|
2560
|
-
|
|
2633
|
+
className: "max-w-[180px] rounded border border-gray-300 px-2 py-1 text-sm dark:border-gray-600 dark:bg-gray-800",
|
|
2634
|
+
value: item.groupId != null && roleOptions.some((g) => g.id === item.groupId) ? String(item.groupId) : "",
|
|
2635
|
+
onChange: (e) => {
|
|
2636
|
+
const v = e.target.value;
|
|
2637
|
+
if (v) handleUserGroupChange(Number(item.id), Number(v));
|
|
2638
|
+
},
|
|
2561
2639
|
children: [
|
|
2562
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2563
|
-
"
|
|
2640
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: "", children: "\u2014" }),
|
|
2641
|
+
roleOptions.map((g) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: g.id, children: g.name }, g.id))
|
|
2564
2642
|
]
|
|
2565
2643
|
}
|
|
2566
2644
|
) }),
|
|
2567
|
-
|
|
2568
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
"
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2645
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableCell, { className: "text-center", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
|
|
2646
|
+
!addEditPage && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2647
|
+
Button,
|
|
2648
|
+
{
|
|
2649
|
+
variant: "outline",
|
|
2650
|
+
size: "icon",
|
|
2651
|
+
className: "h-7 w-7",
|
|
2652
|
+
onClick: () => handleEdit(item),
|
|
2653
|
+
title: "Edit",
|
|
2654
|
+
children: [
|
|
2655
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.Edit, { className: "h-3.5 w-3.5" }),
|
|
2656
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Edit" })
|
|
2657
|
+
]
|
|
2658
|
+
}
|
|
2659
|
+
),
|
|
2660
|
+
addEditPage && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2661
|
+
Button,
|
|
2662
|
+
{
|
|
2663
|
+
variant: "outline",
|
|
2664
|
+
size: "icon",
|
|
2665
|
+
className: "h-7 w-7",
|
|
2666
|
+
onClick: () => router.push(addEditPageUrl + "/" + item.id),
|
|
2667
|
+
title: "Edit",
|
|
2668
|
+
children: [
|
|
2669
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.Edit, { className: "h-3.5 w-3.5" }),
|
|
2670
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Edit" })
|
|
2671
|
+
]
|
|
2672
|
+
}
|
|
2673
|
+
),
|
|
2674
|
+
resourceName === "users" && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2675
|
+
Button,
|
|
2676
|
+
{
|
|
2677
|
+
variant: "outline",
|
|
2678
|
+
size: "icon",
|
|
2679
|
+
className: "h-7 w-7",
|
|
2680
|
+
onClick: () => handleRegenerateInvite(Number(item.id)),
|
|
2681
|
+
title: "Regenerate Invite",
|
|
2682
|
+
children: [
|
|
2683
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.RefreshCw, { className: "h-3.5 w-3.5" }),
|
|
2684
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Regenerate Invite" })
|
|
2685
|
+
]
|
|
2686
|
+
}
|
|
2687
|
+
),
|
|
2688
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2689
|
+
Button,
|
|
2690
|
+
{
|
|
2691
|
+
variant: "outline",
|
|
2692
|
+
size: "icon",
|
|
2693
|
+
className: "h-7 w-7 border-red-300 text-red-600 hover:text-red-700",
|
|
2694
|
+
onClick: () => handleDeleteClick(item),
|
|
2695
|
+
title: "Delete",
|
|
2696
|
+
children: [
|
|
2697
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.Trash2, { className: "h-3.5 w-3.5" }),
|
|
2698
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Delete" })
|
|
2699
|
+
]
|
|
2700
|
+
}
|
|
2701
|
+
)
|
|
2702
|
+
] }) })
|
|
2703
|
+
]
|
|
2704
|
+
},
|
|
2705
|
+
String(item.id ?? index)
|
|
2706
|
+
)) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2593
2707
|
TableCell,
|
|
2594
2708
|
{
|
|
2595
2709
|
colSpan: columns ? columns.length + 1 + (showGroupColumn ? 1 : 0) : 1,
|
|
@@ -2635,21 +2749,35 @@ Note: ${result.note}`);
|
|
|
2635
2749
|
existingData: editingItem
|
|
2636
2750
|
}
|
|
2637
2751
|
),
|
|
2638
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2752
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2753
|
+
Dialog,
|
|
2754
|
+
{
|
|
2755
|
+
open: deleteDialogOpen,
|
|
2756
|
+
onOpenChange: (open) => {
|
|
2757
|
+
console.debug("[CRUD][delete] dialog onOpenChange", {
|
|
2758
|
+
nextOpen: open,
|
|
2759
|
+
itemId: itemToDelete?.id
|
|
2760
|
+
});
|
|
2761
|
+
if (!open) closeDeleteDialog();
|
|
2762
|
+
else setDeleteDialogOpen(true);
|
|
2763
|
+
},
|
|
2764
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DialogContent, { children: [
|
|
2765
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DialogHeader, { children: [
|
|
2766
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DialogTitle, { children: "Confirm Delete" }),
|
|
2767
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DialogDescription, { children: "Are you sure you want to delete this item? This action cannot be undone." }),
|
|
2768
|
+
itemToDelete && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mt-2 p-2 bg-gray-50 rounded", children: [
|
|
2769
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("strong", { children: "Item:" }),
|
|
2770
|
+
" ",
|
|
2771
|
+
String(itemToDelete.name ?? itemToDelete.title ?? itemToDelete.id ?? "")
|
|
2772
|
+
] })
|
|
2773
|
+
] }),
|
|
2774
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DialogFooter, { children: [
|
|
2775
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Button, { variant: "outline", onClick: closeDeleteDialog, disabled: deleteLoading, children: "Cancel" }),
|
|
2776
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Button, { variant: "destructive", onClick: handleDelete, disabled: deleteLoading, children: deleteLoading ? "Deleting..." : "Delete" })
|
|
2777
|
+
] })
|
|
2646
2778
|
] })
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Button, { variant: "outline", onClick: () => setDeleteDialogOpen(false), disabled: deleteLoading, children: "Cancel" }),
|
|
2650
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Button, { variant: "destructive", onClick: handleDelete, disabled: deleteLoading, children: deleteLoading ? "Deleting..." : "Delete" })
|
|
2651
|
-
] })
|
|
2652
|
-
] }) }),
|
|
2779
|
+
}
|
|
2780
|
+
),
|
|
2653
2781
|
bulkDialogOpen && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2654
2782
|
BulkUploadDialog,
|
|
2655
2783
|
{
|
|
@@ -2665,7 +2793,7 @@ Note: ${result.note}`);
|
|
|
2665
2793
|
}
|
|
2666
2794
|
|
|
2667
2795
|
// src/components/Admin/FormBuilder.tsx
|
|
2668
|
-
var
|
|
2796
|
+
var import_react15 = require("react");
|
|
2669
2797
|
|
|
2670
2798
|
// src/components/ui/badge.tsx
|
|
2671
2799
|
var import_class_variance_authority4 = require("class-variance-authority");
|
|
@@ -2692,10 +2820,10 @@ function Badge({ className, variant, ...props }) {
|
|
|
2692
2820
|
|
|
2693
2821
|
// src/components/Admin/FormBuilder.tsx
|
|
2694
2822
|
var import_lucide_react14 = require("lucide-react");
|
|
2695
|
-
var
|
|
2823
|
+
var import_navigation5 = require("next/navigation");
|
|
2696
2824
|
|
|
2697
2825
|
// src/components/Admin/FormBuilder/FieldConfiguration.tsx
|
|
2698
|
-
var
|
|
2826
|
+
var import_react14 = require("react");
|
|
2699
2827
|
var import_lucide_react13 = require("lucide-react");
|
|
2700
2828
|
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2701
2829
|
var FIELD_TYPES = [
|
|
@@ -2716,7 +2844,7 @@ var COLUMN_WIDTHS = [
|
|
|
2716
2844
|
{ value: 12, label: "Full Width (12 cols)" }
|
|
2717
2845
|
];
|
|
2718
2846
|
function FieldConfiguration({ field, onUpdate }) {
|
|
2719
|
-
const [newOption, setNewOption] = (0,
|
|
2847
|
+
const [newOption, setNewOption] = (0, import_react14.useState)("");
|
|
2720
2848
|
const addOption = () => {
|
|
2721
2849
|
if (newOption.trim()) {
|
|
2722
2850
|
const currentOptions = field.options || [];
|
|
@@ -2989,7 +3117,7 @@ function FieldConfiguration({ field, onUpdate }) {
|
|
|
2989
3117
|
// src/components/Admin/FormBuilder.tsx
|
|
2990
3118
|
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2991
3119
|
function FormBuilder({ formId }) {
|
|
2992
|
-
const [formData, setFormData] = (0,
|
|
3120
|
+
const [formData, setFormData] = (0, import_react15.useState)({
|
|
2993
3121
|
name: "",
|
|
2994
3122
|
description: "",
|
|
2995
3123
|
campaign: "",
|
|
@@ -2997,12 +3125,12 @@ function FormBuilder({ formId }) {
|
|
|
2997
3125
|
published: false,
|
|
2998
3126
|
fields: []
|
|
2999
3127
|
});
|
|
3000
|
-
const [errors, setErrors] = (0,
|
|
3001
|
-
const [isLoading, setIsLoading] = (0,
|
|
3002
|
-
const [isSaving, setIsSaving] = (0,
|
|
3003
|
-
const [selectedField, setSelectedField] = (0,
|
|
3004
|
-
const router = (0,
|
|
3005
|
-
const loadFormData = (0,
|
|
3128
|
+
const [errors, setErrors] = (0, import_react15.useState)([]);
|
|
3129
|
+
const [isLoading, setIsLoading] = (0, import_react15.useState)(false);
|
|
3130
|
+
const [isSaving, setIsSaving] = (0, import_react15.useState)(false);
|
|
3131
|
+
const [selectedField, setSelectedField] = (0, import_react15.useState)(null);
|
|
3132
|
+
const router = (0, import_navigation5.useRouter)();
|
|
3133
|
+
const loadFormData = (0, import_react15.useCallback)(async () => {
|
|
3006
3134
|
try {
|
|
3007
3135
|
setIsLoading(true);
|
|
3008
3136
|
const response = await fetch(`/api/forms/${formId}`);
|
|
@@ -3030,12 +3158,12 @@ function FormBuilder({ formId }) {
|
|
|
3030
3158
|
setIsLoading(false);
|
|
3031
3159
|
}
|
|
3032
3160
|
}, [formId]);
|
|
3033
|
-
(0,
|
|
3161
|
+
(0, import_react15.useEffect)(() => {
|
|
3034
3162
|
if (formId) {
|
|
3035
3163
|
loadFormData();
|
|
3036
3164
|
}
|
|
3037
3165
|
}, [formId, loadFormData]);
|
|
3038
|
-
(0,
|
|
3166
|
+
(0, import_react15.useEffect)(() => {
|
|
3039
3167
|
if (formData.name && !formData.slug) {
|
|
3040
3168
|
const generatedSlug = formData.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
3041
3169
|
setFormData((prev) => ({ ...prev, slug: generatedSlug }));
|
|
@@ -3166,19 +3294,34 @@ function FormBuilder({ formId }) {
|
|
|
3166
3294
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h1", { className: "text-xl font-bold text-white", children: formId ? "Edit Form" : "Create New Form" }),
|
|
3167
3295
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-xs text-gray-300 mt-0.5", children: "Design your form with drag-and-drop fields" })
|
|
3168
3296
|
] }),
|
|
3169
|
-
/* @__PURE__ */ (0, import_jsx_runtime25.
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3297
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center space-x-3", children: [
|
|
3298
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3299
|
+
Button,
|
|
3300
|
+
{
|
|
3301
|
+
variant: "outline",
|
|
3302
|
+
size: "icon",
|
|
3303
|
+
className: "md:hidden h-8 w-8 bg-white text-gray-800 hover:bg-gray-100 border-0",
|
|
3304
|
+
onClick: () => router.push("/admin/forms"),
|
|
3305
|
+
children: [
|
|
3306
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react14.X, { className: "h-4 w-4" }),
|
|
3307
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: "Close" })
|
|
3308
|
+
]
|
|
3309
|
+
}
|
|
3310
|
+
),
|
|
3311
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3312
|
+
Button,
|
|
3313
|
+
{
|
|
3314
|
+
variant: "outline",
|
|
3315
|
+
size: "sm",
|
|
3316
|
+
className: "hidden md:inline-flex bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
3317
|
+
onClick: () => router.push("/admin/forms"),
|
|
3318
|
+
children: [
|
|
3319
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react14.X, { className: "h-4 w-4 mr-2" }),
|
|
3320
|
+
"Close"
|
|
3321
|
+
]
|
|
3322
|
+
}
|
|
3323
|
+
)
|
|
3324
|
+
] })
|
|
3182
3325
|
] }) }),
|
|
3183
3326
|
errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "bg-red-50 border-l-4 border-red-400 p-4 mx-6 mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "flex", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "ml-3", children: [
|
|
3184
3327
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { className: "text-sm font-medium text-red-800", children: "Please fix the following errors:" }),
|
|
@@ -3356,11 +3499,24 @@ function FormBuilder({ formId }) {
|
|
|
3356
3499
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "bg-gray-50 border-t border-gray-200 px-6 py-4", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
3357
3500
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-sm text-gray-600", children: formId ? "Editing existing form" : "Creating new form" }),
|
|
3358
3501
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center space-x-3", children: [
|
|
3502
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3503
|
+
Button,
|
|
3504
|
+
{
|
|
3505
|
+
variant: "outline",
|
|
3506
|
+
size: "icon",
|
|
3507
|
+
className: "md:hidden h-8 w-8 bg-white text-gray-800 hover:bg-gray-100 border-0",
|
|
3508
|
+
onClick: () => router.push("/admin/forms"),
|
|
3509
|
+
children: [
|
|
3510
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react14.X, { className: "h-4 w-4" }),
|
|
3511
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: "Close" })
|
|
3512
|
+
]
|
|
3513
|
+
}
|
|
3514
|
+
),
|
|
3359
3515
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3360
3516
|
Button,
|
|
3361
3517
|
{
|
|
3362
3518
|
variant: "outline",
|
|
3363
|
-
className: "bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
3519
|
+
className: "hidden md:inline-flex bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
3364
3520
|
onClick: () => router.push("/admin/forms"),
|
|
3365
3521
|
children: "Close"
|
|
3366
3522
|
}
|
|
@@ -3370,19 +3526,45 @@ function FormBuilder({ formId }) {
|
|
|
3370
3526
|
{
|
|
3371
3527
|
onClick: () => handleSave(false),
|
|
3372
3528
|
disabled: isSaving,
|
|
3373
|
-
|
|
3529
|
+
size: "icon",
|
|
3530
|
+
className: "md:hidden h-8 w-8 bg-white text-gray-800 hover:bg-gray-100 border-0",
|
|
3531
|
+
children: [
|
|
3532
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react14.Save, { className: "h-4 w-4" }),
|
|
3533
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: isSaving ? "Saving..." : "Save" })
|
|
3534
|
+
]
|
|
3535
|
+
}
|
|
3536
|
+
),
|
|
3537
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3538
|
+
Button,
|
|
3539
|
+
{
|
|
3540
|
+
onClick: () => handleSave(false),
|
|
3541
|
+
disabled: isSaving,
|
|
3542
|
+
className: "hidden md:inline-flex bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
3374
3543
|
children: [
|
|
3375
3544
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react14.Save, { className: "h-4 w-4 mr-2" }),
|
|
3376
3545
|
isSaving ? "Saving..." : "Save"
|
|
3377
3546
|
]
|
|
3378
3547
|
}
|
|
3379
3548
|
),
|
|
3549
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3550
|
+
Button,
|
|
3551
|
+
{
|
|
3552
|
+
onClick: () => handleSave(true),
|
|
3553
|
+
disabled: isSaving,
|
|
3554
|
+
size: "icon",
|
|
3555
|
+
className: "md:hidden h-8 w-8 bg-gray-800 text-white hover:bg-gray-700",
|
|
3556
|
+
children: [
|
|
3557
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react14.Check, { className: "h-4 w-4" }),
|
|
3558
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: isSaving ? "Publishing..." : "Publish" })
|
|
3559
|
+
]
|
|
3560
|
+
}
|
|
3561
|
+
),
|
|
3380
3562
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3381
3563
|
Button,
|
|
3382
3564
|
{
|
|
3383
3565
|
onClick: () => handleSave(true),
|
|
3384
3566
|
disabled: isSaving,
|
|
3385
|
-
className: "bg-gray-800 text-white hover:bg-gray-700 text-xs",
|
|
3567
|
+
className: "hidden md:inline-flex bg-gray-800 text-white hover:bg-gray-700 text-xs",
|
|
3386
3568
|
children: isSaving ? "Publishing..." : "Publish"
|
|
3387
3569
|
}
|
|
3388
3570
|
)
|
|
@@ -3392,10 +3574,10 @@ function FormBuilder({ formId }) {
|
|
|
3392
3574
|
}
|
|
3393
3575
|
|
|
3394
3576
|
// src/components/Admin/BlogEditorPage.tsx
|
|
3395
|
-
var
|
|
3577
|
+
var import_react21 = require("react");
|
|
3396
3578
|
|
|
3397
3579
|
// src/components/ui/image-upload.tsx
|
|
3398
|
-
var
|
|
3580
|
+
var import_react16 = require("react");
|
|
3399
3581
|
var import_lucide_react15 = require("lucide-react");
|
|
3400
3582
|
var import_image3 = __toESM(require("next/image"), 1);
|
|
3401
3583
|
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
@@ -3410,12 +3592,12 @@ function ImageUpload({
|
|
|
3410
3592
|
// 10MB default
|
|
3411
3593
|
acceptedTypes = ["image/jpeg", "image/png", "image/gif", "image/webp"]
|
|
3412
3594
|
}) {
|
|
3413
|
-
const [isDragOver, setIsDragOver] = (0,
|
|
3414
|
-
const [isUploading, setIsUploading] = (0,
|
|
3415
|
-
const [uploadProgress, setUploadProgress] = (0,
|
|
3416
|
-
const [error, setError] = (0,
|
|
3417
|
-
const fileInputRef = (0,
|
|
3418
|
-
const handleFileSelect = (0,
|
|
3595
|
+
const [isDragOver, setIsDragOver] = (0, import_react16.useState)(false);
|
|
3596
|
+
const [isUploading, setIsUploading] = (0, import_react16.useState)(false);
|
|
3597
|
+
const [uploadProgress, setUploadProgress] = (0, import_react16.useState)(0);
|
|
3598
|
+
const [error, setError] = (0, import_react16.useState)(null);
|
|
3599
|
+
const fileInputRef = (0, import_react16.useRef)(null);
|
|
3600
|
+
const handleFileSelect = (0, import_react16.useCallback)(async (file) => {
|
|
3419
3601
|
setError(null);
|
|
3420
3602
|
setUploadProgress(0);
|
|
3421
3603
|
if (!acceptedTypes.includes(file.type)) {
|
|
@@ -3447,7 +3629,7 @@ function ImageUpload({
|
|
|
3447
3629
|
setIsUploading(false);
|
|
3448
3630
|
}
|
|
3449
3631
|
}, [onChange, acceptedTypes, maxSize]);
|
|
3450
|
-
const handleDrop = (0,
|
|
3632
|
+
const handleDrop = (0, import_react16.useCallback)((e) => {
|
|
3451
3633
|
e.preventDefault();
|
|
3452
3634
|
setIsDragOver(false);
|
|
3453
3635
|
const files = Array.from(e.dataTransfer.files);
|
|
@@ -3455,21 +3637,21 @@ function ImageUpload({
|
|
|
3455
3637
|
handleFileSelect(files[0]);
|
|
3456
3638
|
}
|
|
3457
3639
|
}, [handleFileSelect]);
|
|
3458
|
-
const handleDragOver = (0,
|
|
3640
|
+
const handleDragOver = (0, import_react16.useCallback)((e) => {
|
|
3459
3641
|
e.preventDefault();
|
|
3460
3642
|
setIsDragOver(true);
|
|
3461
3643
|
}, []);
|
|
3462
|
-
const handleDragLeave = (0,
|
|
3644
|
+
const handleDragLeave = (0, import_react16.useCallback)((e) => {
|
|
3463
3645
|
e.preventDefault();
|
|
3464
3646
|
setIsDragOver(false);
|
|
3465
3647
|
}, []);
|
|
3466
|
-
const handleFileInputChange = (0,
|
|
3648
|
+
const handleFileInputChange = (0, import_react16.useCallback)((e) => {
|
|
3467
3649
|
const files = e.target.files;
|
|
3468
3650
|
if (files && files.length > 0) {
|
|
3469
3651
|
handleFileSelect(files[0]);
|
|
3470
3652
|
}
|
|
3471
3653
|
}, [handleFileSelect]);
|
|
3472
|
-
const handleRemove = (0,
|
|
3654
|
+
const handleRemove = (0, import_react16.useCallback)(() => {
|
|
3473
3655
|
if (onRemove) {
|
|
3474
3656
|
onRemove();
|
|
3475
3657
|
} else {
|
|
@@ -3478,7 +3660,7 @@ function ImageUpload({
|
|
|
3478
3660
|
setError(null);
|
|
3479
3661
|
setUploadProgress(0);
|
|
3480
3662
|
}, [onChange, onRemove]);
|
|
3481
|
-
const openFileDialog = (0,
|
|
3663
|
+
const openFileDialog = (0, import_react16.useCallback)(() => {
|
|
3482
3664
|
fileInputRef.current?.click();
|
|
3483
3665
|
}, []);
|
|
3484
3666
|
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: cn("space-y-3", className), children: [
|
|
@@ -3596,10 +3778,10 @@ function ImageUpload({
|
|
|
3596
3778
|
|
|
3597
3779
|
// src/components/Admin/BlogEditorPage.tsx
|
|
3598
3780
|
var import_lucide_react19 = require("lucide-react");
|
|
3599
|
-
var
|
|
3781
|
+
var import_navigation6 = require("next/navigation");
|
|
3600
3782
|
|
|
3601
3783
|
// src/components/Admin/TagAutocomplete.tsx
|
|
3602
|
-
var
|
|
3784
|
+
var import_react17 = require("react");
|
|
3603
3785
|
var import_lucide_react16 = require("lucide-react");
|
|
3604
3786
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
3605
3787
|
function TagAutocomplete({
|
|
@@ -3608,14 +3790,14 @@ function TagAutocomplete({
|
|
|
3608
3790
|
placeholder = "Search or create tags...",
|
|
3609
3791
|
className = ""
|
|
3610
3792
|
}) {
|
|
3611
|
-
const [inputValue, setInputValue] = (0,
|
|
3612
|
-
const [suggestions, setSuggestions] = (0,
|
|
3613
|
-
const [isLoading, setIsLoading] = (0,
|
|
3614
|
-
const [showSuggestions, setShowSuggestions] = (0,
|
|
3615
|
-
const [isCreating, setIsCreating] = (0,
|
|
3616
|
-
const inputRef = (0,
|
|
3617
|
-
const suggestionsRef = (0,
|
|
3618
|
-
const fetchSuggestions = (0,
|
|
3793
|
+
const [inputValue, setInputValue] = (0, import_react17.useState)("");
|
|
3794
|
+
const [suggestions, setSuggestions] = (0, import_react17.useState)([]);
|
|
3795
|
+
const [isLoading, setIsLoading] = (0, import_react17.useState)(false);
|
|
3796
|
+
const [showSuggestions, setShowSuggestions] = (0, import_react17.useState)(false);
|
|
3797
|
+
const [isCreating, setIsCreating] = (0, import_react17.useState)(false);
|
|
3798
|
+
const inputRef = (0, import_react17.useRef)(null);
|
|
3799
|
+
const suggestionsRef = (0, import_react17.useRef)(null);
|
|
3800
|
+
const fetchSuggestions = (0, import_react17.useCallback)(async (query) => {
|
|
3619
3801
|
if (!query.trim()) {
|
|
3620
3802
|
setSuggestions([]);
|
|
3621
3803
|
return;
|
|
@@ -3637,7 +3819,7 @@ function TagAutocomplete({
|
|
|
3637
3819
|
setIsLoading(false);
|
|
3638
3820
|
}
|
|
3639
3821
|
}, [selectedTags]);
|
|
3640
|
-
(0,
|
|
3822
|
+
(0, import_react17.useEffect)(() => {
|
|
3641
3823
|
const timeoutId = setTimeout(() => {
|
|
3642
3824
|
fetchSuggestions(inputValue);
|
|
3643
3825
|
}, 300);
|
|
@@ -3701,7 +3883,7 @@ function TagAutocomplete({
|
|
|
3701
3883
|
inputRef.current?.blur();
|
|
3702
3884
|
}
|
|
3703
3885
|
};
|
|
3704
|
-
(0,
|
|
3886
|
+
(0, import_react17.useEffect)(() => {
|
|
3705
3887
|
const handleClickOutside = (event) => {
|
|
3706
3888
|
if (suggestionsRef.current && !suggestionsRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
|
|
3707
3889
|
setShowSuggestions(false);
|
|
@@ -3760,7 +3942,10 @@ function TagAutocomplete({
|
|
|
3760
3942
|
"div",
|
|
3761
3943
|
{
|
|
3762
3944
|
className: "px-4 py-2 hover:bg-gray-100 cursor-pointer text-sm",
|
|
3763
|
-
|
|
3945
|
+
onMouseDown: (e) => {
|
|
3946
|
+
e.preventDefault();
|
|
3947
|
+
handleSuggestionSelect(tag);
|
|
3948
|
+
},
|
|
3764
3949
|
children: tag.name
|
|
3765
3950
|
},
|
|
3766
3951
|
tag.id
|
|
@@ -3776,7 +3961,10 @@ function TagAutocomplete({
|
|
|
3776
3961
|
"div",
|
|
3777
3962
|
{
|
|
3778
3963
|
className: "px-4 py-2 hover:bg-gray-100 cursor-pointer text-sm text-gray-700 flex items-center",
|
|
3779
|
-
|
|
3964
|
+
onMouseDown: (e) => {
|
|
3965
|
+
e.preventDefault();
|
|
3966
|
+
handleCreateTag();
|
|
3967
|
+
},
|
|
3780
3968
|
children: [
|
|
3781
3969
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react16.Plus, { className: "h-3 w-3 mr-2" }),
|
|
3782
3970
|
'Create "',
|
|
@@ -3792,7 +3980,7 @@ function TagAutocomplete({
|
|
|
3792
3980
|
|
|
3793
3981
|
// src/components/Admin/JoditRichText.tsx
|
|
3794
3982
|
var import_dynamic = __toESM(require("next/dynamic"), 1);
|
|
3795
|
-
var
|
|
3983
|
+
var import_react18 = require("react");
|
|
3796
3984
|
var import_jodit_min = require("jodit/es2021/jodit.min.css");
|
|
3797
3985
|
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
3798
3986
|
var JoditEditor = (0, import_dynamic.default)(() => import("jodit-react").then((m) => m.default), {
|
|
@@ -3800,7 +3988,7 @@ var JoditEditor = (0, import_dynamic.default)(() => import("jodit-react").then((
|
|
|
3800
3988
|
loading: () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "min-h-[300px] rounded-md border border-gray-200 bg-gray-50 animate-pulse" })
|
|
3801
3989
|
});
|
|
3802
3990
|
function JoditRichText({ value, onChange, placeholder, minHeight = 400 }) {
|
|
3803
|
-
const config = (0,
|
|
3991
|
+
const config = (0, import_react18.useMemo)(
|
|
3804
3992
|
() => ({
|
|
3805
3993
|
readonly: false,
|
|
3806
3994
|
placeholder: placeholder ?? "",
|
|
@@ -3864,7 +4052,7 @@ function JoditRichText({ value, onChange, placeholder, minHeight = 400 }) {
|
|
|
3864
4052
|
}
|
|
3865
4053
|
|
|
3866
4054
|
// src/components/Admin/CategoryAutocomplete.tsx
|
|
3867
|
-
var
|
|
4055
|
+
var import_react19 = require("react");
|
|
3868
4056
|
var import_lucide_react17 = require("lucide-react");
|
|
3869
4057
|
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
3870
4058
|
function CategoryAutocomplete({
|
|
@@ -3873,13 +4061,13 @@ function CategoryAutocomplete({
|
|
|
3873
4061
|
placeholder = "Search or create category...",
|
|
3874
4062
|
className = ""
|
|
3875
4063
|
}) {
|
|
3876
|
-
const [inputValue, setInputValue] = (0,
|
|
3877
|
-
const [suggestions, setSuggestions] = (0,
|
|
3878
|
-
const [isLoading, setIsLoading] = (0,
|
|
3879
|
-
const [showSuggestions, setShowSuggestions] = (0,
|
|
3880
|
-
const [isCreating, setIsCreating] = (0,
|
|
3881
|
-
const inputRef = (0,
|
|
3882
|
-
const suggestionsRef = (0,
|
|
4064
|
+
const [inputValue, setInputValue] = (0, import_react19.useState)("");
|
|
4065
|
+
const [suggestions, setSuggestions] = (0, import_react19.useState)([]);
|
|
4066
|
+
const [isLoading, setIsLoading] = (0, import_react19.useState)(false);
|
|
4067
|
+
const [showSuggestions, setShowSuggestions] = (0, import_react19.useState)(false);
|
|
4068
|
+
const [isCreating, setIsCreating] = (0, import_react19.useState)(false);
|
|
4069
|
+
const inputRef = (0, import_react19.useRef)(null);
|
|
4070
|
+
const suggestionsRef = (0, import_react19.useRef)(null);
|
|
3883
4071
|
const fetchSuggestions = async (query) => {
|
|
3884
4072
|
if (!query.trim()) {
|
|
3885
4073
|
setSuggestions([]);
|
|
@@ -3899,7 +4087,7 @@ function CategoryAutocomplete({
|
|
|
3899
4087
|
setIsLoading(false);
|
|
3900
4088
|
}
|
|
3901
4089
|
};
|
|
3902
|
-
(0,
|
|
4090
|
+
(0, import_react19.useEffect)(() => {
|
|
3903
4091
|
const timeoutId = setTimeout(() => {
|
|
3904
4092
|
fetchSuggestions(inputValue);
|
|
3905
4093
|
}, 300);
|
|
@@ -3961,7 +4149,7 @@ function CategoryAutocomplete({
|
|
|
3961
4149
|
inputRef.current?.blur();
|
|
3962
4150
|
}
|
|
3963
4151
|
};
|
|
3964
|
-
(0,
|
|
4152
|
+
(0, import_react19.useEffect)(() => {
|
|
3965
4153
|
const handleClickOutside = (event) => {
|
|
3966
4154
|
if (suggestionsRef.current && !suggestionsRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
|
|
3967
4155
|
setShowSuggestions(false);
|
|
@@ -4020,7 +4208,10 @@ function CategoryAutocomplete({
|
|
|
4020
4208
|
"div",
|
|
4021
4209
|
{
|
|
4022
4210
|
className: "px-4 py-2 hover:bg-gray-100 cursor-pointer text-sm flex items-center justify-between",
|
|
4023
|
-
|
|
4211
|
+
onMouseDown: (e) => {
|
|
4212
|
+
e.preventDefault();
|
|
4213
|
+
handleSuggestionSelect(category);
|
|
4214
|
+
},
|
|
4024
4215
|
children: [
|
|
4025
4216
|
category.name,
|
|
4026
4217
|
selectedCategory === category.name && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react17.Check, { className: "h-4 w-4 text-green-500" })
|
|
@@ -4039,7 +4230,10 @@ function CategoryAutocomplete({
|
|
|
4039
4230
|
"div",
|
|
4040
4231
|
{
|
|
4041
4232
|
className: "px-4 py-2 hover:bg-gray-100 cursor-pointer text-sm text-gray-700 flex items-center",
|
|
4042
|
-
|
|
4233
|
+
onMouseDown: (e) => {
|
|
4234
|
+
e.preventDefault();
|
|
4235
|
+
handleCreateCategory();
|
|
4236
|
+
},
|
|
4043
4237
|
children: [
|
|
4044
4238
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react17.Plus, { className: "h-3 w-3 mr-2" }),
|
|
4045
4239
|
'Create "',
|
|
@@ -4054,7 +4248,7 @@ function CategoryAutocomplete({
|
|
|
4054
4248
|
}
|
|
4055
4249
|
|
|
4056
4250
|
// src/components/Admin/UserAutocomplete.tsx
|
|
4057
|
-
var
|
|
4251
|
+
var import_react20 = require("react");
|
|
4058
4252
|
var import_lucide_react18 = require("lucide-react");
|
|
4059
4253
|
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
4060
4254
|
function UserAutocomplete({
|
|
@@ -4063,12 +4257,12 @@ function UserAutocomplete({
|
|
|
4063
4257
|
placeholder = "Select author...",
|
|
4064
4258
|
className = ""
|
|
4065
4259
|
}) {
|
|
4066
|
-
const [inputValue, setInputValue] = (0,
|
|
4067
|
-
const [suggestions, setSuggestions] = (0,
|
|
4068
|
-
const [isLoading, setIsLoading] = (0,
|
|
4069
|
-
const [showSuggestions, setShowSuggestions] = (0,
|
|
4070
|
-
const inputRef = (0,
|
|
4071
|
-
const suggestionsRef = (0,
|
|
4260
|
+
const [inputValue, setInputValue] = (0, import_react20.useState)("");
|
|
4261
|
+
const [suggestions, setSuggestions] = (0, import_react20.useState)([]);
|
|
4262
|
+
const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
|
|
4263
|
+
const [showSuggestions, setShowSuggestions] = (0, import_react20.useState)(false);
|
|
4264
|
+
const inputRef = (0, import_react20.useRef)(null);
|
|
4265
|
+
const suggestionsRef = (0, import_react20.useRef)(null);
|
|
4072
4266
|
const fetchSuggestions = async (query) => {
|
|
4073
4267
|
setIsLoading(true);
|
|
4074
4268
|
try {
|
|
@@ -4088,7 +4282,7 @@ function UserAutocomplete({
|
|
|
4088
4282
|
setIsLoading(false);
|
|
4089
4283
|
}
|
|
4090
4284
|
};
|
|
4091
|
-
(0,
|
|
4285
|
+
(0, import_react20.useEffect)(() => {
|
|
4092
4286
|
const timeoutId = setTimeout(() => {
|
|
4093
4287
|
fetchSuggestions(inputValue);
|
|
4094
4288
|
}, 300);
|
|
@@ -4119,7 +4313,7 @@ function UserAutocomplete({
|
|
|
4119
4313
|
inputRef.current?.blur();
|
|
4120
4314
|
}
|
|
4121
4315
|
};
|
|
4122
|
-
(0,
|
|
4316
|
+
(0, import_react20.useEffect)(() => {
|
|
4123
4317
|
const handleClickOutside = (event) => {
|
|
4124
4318
|
if (suggestionsRef.current && !suggestionsRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
|
|
4125
4319
|
setShowSuggestions(false);
|
|
@@ -4166,7 +4360,10 @@ function UserAutocomplete({
|
|
|
4166
4360
|
"div",
|
|
4167
4361
|
{
|
|
4168
4362
|
className: "px-4 py-2 hover:bg-gray-100 cursor-pointer text-sm flex items-center justify-between",
|
|
4169
|
-
|
|
4363
|
+
onMouseDown: (e) => {
|
|
4364
|
+
e.preventDefault();
|
|
4365
|
+
handleSuggestionSelect(user);
|
|
4366
|
+
},
|
|
4170
4367
|
children: [
|
|
4171
4368
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col", children: [
|
|
4172
4369
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "font-medium", children: user.name }),
|
|
@@ -4185,40 +4382,40 @@ function UserAutocomplete({
|
|
|
4185
4382
|
// src/components/Admin/BlogEditorPage.tsx
|
|
4186
4383
|
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
4187
4384
|
function BlogEditor({ existingBlog }) {
|
|
4188
|
-
const [title, setTitle] = (0,
|
|
4189
|
-
const [slug, setSlug] = (0,
|
|
4190
|
-
const [coverImage, setCoverImage] = (0,
|
|
4385
|
+
const [title, setTitle] = (0, import_react21.useState)(existingBlog?.title || "");
|
|
4386
|
+
const [slug, setSlug] = (0, import_react21.useState)(existingBlog?.slug || "");
|
|
4387
|
+
const [coverImage, setCoverImage] = (0, import_react21.useState)(
|
|
4191
4388
|
existingBlog?.coverImage || null
|
|
4192
4389
|
);
|
|
4193
|
-
const [ogImage, setOgImage] = (0,
|
|
4390
|
+
const [ogImage, setOgImage] = (0, import_react21.useState)(
|
|
4194
4391
|
existingBlog?.seo?.ogImage || existingBlog?.ogImage || null
|
|
4195
4392
|
);
|
|
4196
|
-
const [metaTitle, setMetaTitle] = (0,
|
|
4197
|
-
const [metaDescription, setMetaDescription] = (0,
|
|
4393
|
+
const [metaTitle, setMetaTitle] = (0, import_react21.useState)(existingBlog?.seo?.title || "");
|
|
4394
|
+
const [metaDescription, setMetaDescription] = (0, import_react21.useState)(
|
|
4198
4395
|
existingBlog?.seo?.description || ""
|
|
4199
4396
|
);
|
|
4200
|
-
const [metaKeywords, setMetaKeywords] = (0,
|
|
4397
|
+
const [metaKeywords, setMetaKeywords] = (0, import_react21.useState)(
|
|
4201
4398
|
existingBlog?.seo?.keywords || ""
|
|
4202
4399
|
);
|
|
4203
|
-
const [published, setPublished] = (0,
|
|
4204
|
-
const [tags, setTags] = (0,
|
|
4400
|
+
const [published, setPublished] = (0, import_react21.useState)(existingBlog?.published || false);
|
|
4401
|
+
const [tags, setTags] = (0, import_react21.useState)(
|
|
4205
4402
|
existingBlog?.tags?.map((tag) => tag.name) || []
|
|
4206
4403
|
);
|
|
4207
|
-
const [category, setCategory] = (0,
|
|
4404
|
+
const [category, setCategory] = (0, import_react21.useState)(
|
|
4208
4405
|
existingBlog?.category?.name || null
|
|
4209
4406
|
);
|
|
4210
|
-
const [authorId, setAuthorId] = (0,
|
|
4407
|
+
const [authorId, setAuthorId] = (0, import_react21.useState)(
|
|
4211
4408
|
existingBlog?.authorId || null
|
|
4212
4409
|
);
|
|
4213
|
-
const [content, setContent] = (0,
|
|
4214
|
-
const [createdAt, setCreatedAt] = (0,
|
|
4410
|
+
const [content, setContent] = (0, import_react21.useState)(existingBlog?.content || "");
|
|
4411
|
+
const [createdAt, setCreatedAt] = (0, import_react21.useState)(
|
|
4215
4412
|
existingBlog?.createdAt ? new Date(existingBlog.createdAt).toISOString().slice(0, 16) : (/* @__PURE__ */ new Date()).toISOString().slice(0, 16)
|
|
4216
4413
|
);
|
|
4217
|
-
const [errors, setErrors] = (0,
|
|
4218
|
-
const [isLoading, setIsLoading] = (0,
|
|
4219
|
-
const [isSaving, setIsSaving] = (0,
|
|
4220
|
-
const router = (0,
|
|
4221
|
-
(0,
|
|
4414
|
+
const [errors, setErrors] = (0, import_react21.useState)([]);
|
|
4415
|
+
const [isLoading, setIsLoading] = (0, import_react21.useState)(false);
|
|
4416
|
+
const [isSaving, setIsSaving] = (0, import_react21.useState)(false);
|
|
4417
|
+
const router = (0, import_navigation6.useRouter)();
|
|
4418
|
+
(0, import_react21.useEffect)(() => {
|
|
4222
4419
|
if (title && !slug) {
|
|
4223
4420
|
const generatedSlug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
4224
4421
|
setSlug(generatedSlug);
|
|
@@ -4343,11 +4540,25 @@ function BlogEditor({ existingBlog }) {
|
|
|
4343
4540
|
),
|
|
4344
4541
|
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "text-xs text-gray-300", children: "Published" })
|
|
4345
4542
|
] }),
|
|
4543
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
4544
|
+
Button,
|
|
4545
|
+
{
|
|
4546
|
+
size: "icon",
|
|
4547
|
+
className: "md:hidden h-8 w-8 bg-white text-gray-800 hover:bg-gray-100 border-0",
|
|
4548
|
+
onClick: () => handleSave(published),
|
|
4549
|
+
disabled: isSaving,
|
|
4550
|
+
title: isSaving ? "Saving..." : "Save",
|
|
4551
|
+
children: [
|
|
4552
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react19.Save, { className: "h-4 w-4" }),
|
|
4553
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "sr-only", children: isSaving ? "Saving..." : "Save" })
|
|
4554
|
+
]
|
|
4555
|
+
}
|
|
4556
|
+
),
|
|
4346
4557
|
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
4347
4558
|
Button,
|
|
4348
4559
|
{
|
|
4349
4560
|
size: "sm",
|
|
4350
|
-
className: "flex items-center bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
4561
|
+
className: "hidden md:inline-flex items-center bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
4351
4562
|
onClick: () => handleSave(published),
|
|
4352
4563
|
disabled: isSaving,
|
|
4353
4564
|
children: [
|
|
@@ -4356,12 +4567,26 @@ function BlogEditor({ existingBlog }) {
|
|
|
4356
4567
|
]
|
|
4357
4568
|
}
|
|
4358
4569
|
),
|
|
4570
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
4571
|
+
Button,
|
|
4572
|
+
{
|
|
4573
|
+
variant: "outline",
|
|
4574
|
+
size: "icon",
|
|
4575
|
+
className: "md:hidden h-8 w-8 bg-white text-gray-800 hover:bg-gray-100 border-0",
|
|
4576
|
+
onClick: () => router.back(),
|
|
4577
|
+
title: "Close",
|
|
4578
|
+
children: [
|
|
4579
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react19.X, { className: "h-4 w-4" }),
|
|
4580
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "sr-only", children: "Close" })
|
|
4581
|
+
]
|
|
4582
|
+
}
|
|
4583
|
+
),
|
|
4359
4584
|
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
4360
4585
|
Button,
|
|
4361
4586
|
{
|
|
4362
4587
|
variant: "outline",
|
|
4363
4588
|
size: "sm",
|
|
4364
|
-
className: "flex items-center bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
4589
|
+
className: "hidden md:inline-flex items-center bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
4365
4590
|
onClick: () => router.back(),
|
|
4366
4591
|
children: [
|
|
4367
4592
|
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react19.X, { className: "h-4 w-4 mr-1" }),
|
|
@@ -4543,11 +4768,11 @@ function BlogEditor({ existingBlog }) {
|
|
|
4543
4768
|
}
|
|
4544
4769
|
|
|
4545
4770
|
// src/components/Admin/AnalyticsChart.tsx
|
|
4546
|
-
var
|
|
4771
|
+
var import_react22 = require("react");
|
|
4547
4772
|
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
4548
4773
|
function AnalyticsChart({ data, title, type }) {
|
|
4549
|
-
const canvasRef = (0,
|
|
4550
|
-
(0,
|
|
4774
|
+
const canvasRef = (0, import_react22.useRef)(null);
|
|
4775
|
+
(0, import_react22.useEffect)(() => {
|
|
4551
4776
|
if (!canvasRef.current || !data.length) return;
|
|
4552
4777
|
const ctx = canvasRef.current.getContext("2d");
|
|
4553
4778
|
if (!ctx) return;
|
|
@@ -4739,13 +4964,13 @@ function AnalyticsCard({ title, value, subtitle, icon, trend }) {
|
|
|
4739
4964
|
}
|
|
4740
4965
|
|
|
4741
4966
|
// src/components/Admin/AnalyticsExclusion.tsx
|
|
4742
|
-
var
|
|
4967
|
+
var import_navigation7 = require("next/navigation");
|
|
4743
4968
|
|
|
4744
4969
|
// src/hooks/use-analytics.ts
|
|
4745
|
-
var
|
|
4970
|
+
var import_react23 = require("react");
|
|
4746
4971
|
function useAnalytics(pathname) {
|
|
4747
4972
|
const isAdminRoute = pathname != null && pathname.startsWith("/admin");
|
|
4748
|
-
(0,
|
|
4973
|
+
(0, import_react23.useEffect)(() => {
|
|
4749
4974
|
if (isAdminRoute && typeof window !== "undefined") {
|
|
4750
4975
|
if (typeof window.gtag === "function") {
|
|
4751
4976
|
window.gtag = () => {
|
|
@@ -4762,7 +4987,7 @@ function useAnalytics(pathname) {
|
|
|
4762
4987
|
// src/components/Admin/AnalyticsExclusion.tsx
|
|
4763
4988
|
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
4764
4989
|
function AnalyticsExclusion() {
|
|
4765
|
-
const pathname = (0,
|
|
4990
|
+
const pathname = (0, import_navigation7.usePathname)();
|
|
4766
4991
|
const { isAdminRoute, shouldTrack } = useAnalytics(pathname);
|
|
4767
4992
|
if (!isAdminRoute) return null;
|
|
4768
4993
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "fixed bottom-4 right-4 bg-green-100 border border-green-400 text-green-700 px-4 py-2 rounded text-sm z-50", children: [
|
|
@@ -4772,15 +4997,15 @@ function AnalyticsExclusion() {
|
|
|
4772
4997
|
}
|
|
4773
4998
|
|
|
4774
4999
|
// src/components/Admin/ComponentSettings.tsx
|
|
4775
|
-
var
|
|
5000
|
+
var import_react24 = require("react");
|
|
4776
5001
|
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
4777
5002
|
function EntitySelect({
|
|
4778
5003
|
prop,
|
|
4779
5004
|
value,
|
|
4780
5005
|
onChange
|
|
4781
5006
|
}) {
|
|
4782
|
-
const [options, setOptions] = (0,
|
|
4783
|
-
(0,
|
|
5007
|
+
const [options, setOptions] = (0, import_react24.useState)([]);
|
|
5008
|
+
(0, import_react24.useEffect)(() => {
|
|
4784
5009
|
if (!prop.entity) return;
|
|
4785
5010
|
fetch(`/api/${prop.entity}`).then((r) => r.ok ? r.json() : { data: [] }).then((res) => setOptions(res.data || res || [])).catch(() => {
|
|
4786
5011
|
});
|
|
@@ -4918,7 +5143,7 @@ function ComponentSettings({
|
|
|
4918
5143
|
}
|
|
4919
5144
|
|
|
4920
5145
|
// src/components/Admin/NavbarEditor.tsx
|
|
4921
|
-
var
|
|
5146
|
+
var import_react25 = require("react");
|
|
4922
5147
|
var import_lucide_react21 = require("lucide-react");
|
|
4923
5148
|
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
4924
5149
|
function generateId() {
|
|
@@ -4938,9 +5163,9 @@ function NavItemEditor({
|
|
|
4938
5163
|
canMoveUp,
|
|
4939
5164
|
canMoveDown
|
|
4940
5165
|
}) {
|
|
4941
|
-
const [expanded, setExpanded] = (0,
|
|
4942
|
-
const [pages, setPages] = (0,
|
|
4943
|
-
(0,
|
|
5166
|
+
const [expanded, setExpanded] = (0, import_react25.useState)(false);
|
|
5167
|
+
const [pages, setPages] = (0, import_react25.useState)([]);
|
|
5168
|
+
(0, import_react25.useEffect)(() => {
|
|
4944
5169
|
if (!expanded) return;
|
|
4945
5170
|
fetch("/api/pages").then((r) => r.ok ? r.json() : []).then((data) => {
|
|
4946
5171
|
const res = data;
|
|
@@ -5208,9 +5433,9 @@ function NavbarEditor({ config, onChange }) {
|
|
|
5208
5433
|
|
|
5209
5434
|
// src/admin/pages/SignInPage.tsx
|
|
5210
5435
|
var import_link5 = __toESM(require("next/link"), 1);
|
|
5211
|
-
var
|
|
5212
|
-
var
|
|
5213
|
-
var
|
|
5436
|
+
var import_react26 = require("react");
|
|
5437
|
+
var import_react27 = require("next-auth/react");
|
|
5438
|
+
var import_navigation8 = require("next/navigation");
|
|
5214
5439
|
|
|
5215
5440
|
// src/components/Admin/AuthPageLayout.tsx
|
|
5216
5441
|
var import_image5 = __toESM(require("next/image"), 1);
|
|
@@ -5268,13 +5493,13 @@ function AuthPageLayout({ children }) {
|
|
|
5268
5493
|
// src/admin/pages/SignInPage.tsx
|
|
5269
5494
|
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
5270
5495
|
var SigninPage = () => {
|
|
5271
|
-
const [email, setEmail] = (0,
|
|
5272
|
-
const [password, setPassword] = (0,
|
|
5273
|
-
const [error, setError] = (0,
|
|
5274
|
-
const [loading, setLoading] = (0,
|
|
5275
|
-
const router = (0,
|
|
5276
|
-
const { status } = (0,
|
|
5277
|
-
(0,
|
|
5496
|
+
const [email, setEmail] = (0, import_react26.useState)("");
|
|
5497
|
+
const [password, setPassword] = (0, import_react26.useState)("");
|
|
5498
|
+
const [error, setError] = (0, import_react26.useState)("");
|
|
5499
|
+
const [loading, setLoading] = (0, import_react26.useState)(false);
|
|
5500
|
+
const router = (0, import_navigation8.useRouter)();
|
|
5501
|
+
const { status } = (0, import_react27.useSession)();
|
|
5502
|
+
(0, import_react26.useEffect)(() => {
|
|
5278
5503
|
if (status === "authenticated") {
|
|
5279
5504
|
router.replace("/admin/dashboard");
|
|
5280
5505
|
}
|
|
@@ -5284,7 +5509,7 @@ var SigninPage = () => {
|
|
|
5284
5509
|
setLoading(true);
|
|
5285
5510
|
setError("");
|
|
5286
5511
|
try {
|
|
5287
|
-
const result = await (0,
|
|
5512
|
+
const result = await (0, import_react27.signIn)("credentials", {
|
|
5288
5513
|
email,
|
|
5289
5514
|
password,
|
|
5290
5515
|
redirect: false
|
|
@@ -5357,13 +5582,13 @@ var SigninPage = () => {
|
|
|
5357
5582
|
var SignInPage_default = SigninPage;
|
|
5358
5583
|
|
|
5359
5584
|
// src/admin/pages/ForgotPasswordPage.tsx
|
|
5360
|
-
var
|
|
5585
|
+
var import_react28 = require("react");
|
|
5361
5586
|
var import_link6 = __toESM(require("next/link"), 1);
|
|
5362
5587
|
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
5363
5588
|
function ForgotPasswordPage() {
|
|
5364
|
-
const [email, setEmail] = (0,
|
|
5365
|
-
const [loading, setLoading] = (0,
|
|
5366
|
-
const [message, setMessage] = (0,
|
|
5589
|
+
const [email, setEmail] = (0, import_react28.useState)("");
|
|
5590
|
+
const [loading, setLoading] = (0, import_react28.useState)(false);
|
|
5591
|
+
const [message, setMessage] = (0, import_react28.useState)("");
|
|
5367
5592
|
const handleSubmit = async (e) => {
|
|
5368
5593
|
e.preventDefault();
|
|
5369
5594
|
if (!email.trim()) return;
|
|
@@ -5405,17 +5630,17 @@ function ForgotPasswordPage() {
|
|
|
5405
5630
|
}
|
|
5406
5631
|
|
|
5407
5632
|
// src/admin/pages/ResetPasswordPage.tsx
|
|
5408
|
-
var
|
|
5409
|
-
var
|
|
5633
|
+
var import_react29 = require("react");
|
|
5634
|
+
var import_navigation9 = require("next/navigation");
|
|
5410
5635
|
var import_link7 = __toESM(require("next/link"), 1);
|
|
5411
5636
|
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
5412
5637
|
function ResetPasswordPageContent() {
|
|
5413
|
-
const searchParams = (0,
|
|
5638
|
+
const searchParams = (0, import_navigation9.useSearchParams)();
|
|
5414
5639
|
const token = searchParams.get("token");
|
|
5415
|
-
const [formData, setFormData] = (0,
|
|
5416
|
-
const [loading, setLoading] = (0,
|
|
5417
|
-
const [message, setMessage] = (0,
|
|
5418
|
-
(0,
|
|
5640
|
+
const [formData, setFormData] = (0, import_react29.useState)({ password: "", confirmPassword: "" });
|
|
5641
|
+
const [loading, setLoading] = (0, import_react29.useState)(false);
|
|
5642
|
+
const [message, setMessage] = (0, import_react29.useState)("");
|
|
5643
|
+
(0, import_react29.useEffect)(() => {
|
|
5419
5644
|
if (!token) setMessage("Invalid reset link. Token is missing.");
|
|
5420
5645
|
}, [token]);
|
|
5421
5646
|
const handleSubmit = async (e) => {
|
|
@@ -5477,26 +5702,26 @@ function ResetPasswordPageContent() {
|
|
|
5477
5702
|
] }) });
|
|
5478
5703
|
}
|
|
5479
5704
|
function ResetPasswordPage() {
|
|
5480
|
-
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
5705
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react29.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "min-h-screen flex items-center justify-center bg-gray-50 dark:bg-dark", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "max-w-[400px] w-full p-6 text-center", children: [
|
|
5481
5706
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-600 mx-auto" }),
|
|
5482
5707
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "mt-3 text-sm text-body-color", children: "Loading..." })
|
|
5483
5708
|
] }) }), children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ResetPasswordPageContent, {}) });
|
|
5484
5709
|
}
|
|
5485
5710
|
|
|
5486
5711
|
// src/admin/pages/InvitePage.tsx
|
|
5487
|
-
var
|
|
5488
|
-
var
|
|
5712
|
+
var import_react30 = require("react");
|
|
5713
|
+
var import_navigation10 = require("next/navigation");
|
|
5489
5714
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
5490
5715
|
function InvitePageContent() {
|
|
5491
|
-
const searchParams = (0,
|
|
5716
|
+
const searchParams = (0, import_navigation10.useSearchParams)();
|
|
5492
5717
|
const token = searchParams.get("token");
|
|
5493
|
-
const [formData, setFormData] = (0,
|
|
5718
|
+
const [formData, setFormData] = (0, import_react30.useState)({
|
|
5494
5719
|
password: "",
|
|
5495
5720
|
confirmPassword: ""
|
|
5496
5721
|
});
|
|
5497
|
-
const [loading, setLoading] = (0,
|
|
5498
|
-
const [message, setMessage] = (0,
|
|
5499
|
-
(0,
|
|
5722
|
+
const [loading, setLoading] = (0, import_react30.useState)(false);
|
|
5723
|
+
const [message, setMessage] = (0, import_react30.useState)("");
|
|
5724
|
+
(0, import_react30.useEffect)(() => {
|
|
5500
5725
|
if (!token) {
|
|
5501
5726
|
setMessage("Invalid invite link. Token is missing.");
|
|
5502
5727
|
}
|
|
@@ -5561,29 +5786,70 @@ function InvitePageContent() {
|
|
|
5561
5786
|
] }) });
|
|
5562
5787
|
}
|
|
5563
5788
|
function InvitePage() {
|
|
5564
|
-
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
5789
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react30.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "min-h-screen flex items-center justify-center bg-gray-50", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "max-w-[400px] w-full p-6 text-center", children: [
|
|
5565
5790
|
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-600 mx-auto" }),
|
|
5566
5791
|
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "mt-3 text-sm text-gray-600", children: "Loading..." })
|
|
5567
5792
|
] }) }), children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(InvitePageContent, {}) });
|
|
5568
5793
|
}
|
|
5569
5794
|
|
|
5570
5795
|
// src/admin/pages/DashboardPage.tsx
|
|
5571
|
-
var
|
|
5572
|
-
var
|
|
5796
|
+
var import_react31 = require("next-auth/react");
|
|
5797
|
+
var import_react32 = require("react");
|
|
5798
|
+
var import_navigation11 = require("next/navigation");
|
|
5799
|
+
var import_chart2 = require("chart.js");
|
|
5800
|
+
var import_react_chartjs_22 = require("react-chartjs-2");
|
|
5573
5801
|
var import_lucide_react22 = require("lucide-react");
|
|
5574
5802
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
5803
|
+
import_chart2.Chart.register(import_chart2.ArcElement, import_chart2.Tooltip, import_chart2.Legend);
|
|
5575
5804
|
function DashboardPage() {
|
|
5576
|
-
const { data: session } = (0,
|
|
5577
|
-
const
|
|
5578
|
-
const
|
|
5579
|
-
const [
|
|
5580
|
-
const [
|
|
5581
|
-
(0,
|
|
5805
|
+
const { data: session } = (0, import_react31.useSession)();
|
|
5806
|
+
const router = (0, import_navigation11.useRouter)();
|
|
5807
|
+
const { storeEnabled } = (0, import_react32.useContext)(AdminConfigContext);
|
|
5808
|
+
const [analyticsData, setAnalyticsData] = (0, import_react32.useState)(null);
|
|
5809
|
+
const [ecommerceData, setEcommerceData] = (0, import_react32.useState)(null);
|
|
5810
|
+
const [dashboardStats, setDashboardStats] = (0, import_react32.useState)(null);
|
|
5811
|
+
const [loading, setLoading] = (0, import_react32.useState)({ analytics: true, stats: true, ecommerce: true });
|
|
5812
|
+
const [analyticsEnabled, setAnalyticsEnabled] = (0, import_react32.useState)(false);
|
|
5813
|
+
const [days, setDays] = (0, import_react32.useState)(30);
|
|
5814
|
+
const [activeTab, setActiveTab] = (0, import_react32.useState)("overview");
|
|
5815
|
+
const formatMoney4 = (0, import_react32.useMemo)(
|
|
5816
|
+
() => (value) => new Intl.NumberFormat(void 0, {
|
|
5817
|
+
style: "currency",
|
|
5818
|
+
currency: "INR",
|
|
5819
|
+
maximumFractionDigits: 0
|
|
5820
|
+
}).format(value || 0),
|
|
5821
|
+
[]
|
|
5822
|
+
);
|
|
5823
|
+
const safePct = (v, max) => max > 0 ? Math.max(6, Math.round(v / max * 100)) : 0;
|
|
5824
|
+
const productPalette = ["#2563eb", "#0ea5e9", "#14b8a6", "#22c55e", "#eab308", "#f97316"];
|
|
5825
|
+
const salesBreakdownPalette = {
|
|
5826
|
+
sales: "#22c55e",
|
|
5827
|
+
returns: "#ef4444",
|
|
5828
|
+
replacements: "#f59e0b"
|
|
5829
|
+
};
|
|
5830
|
+
const contactTypeColor = (type) => {
|
|
5831
|
+
const t = type.trim().toLowerCase();
|
|
5832
|
+
if (t === "customer") return "#2563eb";
|
|
5833
|
+
if (t === "lead") return "#a855f7";
|
|
5834
|
+
if (t === "vendor") return "#14b8a6";
|
|
5835
|
+
return "#6b7280";
|
|
5836
|
+
};
|
|
5837
|
+
const metricBarColor = (label) => {
|
|
5838
|
+
const key = label.toLowerCase();
|
|
5839
|
+
if (key.includes("contact")) return "bg-blue-500";
|
|
5840
|
+
if (key.includes("submission")) return "bg-purple-500";
|
|
5841
|
+
if (key.includes("net sales")) return "bg-green-500";
|
|
5842
|
+
if (key.includes("gross sales")) return "bg-emerald-500";
|
|
5843
|
+
if (key.includes("return")) return "bg-red-500";
|
|
5844
|
+
return "bg-gray-600";
|
|
5845
|
+
};
|
|
5846
|
+
(0, import_react32.useEffect)(() => {
|
|
5582
5847
|
const fetchData = async () => {
|
|
5583
|
-
const analyticsPromise = fetch(
|
|
5848
|
+
const analyticsPromise = fetch(`/api/analytics?days=${days}`);
|
|
5584
5849
|
const statsPromise = fetch("/api/dashboard/stats");
|
|
5850
|
+
const ecommercePromise = storeEnabled ? fetch(`/api/dashboard/ecommerce?days=${days}`) : Promise.resolve(null);
|
|
5585
5851
|
try {
|
|
5586
|
-
const [analyticsResponse, statsResponse] = await Promise.all([analyticsPromise, statsPromise]);
|
|
5852
|
+
const [analyticsResponse, statsResponse, ecommerceResponse] = await Promise.all([analyticsPromise, statsPromise, ecommercePromise]);
|
|
5587
5853
|
if (analyticsResponse.ok) {
|
|
5588
5854
|
const data = await analyticsResponse.json();
|
|
5589
5855
|
setAnalyticsData(data);
|
|
@@ -5601,15 +5867,22 @@ function DashboardPage() {
|
|
|
5601
5867
|
const stats = await statsResponse.json();
|
|
5602
5868
|
setDashboardStats(stats);
|
|
5603
5869
|
}
|
|
5870
|
+
if (ecommerceResponse && ecommerceResponse.ok) {
|
|
5871
|
+
const ecommerce = await ecommerceResponse.json();
|
|
5872
|
+
setEcommerceData(ecommerce);
|
|
5873
|
+
} else {
|
|
5874
|
+
setEcommerceData(null);
|
|
5875
|
+
}
|
|
5604
5876
|
} catch (error) {
|
|
5605
5877
|
setAnalyticsEnabled(false);
|
|
5878
|
+
setEcommerceData(null);
|
|
5606
5879
|
} finally {
|
|
5607
|
-
setLoading({ analytics: false, stats: false });
|
|
5880
|
+
setLoading({ analytics: false, stats: false, ecommerce: false });
|
|
5608
5881
|
}
|
|
5609
5882
|
};
|
|
5610
5883
|
fetchData();
|
|
5611
|
-
}, []);
|
|
5612
|
-
const isLoading = loading.analytics || loading.stats;
|
|
5884
|
+
}, [days, storeEnabled]);
|
|
5885
|
+
const isLoading = loading.analytics || loading.stats || storeEnabled && loading.ecommerce;
|
|
5613
5886
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "min-w-0 rounded-lg bg-white shadow-md", children: [
|
|
5614
5887
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "bg-gray-800 border-b border-gray-700 px-4 py-2.5 rounded-t-lg", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
5615
5888
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { children: [
|
|
@@ -5625,13 +5898,54 @@ function DashboardPage() {
|
|
|
5625
5898
|
] }) })
|
|
5626
5899
|
] }) }),
|
|
5627
5900
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "min-w-0 p-4 bg-gray-50", children: [
|
|
5628
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "mb-
|
|
5629
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center
|
|
5901
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-3", children: [
|
|
5902
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
5903
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
5904
|
+
"button",
|
|
5905
|
+
{
|
|
5906
|
+
onClick: () => setActiveTab("overview"),
|
|
5907
|
+
className: `text-xs px-2 py-1 rounded border ${activeTab === "overview" ? "bg-gray-800 text-white border-gray-800" : "bg-white text-gray-700 border-gray-300"}`,
|
|
5908
|
+
children: "Overview"
|
|
5909
|
+
}
|
|
5910
|
+
),
|
|
5911
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
5912
|
+
"button",
|
|
5913
|
+
{
|
|
5914
|
+
onClick: () => setActiveTab("crm"),
|
|
5915
|
+
className: `text-xs px-2 py-1 rounded border ${activeTab === "crm" ? "bg-gray-800 text-white border-gray-800" : "bg-white text-gray-700 border-gray-300"}`,
|
|
5916
|
+
children: "CRM / Engagement"
|
|
5917
|
+
}
|
|
5918
|
+
),
|
|
5919
|
+
storeEnabled && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
5920
|
+
"button",
|
|
5921
|
+
{
|
|
5922
|
+
onClick: () => setActiveTab("sales"),
|
|
5923
|
+
className: `text-xs px-2 py-1 rounded border ${activeTab === "sales" ? "bg-gray-800 text-white border-gray-800" : "bg-white text-gray-700 border-gray-300"}`,
|
|
5924
|
+
children: "Sales"
|
|
5925
|
+
}
|
|
5926
|
+
)
|
|
5927
|
+
] }),
|
|
5928
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
5929
|
+
"select",
|
|
5930
|
+
{
|
|
5931
|
+
value: days,
|
|
5932
|
+
onChange: (e) => setDays(Number(e.target.value)),
|
|
5933
|
+
className: "border border-gray-300 text-xs rounded px-2 py-1 bg-white",
|
|
5934
|
+
children: [
|
|
5935
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("option", { value: 7, children: "Last 7 days" }),
|
|
5936
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("option", { value: 30, children: "Last 30 days" }),
|
|
5937
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("option", { value: 90, children: "Last 90 days" })
|
|
5938
|
+
]
|
|
5939
|
+
}
|
|
5940
|
+
)
|
|
5941
|
+
] }),
|
|
5942
|
+
activeTab === "overview" && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "mb-5", children: [
|
|
5943
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center mb-3", children: [
|
|
5630
5944
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.BarChart3, { className: "w-4 h-4 text-gray-600 mr-2" }),
|
|
5631
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h2", { className: "text-sm font-semibold text-gray-800", children: "
|
|
5945
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h2", { className: "text-sm font-semibold text-gray-800", children: "Contacts & Forms" })
|
|
5632
5946
|
] }),
|
|
5633
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-
|
|
5634
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded border border-gray-200 p-
|
|
5947
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4", children: [
|
|
5948
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded border border-gray-200 p-3 shadow-sm", children: [
|
|
5635
5949
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
5636
5950
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs font-medium text-gray-600", children: "Total Contacts" }),
|
|
5637
5951
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "p-1 bg-gray-200 rounded", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.Users, { className: "w-3.5 h-3.5 text-gray-600" }) })
|
|
@@ -5647,7 +5961,7 @@ function DashboardPage() {
|
|
|
5647
5961
|
] })
|
|
5648
5962
|
] })
|
|
5649
5963
|
] }),
|
|
5650
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded border border-gray-200 p-
|
|
5964
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded border border-gray-200 p-3 shadow-sm", children: [
|
|
5651
5965
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
5652
5966
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs font-medium text-gray-600", children: "Form Submissions" }),
|
|
5653
5967
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "p-1 bg-gray-200 rounded", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.FileText, { className: "w-3.5 h-3.5 text-gray-600" }) })
|
|
@@ -5663,7 +5977,7 @@ function DashboardPage() {
|
|
|
5663
5977
|
] })
|
|
5664
5978
|
] })
|
|
5665
5979
|
] }),
|
|
5666
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded border border-gray-200 p-
|
|
5980
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded border border-gray-200 p-3 shadow-sm", children: [
|
|
5667
5981
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
5668
5982
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs font-medium text-gray-600", children: "Active Forms" }),
|
|
5669
5983
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "p-1 bg-gray-200 rounded", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.ClipboardList, { className: "w-3.5 h-3.5 text-gray-600" }) })
|
|
@@ -5673,7 +5987,7 @@ function DashboardPage() {
|
|
|
5673
5987
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-500", children: "Total" })
|
|
5674
5988
|
] })
|
|
5675
5989
|
] }),
|
|
5676
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded border border-gray-200 p-
|
|
5990
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded border border-gray-200 p-3 shadow-sm", children: [
|
|
5677
5991
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
5678
5992
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs font-medium text-gray-600", children: "Registered Users" }),
|
|
5679
5993
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "p-1 bg-gray-200 rounded", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.UserCheck, { className: "w-3.5 h-3.5 text-gray-600" }) })
|
|
@@ -5685,8 +5999,151 @@ function DashboardPage() {
|
|
|
5685
5999
|
] })
|
|
5686
6000
|
] })
|
|
5687
6001
|
] }),
|
|
5688
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.
|
|
5689
|
-
|
|
6002
|
+
activeTab === "overview" && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "mb-6 bg-white rounded-lg border border-gray-200 p-4 shadow-sm", children: [
|
|
6003
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center mb-3", children: [
|
|
6004
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.Activity, { className: "w-4 h-4 text-gray-600 mr-2" }),
|
|
6005
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-sm font-semibold text-gray-800", children: "Overview Snapshot" })
|
|
6006
|
+
] }),
|
|
6007
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6", children: [
|
|
6008
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { children: [
|
|
6009
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h4", { className: "text-xs font-semibold text-gray-700 mb-2", children: "Contacts & Forms" }),
|
|
6010
|
+
(() => {
|
|
6011
|
+
const rows = [
|
|
6012
|
+
{ label: "Contacts (total)", value: dashboardStats?.contacts.total || 0 },
|
|
6013
|
+
{ label: "New contacts", value: dashboardStats?.contacts.recent || 0 },
|
|
6014
|
+
{ label: "Submissions", value: dashboardStats?.forms.submissions || 0 },
|
|
6015
|
+
{ label: "New submissions", value: dashboardStats?.forms.recentSubmissions || 0 }
|
|
6016
|
+
];
|
|
6017
|
+
const max = Math.max(...rows.map((r) => r.value), 0);
|
|
6018
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "space-y-2", children: rows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { children: [
|
|
6019
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between text-xs mb-1", children: [
|
|
6020
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-gray-600", children: r.label }),
|
|
6021
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-semibold text-gray-900", children: r.value })
|
|
6022
|
+
] }),
|
|
6023
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "h-2 rounded bg-gray-100 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: `h-2 rounded ${metricBarColor(r.label)}`, style: { width: `${safePct(r.value, max)}%` } }) })
|
|
6024
|
+
] }, r.label)) });
|
|
6025
|
+
})()
|
|
6026
|
+
] }),
|
|
6027
|
+
storeEnabled && ecommerceData && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { children: [
|
|
6028
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h4", { className: "text-xs font-semibold text-gray-700 mb-2", children: "Sales, Returns & Products" }),
|
|
6029
|
+
(() => {
|
|
6030
|
+
const salesBase = Math.max(ecommerceData.kpis.grossSales, 1);
|
|
6031
|
+
const rows = [
|
|
6032
|
+
{ label: "Net sales", value: ecommerceData.kpis.netSales, display: formatMoney4(ecommerceData.kpis.netSales) },
|
|
6033
|
+
{ label: "Gross sales", value: ecommerceData.kpis.grossSales, display: formatMoney4(ecommerceData.kpis.grossSales) },
|
|
6034
|
+
{ label: "Return value", value: ecommerceData.kpis.returnValue, display: formatMoney4(ecommerceData.kpis.returnValue) },
|
|
6035
|
+
{ label: "Return rate", value: ecommerceData.kpis.returnRate, display: `${ecommerceData.kpis.returnRate.toFixed(1)}%` }
|
|
6036
|
+
];
|
|
6037
|
+
const topProduct = ecommerceData.topProducts[0];
|
|
6038
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "space-y-2", children: [
|
|
6039
|
+
rows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { children: [
|
|
6040
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between text-xs mb-1", children: [
|
|
6041
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-gray-600", children: r.label }),
|
|
6042
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-semibold text-gray-900", children: r.display })
|
|
6043
|
+
] }),
|
|
6044
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "h-2 rounded bg-gray-100 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
6045
|
+
"div",
|
|
6046
|
+
{
|
|
6047
|
+
className: `h-2 rounded ${metricBarColor(r.label)}`,
|
|
6048
|
+
style: { width: `${r.label === "Return rate" ? Math.max(6, Math.round(r.value)) : safePct(r.value, salesBase)}%` }
|
|
6049
|
+
}
|
|
6050
|
+
) })
|
|
6051
|
+
] }, r.label)),
|
|
6052
|
+
topProduct && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "pt-1 text-xs text-gray-600", children: [
|
|
6053
|
+
"Top product: ",
|
|
6054
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-medium text-gray-900", children: topProduct.name }),
|
|
6055
|
+
" (",
|
|
6056
|
+
topProduct.units,
|
|
6057
|
+
" units)"
|
|
6058
|
+
] })
|
|
6059
|
+
] });
|
|
6060
|
+
})()
|
|
6061
|
+
] })
|
|
6062
|
+
] })
|
|
6063
|
+
] }),
|
|
6064
|
+
activeTab === "overview" && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-6 mb-7", children: [
|
|
6065
|
+
storeEnabled && ecommerceData && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-200 p-4 shadow-sm", children: [
|
|
6066
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-sm font-semibold text-gray-800 mb-3", children: "Sales vs Returns vs Replacements" }),
|
|
6067
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "h-56", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
6068
|
+
import_react_chartjs_22.Doughnut,
|
|
6069
|
+
{
|
|
6070
|
+
data: {
|
|
6071
|
+
labels: ["Sales", "Returns", "Replacements"],
|
|
6072
|
+
datasets: [
|
|
6073
|
+
{
|
|
6074
|
+
data: [
|
|
6075
|
+
ecommerceData.salesBreakdown?.sales.value ?? ecommerceData.kpis.grossSales,
|
|
6076
|
+
ecommerceData.salesBreakdown?.returns.value ?? ecommerceData.kpis.returnValue,
|
|
6077
|
+
ecommerceData.salesBreakdown?.replacements.value ?? 0
|
|
6078
|
+
],
|
|
6079
|
+
backgroundColor: [
|
|
6080
|
+
salesBreakdownPalette.sales,
|
|
6081
|
+
salesBreakdownPalette.returns,
|
|
6082
|
+
salesBreakdownPalette.replacements
|
|
6083
|
+
],
|
|
6084
|
+
borderWidth: 0
|
|
6085
|
+
}
|
|
6086
|
+
]
|
|
6087
|
+
},
|
|
6088
|
+
options: {
|
|
6089
|
+
maintainAspectRatio: false,
|
|
6090
|
+
plugins: {
|
|
6091
|
+
legend: { position: "bottom" }
|
|
6092
|
+
}
|
|
6093
|
+
}
|
|
6094
|
+
}
|
|
6095
|
+
) })
|
|
6096
|
+
] }),
|
|
6097
|
+
storeEnabled && ecommerceData && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-200 p-4 shadow-sm", children: [
|
|
6098
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-sm font-semibold text-gray-800 mb-3", children: "Product-wise Sales (Top)" }),
|
|
6099
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "h-56", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
6100
|
+
import_react_chartjs_22.Doughnut,
|
|
6101
|
+
{
|
|
6102
|
+
data: {
|
|
6103
|
+
labels: ecommerceData.topProducts.map((p) => p.name),
|
|
6104
|
+
datasets: [
|
|
6105
|
+
{
|
|
6106
|
+
data: ecommerceData.topProducts.map((p) => p.sales),
|
|
6107
|
+
backgroundColor: productPalette.slice(0, Math.max(3, ecommerceData.topProducts.length)),
|
|
6108
|
+
borderWidth: 0
|
|
6109
|
+
}
|
|
6110
|
+
]
|
|
6111
|
+
},
|
|
6112
|
+
options: {
|
|
6113
|
+
maintainAspectRatio: false,
|
|
6114
|
+
plugins: {
|
|
6115
|
+
legend: { position: "bottom" }
|
|
6116
|
+
}
|
|
6117
|
+
}
|
|
6118
|
+
}
|
|
6119
|
+
) })
|
|
6120
|
+
] }),
|
|
6121
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-200 p-4 shadow-sm", children: [
|
|
6122
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-sm font-semibold text-gray-800 mb-3", children: "Contact Distribution" }),
|
|
6123
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "h-56", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
6124
|
+
import_react_chartjs_22.Doughnut,
|
|
6125
|
+
{
|
|
6126
|
+
data: {
|
|
6127
|
+
labels: (dashboardStats?.contactTypes?.length ? dashboardStats.contactTypes : [{ type: "unknown", count: dashboardStats?.contacts.total || 0 }]).map((c) => c.type),
|
|
6128
|
+
datasets: [
|
|
6129
|
+
{
|
|
6130
|
+
data: (dashboardStats?.contactTypes?.length ? dashboardStats.contactTypes : [{ type: "unknown", count: dashboardStats?.contacts.total || 0 }]).map((c) => c.count),
|
|
6131
|
+
backgroundColor: (dashboardStats?.contactTypes?.length ? dashboardStats.contactTypes : [{ type: "unknown", count: dashboardStats?.contacts.total || 0 }]).map((c) => contactTypeColor(c.type)),
|
|
6132
|
+
borderWidth: 0
|
|
6133
|
+
}
|
|
6134
|
+
]
|
|
6135
|
+
},
|
|
6136
|
+
options: {
|
|
6137
|
+
maintainAspectRatio: false,
|
|
6138
|
+
plugins: {
|
|
6139
|
+
legend: { position: "bottom" }
|
|
6140
|
+
}
|
|
6141
|
+
}
|
|
6142
|
+
}
|
|
6143
|
+
) })
|
|
6144
|
+
] })
|
|
6145
|
+
] }),
|
|
6146
|
+
activeTab === "overview" && analyticsEnabled && !isLoading && analyticsData && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
5690
6147
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "mb-4", children: [
|
|
5691
6148
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center mb-2", children: [
|
|
5692
6149
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.Globe, { className: "w-4 h-4 text-gray-600 mr-2" }),
|
|
@@ -5772,31 +6229,279 @@ function DashboardPage() {
|
|
|
5772
6229
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "border-t-2 border-dotted border-gray-200 my-6" }),
|
|
5773
6230
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "mb-6", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(GeographicMap, { data: analyticsData.geographicData }) })
|
|
5774
6231
|
] }),
|
|
6232
|
+
activeTab === "crm" && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
6233
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "mb-4", children: [
|
|
6234
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center mb-2", children: [
|
|
6235
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.Users, { className: "w-4 h-4 text-gray-600 mr-2" }),
|
|
6236
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h2", { className: "text-sm font-semibold text-gray-800", children: "CRM Activity" })
|
|
6237
|
+
] }),
|
|
6238
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3", children: [
|
|
6239
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/contacts"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6240
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "Contacts" }),
|
|
6241
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-lg font-bold text-gray-900", children: dashboardStats?.contacts.total || 0 }),
|
|
6242
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-green-600", children: [
|
|
6243
|
+
"+",
|
|
6244
|
+
dashboardStats?.contacts.recent || 0,
|
|
6245
|
+
" recent"
|
|
6246
|
+
] })
|
|
6247
|
+
] }),
|
|
6248
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/forms"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6249
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "Active Forms" }),
|
|
6250
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-lg font-bold text-gray-900", children: dashboardStats?.forms.total || 0 })
|
|
6251
|
+
] }),
|
|
6252
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/submissions"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6253
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "Form Submissions" }),
|
|
6254
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-lg font-bold text-gray-900", children: dashboardStats?.forms.submissions || 0 }),
|
|
6255
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-green-600", children: [
|
|
6256
|
+
"+",
|
|
6257
|
+
dashboardStats?.forms.recentSubmissions || 0,
|
|
6258
|
+
" recent"
|
|
6259
|
+
] })
|
|
6260
|
+
] }),
|
|
6261
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/blogs"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6262
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "Blogs" }),
|
|
6263
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-lg font-bold text-gray-900", children: dashboardStats?.blogs || 0 })
|
|
6264
|
+
] })
|
|
6265
|
+
] })
|
|
6266
|
+
] }),
|
|
6267
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6", children: [
|
|
6268
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-100 p-4 shadow-sm", children: [
|
|
6269
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-semibold text-gray-800 mb-3", children: "Engagement Funnel" }),
|
|
6270
|
+
(() => {
|
|
6271
|
+
const contacts = dashboardStats?.contacts.total || 0;
|
|
6272
|
+
const submissions = dashboardStats?.forms.submissions || 0;
|
|
6273
|
+
const visitors = analyticsData?.visitors || 0;
|
|
6274
|
+
const base = Math.max(visitors, contacts, submissions, 1);
|
|
6275
|
+
const rows = [
|
|
6276
|
+
{ label: "Visitors", value: visitors },
|
|
6277
|
+
{ label: "Contacts", value: contacts },
|
|
6278
|
+
{ label: "Submissions", value: submissions }
|
|
6279
|
+
];
|
|
6280
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "space-y-3", children: [
|
|
6281
|
+
rows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { children: [
|
|
6282
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between text-xs mb-1", children: [
|
|
6283
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-gray-600", children: r.label }),
|
|
6284
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-semibold text-gray-900", children: r.value.toLocaleString() })
|
|
6285
|
+
] }),
|
|
6286
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "h-2 rounded bg-gray-100 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "h-2 bg-gray-700 rounded", style: { width: `${safePct(r.value, base)}%` } }) })
|
|
6287
|
+
] }, r.label)),
|
|
6288
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "pt-1 text-xs text-gray-600", children: [
|
|
6289
|
+
"Contact rate:",
|
|
6290
|
+
" ",
|
|
6291
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "font-semibold text-gray-900", children: [
|
|
6292
|
+
visitors > 0 ? (contacts / visitors * 100).toFixed(1) : "0.0",
|
|
6293
|
+
"%"
|
|
6294
|
+
] }),
|
|
6295
|
+
" ",
|
|
6296
|
+
" | Submission rate:",
|
|
6297
|
+
" ",
|
|
6298
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "font-semibold text-gray-900", children: [
|
|
6299
|
+
visitors > 0 ? (submissions / visitors * 100).toFixed(1) : "0.0",
|
|
6300
|
+
"%"
|
|
6301
|
+
] })
|
|
6302
|
+
] })
|
|
6303
|
+
] });
|
|
6304
|
+
})()
|
|
6305
|
+
] }),
|
|
6306
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-100 p-4 shadow-sm", children: [
|
|
6307
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-semibold text-gray-800 mb-3", children: "CRM Distribution" }),
|
|
6308
|
+
(() => {
|
|
6309
|
+
const contacts = dashboardStats?.contacts.total || 0;
|
|
6310
|
+
const forms = dashboardStats?.forms.total || 0;
|
|
6311
|
+
const blogs = dashboardStats?.blogs || 0;
|
|
6312
|
+
const users = dashboardStats?.users || 0;
|
|
6313
|
+
const base = Math.max(contacts, forms, blogs, users, 1);
|
|
6314
|
+
const rows = [
|
|
6315
|
+
{ label: "Contacts", value: contacts },
|
|
6316
|
+
{ label: "Forms", value: forms },
|
|
6317
|
+
{ label: "Blogs", value: blogs },
|
|
6318
|
+
{ label: "Users", value: users }
|
|
6319
|
+
];
|
|
6320
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "space-y-2", children: rows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { children: [
|
|
6321
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between text-xs mb-1", children: [
|
|
6322
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-gray-600", children: r.label }),
|
|
6323
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-semibold text-gray-900", children: r.value })
|
|
6324
|
+
] }),
|
|
6325
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "h-2 rounded bg-gray-100 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "h-2 bg-gray-700 rounded", style: { width: `${safePct(r.value, base)}%` } }) })
|
|
6326
|
+
] }, r.label)) });
|
|
6327
|
+
})()
|
|
6328
|
+
] })
|
|
6329
|
+
] }),
|
|
6330
|
+
analyticsEnabled && analyticsData && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-100 p-4 shadow-sm mb-2", children: [
|
|
6331
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-semibold text-gray-800 mb-3", children: "Top Content & Sources" }),
|
|
6332
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6", children: [
|
|
6333
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { children: [
|
|
6334
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs font-semibold text-gray-700 mb-2", children: "Top Pages" }),
|
|
6335
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "space-y-1", children: analyticsData.topPages.slice(0, 5).map((page, index) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between text-xs", children: [
|
|
6336
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-gray-600 truncate max-w-[75%]", children: page.page }),
|
|
6337
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-semibold text-gray-900", children: page.views.toLocaleString() })
|
|
6338
|
+
] }, index)) })
|
|
6339
|
+
] }),
|
|
6340
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { children: [
|
|
6341
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs font-semibold text-gray-700 mb-2", children: "Traffic Sources" }),
|
|
6342
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "space-y-1", children: analyticsData.trafficSources.slice(0, 5).map((source, index) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between text-xs", children: [
|
|
6343
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-gray-600", children: source.source }),
|
|
6344
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-semibold text-gray-900", children: source.sessions.toLocaleString() })
|
|
6345
|
+
] }, index)) })
|
|
6346
|
+
] })
|
|
6347
|
+
] })
|
|
6348
|
+
] })
|
|
6349
|
+
] }),
|
|
6350
|
+
activeTab === "sales" && !isLoading && storeEnabled && ecommerceData && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
6351
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "border-t-2 border-dotted border-gray-200 my-6" }),
|
|
6352
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "mb-4", children: [
|
|
6353
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center mb-2", children: [
|
|
6354
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.BarChart3, { className: "w-4 h-4 text-gray-600 mr-2" }),
|
|
6355
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h2", { className: "text-sm font-semibold text-gray-800", children: "Store Analytics" })
|
|
6356
|
+
] }),
|
|
6357
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3", children: [
|
|
6358
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/orders"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6359
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "Net Sales" }),
|
|
6360
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-lg font-bold text-gray-900", children: formatMoney4(ecommerceData.kpis.netSales) })
|
|
6361
|
+
] }),
|
|
6362
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/orders"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6363
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "Orders" }),
|
|
6364
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-lg font-bold text-gray-900", children: ecommerceData.kpis.ordersPlaced })
|
|
6365
|
+
] }),
|
|
6366
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/orders"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6367
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "AOV" }),
|
|
6368
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-lg font-bold text-gray-900", children: formatMoney4(ecommerceData.kpis.averageOrderValue) })
|
|
6369
|
+
] }),
|
|
6370
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/contacts"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6371
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "Returning Customer Rate" }),
|
|
6372
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-lg font-bold text-gray-900", children: [
|
|
6373
|
+
ecommerceData.kpis.returningCustomerRate.toFixed(1),
|
|
6374
|
+
"%"
|
|
6375
|
+
] })
|
|
6376
|
+
] }),
|
|
6377
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/orders"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6378
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "Return Rate" }),
|
|
6379
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-lg font-bold text-gray-900", children: [
|
|
6380
|
+
ecommerceData.kpis.returnRate.toFixed(1),
|
|
6381
|
+
"%"
|
|
6382
|
+
] })
|
|
6383
|
+
] }),
|
|
6384
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("button", { onClick: () => router.push("/admin/payments"), className: "text-left bg-white rounded border border-gray-200 p-2.5 shadow-sm", children: [
|
|
6385
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-600", children: "Payment Success" }),
|
|
6386
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-lg font-bold text-gray-900", children: [
|
|
6387
|
+
ecommerceData.kpis.paymentSuccessRate.toFixed(1),
|
|
6388
|
+
"%"
|
|
6389
|
+
] })
|
|
6390
|
+
] })
|
|
6391
|
+
] })
|
|
6392
|
+
] }),
|
|
6393
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6", children: [
|
|
6394
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-100 p-4 shadow-sm", children: [
|
|
6395
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-semibold text-gray-800 mb-3", children: "Sales Over Time" }),
|
|
6396
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "space-y-2 max-h-64 overflow-auto", children: ecommerceData.salesOverTime.slice(-10).map((point) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between text-xs", children: [
|
|
6397
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-gray-600", children: point.date }),
|
|
6398
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "font-semibold text-gray-900", children: [
|
|
6399
|
+
formatMoney4(point.value),
|
|
6400
|
+
" (",
|
|
6401
|
+
point.orders,
|
|
6402
|
+
")"
|
|
6403
|
+
] })
|
|
6404
|
+
] }, point.date)) })
|
|
6405
|
+
] }),
|
|
6406
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-100 p-4 shadow-sm", children: [
|
|
6407
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-semibold text-gray-800 mb-3", children: "Top Products" }),
|
|
6408
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "space-y-2", children: ecommerceData.topProducts.map((p, idx) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
6409
|
+
"button",
|
|
6410
|
+
{
|
|
6411
|
+
onClick: () => router.push("/admin/products"),
|
|
6412
|
+
className: "w-full text-left flex items-center justify-between p-2 bg-gray-50 rounded-lg",
|
|
6413
|
+
children: [
|
|
6414
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-xs text-gray-700 truncate max-w-[70%]", children: p.name }),
|
|
6415
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "text-xs font-semibold text-gray-900", children: [
|
|
6416
|
+
p.units,
|
|
6417
|
+
" / ",
|
|
6418
|
+
formatMoney4(p.sales)
|
|
6419
|
+
] })
|
|
6420
|
+
]
|
|
6421
|
+
},
|
|
6422
|
+
`${p.name}-${idx}`
|
|
6423
|
+
)) })
|
|
6424
|
+
] })
|
|
6425
|
+
] }),
|
|
6426
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-6 mb-2", children: [
|
|
6427
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-100 p-4 shadow-sm", children: [
|
|
6428
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-semibold text-gray-800 mb-2", children: "Customer Mix" }),
|
|
6429
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-gray-700", children: [
|
|
6430
|
+
"New: ",
|
|
6431
|
+
ecommerceData.customerMix.newCustomers
|
|
6432
|
+
] }),
|
|
6433
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-gray-700", children: [
|
|
6434
|
+
"Returning: ",
|
|
6435
|
+
ecommerceData.customerMix.returningCustomers
|
|
6436
|
+
] }),
|
|
6437
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-gray-700", children: [
|
|
6438
|
+
"Repeat rate: ",
|
|
6439
|
+
ecommerceData.customerMix.repeatPurchaseRate.toFixed(1),
|
|
6440
|
+
"%"
|
|
6441
|
+
] })
|
|
6442
|
+
] }),
|
|
6443
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-100 p-4 shadow-sm", children: [
|
|
6444
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-semibold text-gray-800 mb-2", children: "Returns Trend" }),
|
|
6445
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-gray-700", children: [
|
|
6446
|
+
"Return value: ",
|
|
6447
|
+
formatMoney4(ecommerceData.kpis.returnValue)
|
|
6448
|
+
] }),
|
|
6449
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-gray-700", children: [
|
|
6450
|
+
"Return orders: ",
|
|
6451
|
+
ecommerceData.returnsTrend.reduce((s, r) => s + r.count, 0)
|
|
6452
|
+
] }),
|
|
6453
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-gray-700", children: [
|
|
6454
|
+
"Return rate: ",
|
|
6455
|
+
ecommerceData.kpis.returnRate.toFixed(1),
|
|
6456
|
+
"%"
|
|
6457
|
+
] })
|
|
6458
|
+
] }),
|
|
6459
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "bg-white rounded-lg border border-gray-100 p-4 shadow-sm", children: [
|
|
6460
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-semibold text-gray-800 mb-2", children: "Inventory Risk" }),
|
|
6461
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-gray-700", children: [
|
|
6462
|
+
"Out of stock: ",
|
|
6463
|
+
ecommerceData.inventoryRisk.outOfStockCount
|
|
6464
|
+
] }),
|
|
6465
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-gray-700", children: [
|
|
6466
|
+
"Low stock: ",
|
|
6467
|
+
ecommerceData.inventoryRisk.lowStockCount
|
|
6468
|
+
] }),
|
|
6469
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-gray-700", children: [
|
|
6470
|
+
"Total units: ",
|
|
6471
|
+
ecommerceData.inventoryRisk.totalInventory
|
|
6472
|
+
] })
|
|
6473
|
+
] })
|
|
6474
|
+
] })
|
|
6475
|
+
] }),
|
|
5775
6476
|
isLoading && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-center py-8", children: [
|
|
5776
6477
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "animate-spin rounded-full h-5 w-5 border-2 border-gray-300 border-t-gray-600" }),
|
|
5777
6478
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "ml-2 text-sm text-gray-600", children: "Loading dashboard data..." })
|
|
5778
6479
|
] }),
|
|
5779
|
-
!isLoading && !analyticsEnabled && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "text-center py-8", children: [
|
|
6480
|
+
!isLoading && activeTab === "overview" && !analyticsEnabled && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "text-center py-8", children: [
|
|
5780
6481
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react22.Globe, { className: "w-10 h-10 text-gray-400 mx-auto mb-3" }),
|
|
5781
6482
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-medium text-gray-600 mb-1", children: "Analytics Not Configured" }),
|
|
5782
6483
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-500", children: "Google Analytics integration is required to view website analytics." })
|
|
6484
|
+
] }),
|
|
6485
|
+
!isLoading && activeTab === "sales" && !storeEnabled && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "text-center py-8", children: [
|
|
6486
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h3", { className: "text-base font-medium text-gray-600 mb-1", children: "Store analytics unavailable" }),
|
|
6487
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-gray-500", children: "Enable store/ecomm to view sales reports." })
|
|
5783
6488
|
] })
|
|
5784
6489
|
] })
|
|
5785
6490
|
] });
|
|
5786
6491
|
}
|
|
5787
6492
|
|
|
5788
6493
|
// src/admin/pages/AdminPageResolver.tsx
|
|
5789
|
-
var
|
|
5790
|
-
var
|
|
6494
|
+
var import_react48 = require("react");
|
|
6495
|
+
var import_navigation21 = require("next/navigation");
|
|
5791
6496
|
|
|
5792
6497
|
// src/admin/pages/SubmissionDetailPage.tsx
|
|
5793
|
-
var
|
|
6498
|
+
var import_react33 = require("react");
|
|
5794
6499
|
var import_link9 = __toESM(require("next/link"), 1);
|
|
5795
6500
|
var import_lucide_react24 = require("lucide-react");
|
|
5796
6501
|
|
|
5797
6502
|
// src/components/Admin/DetailPageHeader.tsx
|
|
5798
6503
|
var import_link8 = __toESM(require("next/link"), 1);
|
|
5799
|
-
var
|
|
6504
|
+
var import_navigation12 = require("next/navigation");
|
|
5800
6505
|
var import_lucide_react23 = require("lucide-react");
|
|
5801
6506
|
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
5802
6507
|
function DetailPageHeader({
|
|
@@ -5808,7 +6513,7 @@ function DetailPageHeader({
|
|
|
5808
6513
|
onClose,
|
|
5809
6514
|
menuItems = []
|
|
5810
6515
|
}) {
|
|
5811
|
-
const router = (0,
|
|
6516
|
+
const router = (0, import_navigation12.useRouter)();
|
|
5812
6517
|
const handleClose = () => {
|
|
5813
6518
|
if (onClose) onClose();
|
|
5814
6519
|
else if (closeHref) router.push(closeHref);
|
|
@@ -5833,20 +6538,32 @@ function DetailPageHeader({
|
|
|
5833
6538
|
] })
|
|
5834
6539
|
] }),
|
|
5835
6540
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
5836
|
-
menuItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
5837
|
-
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
6541
|
+
menuItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
|
|
6542
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex items-center gap-2 md:hidden", children: menuItems.map((item, i) => {
|
|
6543
|
+
const Icon2 = item.icon;
|
|
6544
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
6545
|
+
Button,
|
|
6546
|
+
{
|
|
6547
|
+
variant: item.variant ?? "outline",
|
|
6548
|
+
size: "icon",
|
|
6549
|
+
className: "h-8 w-8 border border-gray-600 bg-transparent text-white hover:bg-gray-700",
|
|
6550
|
+
onClick: item.onClick,
|
|
6551
|
+
title: item.label,
|
|
6552
|
+
children: [
|
|
6553
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Icon2, { className: "h-4 w-4" }),
|
|
6554
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "sr-only", children: item.label })
|
|
6555
|
+
]
|
|
6556
|
+
},
|
|
6557
|
+
i
|
|
6558
|
+
);
|
|
6559
|
+
}) }),
|
|
6560
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "hidden md:flex items-center gap-2", children: menuItems.map((item, i) => {
|
|
6561
|
+
const Icon2 = item.icon;
|
|
6562
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(Button, { variant: item.variant ?? "outline", size: "sm", onClick: item.onClick, children: [
|
|
6563
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Icon2, { className: "h-4 w-4 mr-1" }),
|
|
6564
|
+
item.label
|
|
6565
|
+
] }, i);
|
|
6566
|
+
}) })
|
|
5850
6567
|
] }),
|
|
5851
6568
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
5852
6569
|
Button,
|
|
@@ -5868,10 +6585,10 @@ function DetailPageHeader({
|
|
|
5868
6585
|
// src/admin/pages/SubmissionDetailPage.tsx
|
|
5869
6586
|
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
5870
6587
|
function SubmissionDetailPage({ submissionId }) {
|
|
5871
|
-
const [submission, setSubmission] = (0,
|
|
5872
|
-
const [loading, setLoading] = (0,
|
|
5873
|
-
const [error, setError] = (0,
|
|
5874
|
-
(0,
|
|
6588
|
+
const [submission, setSubmission] = (0, import_react33.useState)(null);
|
|
6589
|
+
const [loading, setLoading] = (0, import_react33.useState)(true);
|
|
6590
|
+
const [error, setError] = (0, import_react33.useState)(null);
|
|
6591
|
+
(0, import_react33.useEffect)(() => {
|
|
5875
6592
|
async function load() {
|
|
5876
6593
|
try {
|
|
5877
6594
|
setLoading(true);
|
|
@@ -5979,9 +6696,9 @@ function SubmissionDetailPage({ submissionId }) {
|
|
|
5979
6696
|
}
|
|
5980
6697
|
|
|
5981
6698
|
// src/admin/pages/OrderDetailPage.tsx
|
|
5982
|
-
var
|
|
6699
|
+
var import_react34 = require("react");
|
|
5983
6700
|
var import_link10 = __toESM(require("next/link"), 1);
|
|
5984
|
-
var
|
|
6701
|
+
var import_navigation13 = require("next/navigation");
|
|
5985
6702
|
var import_lucide_react25 = require("lucide-react");
|
|
5986
6703
|
|
|
5987
6704
|
// src/components/Admin/DetailPageLayout.tsx
|
|
@@ -6023,13 +6740,13 @@ function formatAddress(a) {
|
|
|
6023
6740
|
return parts.join(", ") || "\u2014";
|
|
6024
6741
|
}
|
|
6025
6742
|
function OrderDetailPage({ orderId }) {
|
|
6026
|
-
const router = (0,
|
|
6027
|
-
const [order, setOrder] = (0,
|
|
6028
|
-
const [loading, setLoading] = (0,
|
|
6029
|
-
const [error, setError] = (0,
|
|
6030
|
-
const [erpEnabled, setErpEnabled] = (0,
|
|
6031
|
-
const [reposting, setReposting] = (0,
|
|
6032
|
-
(0,
|
|
6743
|
+
const router = (0, import_navigation13.useRouter)();
|
|
6744
|
+
const [order, setOrder] = (0, import_react34.useState)(null);
|
|
6745
|
+
const [loading, setLoading] = (0, import_react34.useState)(true);
|
|
6746
|
+
const [error, setError] = (0, import_react34.useState)(null);
|
|
6747
|
+
const [erpEnabled, setErpEnabled] = (0, import_react34.useState)(false);
|
|
6748
|
+
const [reposting, setReposting] = (0, import_react34.useState)(false);
|
|
6749
|
+
(0, import_react34.useEffect)(() => {
|
|
6033
6750
|
async function load() {
|
|
6034
6751
|
try {
|
|
6035
6752
|
setLoading(true);
|
|
@@ -6052,7 +6769,7 @@ function OrderDetailPage({ orderId }) {
|
|
|
6052
6769
|
}
|
|
6053
6770
|
load();
|
|
6054
6771
|
}, [orderId]);
|
|
6055
|
-
(0,
|
|
6772
|
+
(0, import_react34.useEffect)(() => {
|
|
6056
6773
|
let cancelled = false;
|
|
6057
6774
|
(async () => {
|
|
6058
6775
|
try {
|
|
@@ -6108,7 +6825,7 @@ function OrderDetailPage({ orderId }) {
|
|
|
6108
6825
|
title: `Order ${order.orderNumber}`,
|
|
6109
6826
|
subtitle: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-sm text-gray-400", children: formatDateTime(order.createdAt) }),
|
|
6110
6827
|
closeHref: "/admin/orders",
|
|
6111
|
-
menuItems: erpEnabled ? [{ label: reposting ? "Reposting..." : "Repost to ERP", onClick: handleRepostToErp }] : void 0
|
|
6828
|
+
menuItems: erpEnabled ? [{ label: reposting ? "Reposting..." : "Repost to ERP", icon: import_lucide_react25.RefreshCw, onClick: handleRepostToErp }] : void 0
|
|
6112
6829
|
}
|
|
6113
6830
|
),
|
|
6114
6831
|
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
@@ -6348,9 +7065,9 @@ function OrderDetailPage({ orderId }) {
|
|
|
6348
7065
|
}
|
|
6349
7066
|
|
|
6350
7067
|
// src/admin/pages/PaymentDetailPage.tsx
|
|
6351
|
-
var
|
|
7068
|
+
var import_react35 = require("react");
|
|
6352
7069
|
var import_link11 = __toESM(require("next/link"), 1);
|
|
6353
|
-
var
|
|
7070
|
+
var import_navigation14 = require("next/navigation");
|
|
6354
7071
|
var import_lucide_react26 = require("lucide-react");
|
|
6355
7072
|
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
6356
7073
|
function formatMoney2(amount, currency = "INR") {
|
|
@@ -6361,11 +7078,11 @@ function formatMoney2(amount, currency = "INR") {
|
|
|
6361
7078
|
}).format(Number(amount));
|
|
6362
7079
|
}
|
|
6363
7080
|
function PaymentDetailPage({ paymentId }) {
|
|
6364
|
-
const router = (0,
|
|
6365
|
-
const [payment, setPayment] = (0,
|
|
6366
|
-
const [loading, setLoading] = (0,
|
|
6367
|
-
const [error, setError] = (0,
|
|
6368
|
-
(0,
|
|
7081
|
+
const router = (0, import_navigation14.useRouter)();
|
|
7082
|
+
const [payment, setPayment] = (0, import_react35.useState)(null);
|
|
7083
|
+
const [loading, setLoading] = (0, import_react35.useState)(true);
|
|
7084
|
+
const [error, setError] = (0, import_react35.useState)(null);
|
|
7085
|
+
(0, import_react35.useEffect)(() => {
|
|
6369
7086
|
async function load() {
|
|
6370
7087
|
try {
|
|
6371
7088
|
setLoading(true);
|
|
@@ -6507,9 +7224,9 @@ function PaymentDetailPage({ paymentId }) {
|
|
|
6507
7224
|
}
|
|
6508
7225
|
|
|
6509
7226
|
// src/admin/pages/ContactDetailPage.tsx
|
|
6510
|
-
var
|
|
7227
|
+
var import_react36 = require("react");
|
|
6511
7228
|
var import_link12 = __toESM(require("next/link"), 1);
|
|
6512
|
-
var
|
|
7229
|
+
var import_navigation15 = require("next/navigation");
|
|
6513
7230
|
var import_lucide_react27 = require("lucide-react");
|
|
6514
7231
|
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
6515
7232
|
function formatMoney3(amount, currency = "INR") {
|
|
@@ -6525,13 +7242,13 @@ function formatAddress2(a) {
|
|
|
6525
7242
|
}
|
|
6526
7243
|
var ADDRESS_TAGS = [{ value: "", label: "\u2014" }, { value: "default", label: "Default" }, { value: "billing", label: "Billing" }, { value: "shipping", label: "Shipping" }];
|
|
6527
7244
|
function ContactDetailPage({ contactId }) {
|
|
6528
|
-
const router = (0,
|
|
6529
|
-
const [contact, setContact] = (0,
|
|
6530
|
-
const [loading, setLoading] = (0,
|
|
6531
|
-
const [error, setError] = (0,
|
|
6532
|
-
const [addAddressOpen, setAddAddressOpen] = (0,
|
|
6533
|
-
const [addAddressSaving, setAddAddressSaving] = (0,
|
|
6534
|
-
const [addAddressForm, setAddAddressForm] = (0,
|
|
7245
|
+
const router = (0, import_navigation15.useRouter)();
|
|
7246
|
+
const [contact, setContact] = (0, import_react36.useState)(null);
|
|
7247
|
+
const [loading, setLoading] = (0, import_react36.useState)(true);
|
|
7248
|
+
const [error, setError] = (0, import_react36.useState)(null);
|
|
7249
|
+
const [addAddressOpen, setAddAddressOpen] = (0, import_react36.useState)(false);
|
|
7250
|
+
const [addAddressSaving, setAddAddressSaving] = (0, import_react36.useState)(false);
|
|
7251
|
+
const [addAddressForm, setAddAddressForm] = (0, import_react36.useState)({
|
|
6535
7252
|
tag: "",
|
|
6536
7253
|
line1: "",
|
|
6537
7254
|
line2: "",
|
|
@@ -6543,7 +7260,7 @@ function ContactDetailPage({ contactId }) {
|
|
|
6543
7260
|
const loadContact = () => {
|
|
6544
7261
|
fetch(`/api/contacts/${contactId}`).then((res) => res.ok ? res.json() : null).then((data) => setContact(data)).catch(() => setContact(null));
|
|
6545
7262
|
};
|
|
6546
|
-
(0,
|
|
7263
|
+
(0, import_react36.useEffect)(() => {
|
|
6547
7264
|
async function load() {
|
|
6548
7265
|
try {
|
|
6549
7266
|
setLoading(true);
|
|
@@ -6879,9 +7596,9 @@ function ContactDetailPage({ contactId }) {
|
|
|
6879
7596
|
}
|
|
6880
7597
|
|
|
6881
7598
|
// src/admin/pages/SettingsPage.tsx
|
|
6882
|
-
var
|
|
6883
|
-
var
|
|
6884
|
-
var
|
|
7599
|
+
var import_react37 = require("react");
|
|
7600
|
+
var import_navigation16 = require("next/navigation");
|
|
7601
|
+
var import_sonner5 = require("sonner");
|
|
6885
7602
|
var import_lucide_react28 = require("lucide-react");
|
|
6886
7603
|
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
6887
7604
|
var DEFAULTS = {
|
|
@@ -6905,25 +7622,25 @@ function hexToHsl(hex) {
|
|
|
6905
7622
|
return `${Math.round(h * 360)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;
|
|
6906
7623
|
}
|
|
6907
7624
|
function SettingsPage() {
|
|
6908
|
-
const searchParams = (0,
|
|
7625
|
+
const searchParams = (0, import_navigation16.useSearchParams)();
|
|
6909
7626
|
const tabParam = searchParams.get("tab");
|
|
6910
|
-
const { theme, themeRegistry } = (0,
|
|
6911
|
-
const [tab, setTab] = (0,
|
|
7627
|
+
const { theme, themeRegistry } = (0, import_react37.useContext)(AdminConfigContext);
|
|
7628
|
+
const [tab, setTab] = (0, import_react37.useState)(
|
|
6912
7629
|
tabParam === "navbar" ? "navbar" : tabParam === "store" ? "store" : "appearance"
|
|
6913
7630
|
);
|
|
6914
|
-
(0,
|
|
7631
|
+
(0, import_react37.useEffect)(() => {
|
|
6915
7632
|
if (tabParam === "navbar") setTab("navbar");
|
|
6916
7633
|
else if (tabParam === "store") setTab("store");
|
|
6917
7634
|
}, [tabParam]);
|
|
6918
|
-
const [settings, setSettings] = (0,
|
|
6919
|
-
const [loading, setLoading] = (0,
|
|
6920
|
-
const [saving, setSaving] = (0,
|
|
6921
|
-
const [activeThemeId, setActiveThemeId] = (0,
|
|
6922
|
-
const [navbarConfig, setNavbarConfig] = (0,
|
|
6923
|
-
const [themeSettingsLoading, setThemeSettingsLoading] = (0,
|
|
6924
|
-
const [storeEnabled, setStoreEnabled] = (0,
|
|
6925
|
-
const [storeSettingsLoading, setStoreSettingsLoading] = (0,
|
|
6926
|
-
(0,
|
|
7635
|
+
const [settings, setSettings] = (0, import_react37.useState)(DEFAULTS);
|
|
7636
|
+
const [loading, setLoading] = (0, import_react37.useState)(true);
|
|
7637
|
+
const [saving, setSaving] = (0, import_react37.useState)(false);
|
|
7638
|
+
const [activeThemeId, setActiveThemeId] = (0, import_react37.useState)("");
|
|
7639
|
+
const [navbarConfig, setNavbarConfig] = (0, import_react37.useState)({ logo: "", items: [], ctaLabel: "", ctaUrl: "" });
|
|
7640
|
+
const [themeSettingsLoading, setThemeSettingsLoading] = (0, import_react37.useState)(true);
|
|
7641
|
+
const [storeEnabled, setStoreEnabled] = (0, import_react37.useState)(false);
|
|
7642
|
+
const [storeSettingsLoading, setStoreSettingsLoading] = (0, import_react37.useState)(true);
|
|
7643
|
+
(0, import_react37.useEffect)(() => {
|
|
6927
7644
|
fetch("/api/settings/admin_view").then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
6928
7645
|
setSettings({
|
|
6929
7646
|
primaryColor: data.primaryColor || DEFAULTS.primaryColor,
|
|
@@ -6932,7 +7649,7 @@ function SettingsPage() {
|
|
|
6932
7649
|
});
|
|
6933
7650
|
}).finally(() => setLoading(false));
|
|
6934
7651
|
}, []);
|
|
6935
|
-
(0,
|
|
7652
|
+
(0, import_react37.useEffect)(() => {
|
|
6936
7653
|
fetch("/api/settings/theme").then((r) => r.ok ? r.json() : null).then((data) => {
|
|
6937
7654
|
if (!data) return;
|
|
6938
7655
|
setActiveThemeId((data.activeThemeId || "").trim());
|
|
@@ -6944,7 +7661,7 @@ function SettingsPage() {
|
|
|
6944
7661
|
}
|
|
6945
7662
|
}).finally(() => setThemeSettingsLoading(false));
|
|
6946
7663
|
}, []);
|
|
6947
|
-
(0,
|
|
7664
|
+
(0, import_react37.useEffect)(() => {
|
|
6948
7665
|
fetch("/api/settings/store").then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
6949
7666
|
setStoreEnabled(data.enabled === "true");
|
|
6950
7667
|
}).finally(() => setStoreSettingsLoading(false));
|
|
@@ -6968,9 +7685,9 @@ function SettingsPage() {
|
|
|
6968
7685
|
document.documentElement.style.setProperty("--secondary", hexToHsl(settings.secondaryColor));
|
|
6969
7686
|
if (settings.compactView === "true") document.documentElement.classList.add("compact");
|
|
6970
7687
|
else document.documentElement.classList.remove("compact");
|
|
6971
|
-
|
|
7688
|
+
import_sonner5.toast.success("Settings saved");
|
|
6972
7689
|
} catch {
|
|
6973
|
-
|
|
7690
|
+
import_sonner5.toast.error("Failed to save settings");
|
|
6974
7691
|
} finally {
|
|
6975
7692
|
setSaving(false);
|
|
6976
7693
|
}
|
|
@@ -6984,10 +7701,10 @@ function SettingsPage() {
|
|
|
6984
7701
|
headers: { "Content-Type": "application/json" },
|
|
6985
7702
|
body: JSON.stringify({ activeThemeId: { value: id, type: "public" } })
|
|
6986
7703
|
});
|
|
6987
|
-
|
|
7704
|
+
import_sonner5.toast.success("Theme updated");
|
|
6988
7705
|
window.location.reload();
|
|
6989
7706
|
} catch {
|
|
6990
|
-
|
|
7707
|
+
import_sonner5.toast.error("Failed to save theme");
|
|
6991
7708
|
} finally {
|
|
6992
7709
|
setSaving(false);
|
|
6993
7710
|
}
|
|
@@ -7000,9 +7717,9 @@ function SettingsPage() {
|
|
|
7000
7717
|
headers: { "Content-Type": "application/json" },
|
|
7001
7718
|
body: JSON.stringify({ navbar: { value: JSON.stringify(navbarConfig), type: "public" } })
|
|
7002
7719
|
});
|
|
7003
|
-
|
|
7720
|
+
import_sonner5.toast.success("Navbar saved");
|
|
7004
7721
|
} catch {
|
|
7005
|
-
|
|
7722
|
+
import_sonner5.toast.error("Failed to save");
|
|
7006
7723
|
} finally {
|
|
7007
7724
|
setSaving(false);
|
|
7008
7725
|
}
|
|
@@ -7015,10 +7732,10 @@ function SettingsPage() {
|
|
|
7015
7732
|
headers: { "Content-Type": "application/json" },
|
|
7016
7733
|
body: JSON.stringify({ enabled: { value: storeEnabled ? "true" : "false", type: "public" } })
|
|
7017
7734
|
});
|
|
7018
|
-
|
|
7735
|
+
import_sonner5.toast.success("Store settings saved");
|
|
7019
7736
|
window.location.reload();
|
|
7020
7737
|
} catch {
|
|
7021
|
-
|
|
7738
|
+
import_sonner5.toast.error("Failed to save store settings");
|
|
7022
7739
|
} finally {
|
|
7023
7740
|
setSaving(false);
|
|
7024
7741
|
}
|
|
@@ -7134,11 +7851,24 @@ function SettingsPage() {
|
|
|
7134
7851
|
}
|
|
7135
7852
|
|
|
7136
7853
|
// src/admin/pages/MediaLibraryPage.tsx
|
|
7137
|
-
var
|
|
7854
|
+
var import_react38 = __toESM(require("react"), 1);
|
|
7855
|
+
|
|
7856
|
+
// src/lib/media-zip-extract.ts
|
|
7857
|
+
var import_typeorm = require("typeorm");
|
|
7858
|
+
var ZIP_MIME_TYPES = /* @__PURE__ */ new Set(["application/zip", "application/x-zip-compressed"]);
|
|
7859
|
+
var MAX_TOTAL_UNCOMPRESSED = 80 * 1024 * 1024;
|
|
7860
|
+
function isZipMedia(mime, filename) {
|
|
7861
|
+
if (mime && ZIP_MIME_TYPES.has(mime)) return true;
|
|
7862
|
+
return filename.toLowerCase().endsWith(".zip");
|
|
7863
|
+
}
|
|
7864
|
+
|
|
7865
|
+
// src/admin/pages/MediaLibraryPage.tsx
|
|
7138
7866
|
var import_lucide_react29 = require("lucide-react");
|
|
7139
|
-
var
|
|
7867
|
+
var import_sonner6 = require("sonner");
|
|
7140
7868
|
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
7141
|
-
function getTypeCategory(mime) {
|
|
7869
|
+
function getTypeCategory(mime, kind, filename) {
|
|
7870
|
+
if (kind === "folder" || mime === "inode/directory") return "folder";
|
|
7871
|
+
if (isZipMedia(mime, filename ?? "")) return "zip";
|
|
7142
7872
|
if (!mime) return "other";
|
|
7143
7873
|
if (mime.startsWith("image/")) return "image";
|
|
7144
7874
|
if (mime.startsWith("video/")) return "video";
|
|
@@ -7146,56 +7876,66 @@ function getTypeCategory(mime) {
|
|
|
7146
7876
|
if (mime === "application/pdf" || mime.startsWith("application/")) return "document";
|
|
7147
7877
|
return "other";
|
|
7148
7878
|
}
|
|
7149
|
-
function getTypeLabel(mime) {
|
|
7150
|
-
|
|
7879
|
+
function getTypeLabel(mime, kind, filename) {
|
|
7880
|
+
if (kind === "folder" || mime === "inode/directory") return "Folder";
|
|
7881
|
+
if (isZipMedia(mime, filename ?? "")) return "Zip";
|
|
7882
|
+
const c = getTypeCategory(mime, kind, filename);
|
|
7151
7883
|
const labels = {
|
|
7152
7884
|
image: "Image",
|
|
7153
7885
|
video: "Video",
|
|
7154
7886
|
audio: "Audio",
|
|
7155
7887
|
document: "Document",
|
|
7888
|
+
folder: "Folder",
|
|
7889
|
+
zip: "Zip",
|
|
7156
7890
|
other: "Other"
|
|
7157
7891
|
};
|
|
7158
7892
|
return labels[c] || "Other";
|
|
7159
7893
|
}
|
|
7160
|
-
function TypeIcon({ mimeType }) {
|
|
7161
|
-
|
|
7894
|
+
function TypeIcon({ mimeType, kind, filename }) {
|
|
7895
|
+
if (kind === "folder" || mimeType === "inode/directory") {
|
|
7896
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Folder, { className: "h-10 w-10 text-amber-500" });
|
|
7897
|
+
}
|
|
7898
|
+
if (isZipMedia(mimeType, filename ?? "")) {
|
|
7899
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Archive, { className: "h-10 w-10 text-violet-600" });
|
|
7900
|
+
}
|
|
7901
|
+
const c = getTypeCategory(mimeType, kind, filename);
|
|
7162
7902
|
if (c === "image") return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Image, { className: "h-8 w-8 text-gray-400" });
|
|
7163
7903
|
if (c === "video") return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Film, { className: "h-8 w-8 text-gray-400" });
|
|
7164
7904
|
if (c === "document") return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.FileText, { className: "h-8 w-8 text-gray-400" });
|
|
7165
7905
|
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.File, { className: "h-8 w-8 text-gray-400" });
|
|
7166
7906
|
}
|
|
7167
|
-
function groupByMonth(items) {
|
|
7168
|
-
const groups = {};
|
|
7169
|
-
items.forEach((item) => {
|
|
7170
|
-
const d = new Date(item.createdAt);
|
|
7171
|
-
const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
|
|
7172
|
-
const label = d.toLocaleDateString("en-US", { year: "numeric", month: "long" });
|
|
7173
|
-
if (!groups[label]) groups[label] = [];
|
|
7174
|
-
groups[label].push(item);
|
|
7175
|
-
});
|
|
7176
|
-
return groups;
|
|
7177
|
-
}
|
|
7178
7907
|
function MediaLibraryPage() {
|
|
7179
|
-
const [data, setData] = (0,
|
|
7180
|
-
const [loading, setLoading] = (0,
|
|
7181
|
-
const [page, setPage] = (0,
|
|
7182
|
-
const [totalPages, setTotalPages] = (0,
|
|
7183
|
-
const [search, setSearch] = (0,
|
|
7184
|
-
const [searchInput, setSearchInput] = (0,
|
|
7185
|
-
const [typeFilter, setTypeFilter] = (0,
|
|
7186
|
-
const [
|
|
7187
|
-
const [
|
|
7188
|
-
const [
|
|
7189
|
-
const [
|
|
7190
|
-
const
|
|
7191
|
-
const
|
|
7908
|
+
const [data, setData] = (0, import_react38.useState)([]);
|
|
7909
|
+
const [loading, setLoading] = (0, import_react38.useState)(true);
|
|
7910
|
+
const [page, setPage] = (0, import_react38.useState)(1);
|
|
7911
|
+
const [totalPages, setTotalPages] = (0, import_react38.useState)(1);
|
|
7912
|
+
const [search, setSearch] = (0, import_react38.useState)("");
|
|
7913
|
+
const [searchInput, setSearchInput] = (0, import_react38.useState)("");
|
|
7914
|
+
const [typeFilter, setTypeFilter] = (0, import_react38.useState)("");
|
|
7915
|
+
const [sortField, setSortField] = (0, import_react38.useState)("filename");
|
|
7916
|
+
const [sortOrder, setSortOrder] = (0, import_react38.useState)("asc");
|
|
7917
|
+
const [viewMode, setViewMode] = (0, import_react38.useState)("grid");
|
|
7918
|
+
const [uploading, setUploading] = (0, import_react38.useState)(false);
|
|
7919
|
+
const [currentParentId, setCurrentParentId] = (0, import_react38.useState)(null);
|
|
7920
|
+
const [crumb, setCrumb] = (0, import_react38.useState)([]);
|
|
7921
|
+
const [newFolderOpen, setNewFolderOpen] = (0, import_react38.useState)(false);
|
|
7922
|
+
const [newFolderName, setNewFolderName] = (0, import_react38.useState)("");
|
|
7923
|
+
const [editModal, setEditModal] = (0, import_react38.useState)(null);
|
|
7924
|
+
const [deleteTarget, setDeleteTarget] = (0, import_react38.useState)(null);
|
|
7925
|
+
const [editAlt, setEditAlt] = (0, import_react38.useState)("");
|
|
7926
|
+
const [editPublic, setEditPublic] = (0, import_react38.useState)(false);
|
|
7927
|
+
const [editFilename, setEditFilename] = (0, import_react38.useState)("");
|
|
7928
|
+
const [extractingId, setExtractingId] = (0, import_react38.useState)(null);
|
|
7929
|
+
const fileInputRef = (0, import_react38.useRef)(null);
|
|
7930
|
+
const load = (0, import_react38.useCallback)(async () => {
|
|
7192
7931
|
setLoading(true);
|
|
7193
7932
|
const params = new URLSearchParams({
|
|
7194
7933
|
page: String(page),
|
|
7195
7934
|
limit: "24",
|
|
7196
|
-
sortField
|
|
7197
|
-
sortOrder
|
|
7935
|
+
sortField,
|
|
7936
|
+
sortOrder
|
|
7198
7937
|
});
|
|
7938
|
+
params.set("parentId", currentParentId === null ? "" : String(currentParentId));
|
|
7199
7939
|
if (search) params.set("search", search);
|
|
7200
7940
|
if (typeFilter) params.set("type", typeFilter);
|
|
7201
7941
|
try {
|
|
@@ -7210,11 +7950,33 @@ function MediaLibraryPage() {
|
|
|
7210
7950
|
} finally {
|
|
7211
7951
|
setLoading(false);
|
|
7212
7952
|
}
|
|
7213
|
-
}, [page, search, typeFilter]);
|
|
7214
|
-
(0,
|
|
7953
|
+
}, [page, search, typeFilter, currentParentId, sortField, sortOrder]);
|
|
7954
|
+
(0, import_react38.useEffect)(() => {
|
|
7215
7955
|
load();
|
|
7216
7956
|
}, [load]);
|
|
7217
7957
|
const handleSearch = () => setSearch(searchInput.trim());
|
|
7958
|
+
const goRoot = (0, import_react38.useCallback)(() => {
|
|
7959
|
+
setPage(1);
|
|
7960
|
+
setCurrentParentId(null);
|
|
7961
|
+
setCrumb([]);
|
|
7962
|
+
}, []);
|
|
7963
|
+
const goCrumb = (0, import_react38.useCallback)((index) => {
|
|
7964
|
+
setPage(1);
|
|
7965
|
+
if (index < 0) {
|
|
7966
|
+
goRoot();
|
|
7967
|
+
return;
|
|
7968
|
+
}
|
|
7969
|
+
const slice = crumb.slice(0, index + 1);
|
|
7970
|
+
setCrumb(slice);
|
|
7971
|
+
const last = slice[slice.length - 1];
|
|
7972
|
+
setCurrentParentId(last.id);
|
|
7973
|
+
}, [crumb, goRoot]);
|
|
7974
|
+
const enterFolder = (item) => {
|
|
7975
|
+
if (item.kind !== "folder") return;
|
|
7976
|
+
setPage(1);
|
|
7977
|
+
setCurrentParentId(item.id);
|
|
7978
|
+
setCrumb((c) => [...c, { id: item.id, name: item.filename }]);
|
|
7979
|
+
};
|
|
7218
7980
|
const handleUpload = async (e) => {
|
|
7219
7981
|
const file = e.target.files?.[0];
|
|
7220
7982
|
if (!file) return;
|
|
@@ -7222,6 +7984,7 @@ function MediaLibraryPage() {
|
|
|
7222
7984
|
try {
|
|
7223
7985
|
const formData = new FormData();
|
|
7224
7986
|
formData.append("file", file);
|
|
7987
|
+
if (currentParentId != null) formData.append("parentId", String(currentParentId));
|
|
7225
7988
|
const uploadRes = await fetch("/api/upload", { method: "POST", body: formData });
|
|
7226
7989
|
const uploadJson = await uploadRes.json();
|
|
7227
7990
|
if (!uploadRes.ok) throw new Error(uploadJson.error || "Upload failed");
|
|
@@ -7231,69 +7994,134 @@ function MediaLibraryPage() {
|
|
|
7231
7994
|
method: "POST",
|
|
7232
7995
|
headers: { "Content-Type": "application/json" },
|
|
7233
7996
|
body: JSON.stringify({
|
|
7997
|
+
kind: "file",
|
|
7234
7998
|
filename: file.name,
|
|
7235
7999
|
url: filePath.startsWith("http") ? filePath : filePath,
|
|
7236
8000
|
mimeType: file.type || "application/octet-stream",
|
|
7237
8001
|
size: file.size,
|
|
7238
8002
|
alt: null,
|
|
7239
|
-
isPublic: false
|
|
8003
|
+
isPublic: false,
|
|
8004
|
+
parentId: currentParentId
|
|
7240
8005
|
})
|
|
7241
8006
|
});
|
|
7242
8007
|
if (!createRes.ok) throw new Error("Failed to create media record");
|
|
7243
|
-
|
|
8008
|
+
import_sonner6.toast.success("File uploaded");
|
|
7244
8009
|
load();
|
|
7245
8010
|
} catch (err) {
|
|
7246
|
-
|
|
8011
|
+
import_sonner6.toast.error(err instanceof Error ? err.message : "Upload failed");
|
|
7247
8012
|
} finally {
|
|
7248
8013
|
setUploading(false);
|
|
7249
8014
|
e.target.value = "";
|
|
7250
8015
|
}
|
|
7251
8016
|
};
|
|
7252
|
-
const
|
|
7253
|
-
|
|
8017
|
+
const createFolder = async () => {
|
|
8018
|
+
const name = newFolderName.trim();
|
|
8019
|
+
if (!name) {
|
|
8020
|
+
import_sonner6.toast.error("Enter a folder name");
|
|
8021
|
+
return;
|
|
8022
|
+
}
|
|
8023
|
+
try {
|
|
8024
|
+
const res = await fetch("/api/media", {
|
|
8025
|
+
method: "POST",
|
|
8026
|
+
headers: { "Content-Type": "application/json" },
|
|
8027
|
+
body: JSON.stringify({
|
|
8028
|
+
kind: "folder",
|
|
8029
|
+
filename: name,
|
|
8030
|
+
parentId: currentParentId
|
|
8031
|
+
})
|
|
8032
|
+
});
|
|
8033
|
+
const j = await res.json().catch(() => ({}));
|
|
8034
|
+
if (!res.ok) throw new Error(j.error || "Failed to create folder");
|
|
8035
|
+
import_sonner6.toast.success("Folder created");
|
|
8036
|
+
setNewFolderOpen(false);
|
|
8037
|
+
setNewFolderName("");
|
|
8038
|
+
load();
|
|
8039
|
+
} catch (err) {
|
|
8040
|
+
import_sonner6.toast.error(err instanceof Error ? err.message : "Failed");
|
|
8041
|
+
}
|
|
8042
|
+
};
|
|
8043
|
+
const handleExtractZip = async (id) => {
|
|
8044
|
+
setExtractingId(id);
|
|
8045
|
+
try {
|
|
8046
|
+
const res = await fetch(`/api/media/extract/${id}`, { method: "POST" });
|
|
8047
|
+
const j = await res.json().catch(() => ({}));
|
|
8048
|
+
if (!res.ok) throw new Error(j.error || "Extract failed");
|
|
8049
|
+
import_sonner6.toast.success(
|
|
8050
|
+
`Extracted ${j.files ?? 0} file(s)` + (j.folderEntries ? `, ${j.folderEntries} folder path(s)` : "")
|
|
8051
|
+
);
|
|
8052
|
+
load();
|
|
8053
|
+
} catch (e) {
|
|
8054
|
+
import_sonner6.toast.error(e instanceof Error ? e.message : "Extract failed");
|
|
8055
|
+
} finally {
|
|
8056
|
+
setExtractingId(null);
|
|
8057
|
+
}
|
|
8058
|
+
};
|
|
8059
|
+
const handleDelete = async (item) => {
|
|
7254
8060
|
try {
|
|
7255
|
-
const res = await fetch(`/api/media/${id}`, { method: "DELETE" });
|
|
8061
|
+
const res = await fetch(`/api/media/${item.id}`, { method: "DELETE" });
|
|
7256
8062
|
if (!res.ok) throw new Error("Delete failed");
|
|
7257
|
-
|
|
8063
|
+
import_sonner6.toast.success("Deleted");
|
|
8064
|
+
setDeleteTarget(null);
|
|
7258
8065
|
load();
|
|
7259
8066
|
} catch {
|
|
7260
|
-
|
|
8067
|
+
import_sonner6.toast.error("Delete failed");
|
|
7261
8068
|
}
|
|
7262
8069
|
};
|
|
7263
8070
|
const handleSaveEdit = async () => {
|
|
7264
8071
|
if (!editModal) return;
|
|
7265
8072
|
try {
|
|
8073
|
+
const isFolder = editModal.kind === "folder";
|
|
8074
|
+
const body = isFolder ? { filename: editFilename.trim() || editModal.filename } : { alt: editAlt || null, isPublic: editPublic };
|
|
8075
|
+
if (isFolder && !body.filename) {
|
|
8076
|
+
import_sonner6.toast.error("Name required");
|
|
8077
|
+
return;
|
|
8078
|
+
}
|
|
7266
8079
|
const res = await fetch(`/api/media/${editModal.id}`, {
|
|
7267
8080
|
method: "PUT",
|
|
7268
8081
|
headers: { "Content-Type": "application/json" },
|
|
7269
|
-
body: JSON.stringify(
|
|
8082
|
+
body: JSON.stringify(body)
|
|
7270
8083
|
});
|
|
7271
8084
|
if (!res.ok) throw new Error("Update failed");
|
|
7272
|
-
|
|
8085
|
+
import_sonner6.toast.success("Updated");
|
|
7273
8086
|
setEditModal(null);
|
|
7274
8087
|
load();
|
|
7275
8088
|
} catch {
|
|
7276
|
-
|
|
8089
|
+
import_sonner6.toast.error("Update failed");
|
|
7277
8090
|
}
|
|
7278
8091
|
};
|
|
7279
8092
|
const copyUrl = (url) => {
|
|
7280
8093
|
const full = url.startsWith("http") ? url : `${typeof window !== "undefined" ? window.location.origin : ""}${url}`;
|
|
7281
8094
|
navigator.clipboard.writeText(full);
|
|
7282
|
-
|
|
8095
|
+
import_sonner6.toast.success("URL copied");
|
|
7283
8096
|
};
|
|
7284
8097
|
const openEdit = (item) => {
|
|
7285
8098
|
setEditModal(item);
|
|
7286
8099
|
setEditAlt(item.alt || "");
|
|
7287
8100
|
setEditPublic(item.isPublic);
|
|
8101
|
+
setEditFilename(item.filename);
|
|
7288
8102
|
};
|
|
7289
|
-
const
|
|
7290
|
-
const
|
|
8103
|
+
const isImage = (mime, kind, filename) => kind !== "folder" && getTypeCategory(mime, kind, filename) === "image";
|
|
8104
|
+
const listViewData = import_react38.default.useMemo(() => {
|
|
8105
|
+
const sorted = [...data];
|
|
8106
|
+
const byDateDesc = (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
|
|
8107
|
+
const folders = sorted.filter((x) => x.kind === "folder").sort(byDateDesc);
|
|
8108
|
+
const files = sorted.filter((x) => x.kind !== "folder").sort(byDateDesc);
|
|
8109
|
+
return [...folders, ...files];
|
|
8110
|
+
}, [data]);
|
|
7291
8111
|
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "min-w-0 rounded-lg bg-white shadow-md", children: [
|
|
7292
8112
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "bg-gray-800 border-b border-gray-700 px-4 py-2.5 rounded-t-lg", children: [
|
|
7293
8113
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("h1", { className: "text-base font-semibold text-white", children: "Media Library" }),
|
|
7294
|
-
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "text-xs text-gray-300 mt-0.5", children: "
|
|
8114
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "text-xs text-gray-300 mt-0.5", children: "Folders and files (Google Drive\u2013style). Storage mirrors the folder tree under uploads/." })
|
|
7295
8115
|
] }),
|
|
7296
8116
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "min-w-0 p-4 space-y-3", children: [
|
|
8117
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex flex-wrap items-center gap-2 text-sm text-gray-700", children: [
|
|
8118
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "font-medium text-gray-600", children: "Location:" }),
|
|
8119
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("button", { type: "button", className: "text-blue-600 hover:underline", onClick: () => goCrumb(-1), children: "Media" }),
|
|
8120
|
+
crumb.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { className: "flex items-center gap-1", children: [
|
|
8121
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "text-gray-400", children: "/" }),
|
|
8122
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("button", { type: "button", className: "text-blue-600 hover:underline", onClick: () => goCrumb(i), children: c.name })
|
|
8123
|
+
] }, `${c.id}-${i}`))
|
|
8124
|
+
] }),
|
|
7297
8125
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
7298
8126
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
7299
8127
|
"input",
|
|
@@ -7303,7 +8131,7 @@ function MediaLibraryPage() {
|
|
|
7303
8131
|
className: "hidden",
|
|
7304
8132
|
onChange: handleUpload,
|
|
7305
8133
|
disabled: uploading,
|
|
7306
|
-
accept: "image/*,video/*,audio/*,.pdf,.doc,.docx"
|
|
8134
|
+
accept: "image/*,video/*,audio/*,.pdf,.doc,.docx,.zip"
|
|
7307
8135
|
}
|
|
7308
8136
|
),
|
|
7309
8137
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
@@ -7319,11 +8147,15 @@ function MediaLibraryPage() {
|
|
|
7319
8147
|
]
|
|
7320
8148
|
}
|
|
7321
8149
|
),
|
|
8150
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(Button, { type: "button", variant: "secondary", className: "flex items-center gap-2", onClick: () => setNewFolderOpen(true), children: [
|
|
8151
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.FolderPlus, { className: "h-4 w-4" }),
|
|
8152
|
+
"New folder"
|
|
8153
|
+
] }),
|
|
7322
8154
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex items-center gap-2 flex-1 min-w-[200px]", children: [
|
|
7323
8155
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
7324
8156
|
Input,
|
|
7325
8157
|
{
|
|
7326
|
-
placeholder: "Search by
|
|
8158
|
+
placeholder: "Search by name...",
|
|
7327
8159
|
value: searchInput,
|
|
7328
8160
|
onChange: (e) => setSearchInput(e.target.value),
|
|
7329
8161
|
onKeyDown: (e) => e.key === "Enter" && handleSearch()
|
|
@@ -7345,61 +8177,192 @@ function MediaLibraryPage() {
|
|
|
7345
8177
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("option", { value: "application", children: "Documents" })
|
|
7346
8178
|
]
|
|
7347
8179
|
}
|
|
7348
|
-
)
|
|
8180
|
+
),
|
|
8181
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
8182
|
+
"select",
|
|
8183
|
+
{
|
|
8184
|
+
className: "border rounded-md px-3 py-2 text-sm bg-white max-w-[200px]",
|
|
8185
|
+
value: `${sortField}:${sortOrder}`,
|
|
8186
|
+
onChange: (e) => {
|
|
8187
|
+
const [f, o] = e.target.value.split(":");
|
|
8188
|
+
setSortField(f);
|
|
8189
|
+
setSortOrder(o);
|
|
8190
|
+
setPage(1);
|
|
8191
|
+
},
|
|
8192
|
+
children: [
|
|
8193
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("option", { value: "filename:asc", children: "Name A\u2013Z" }),
|
|
8194
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("option", { value: "filename:desc", children: "Name Z\u2013A" }),
|
|
8195
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("option", { value: "createdAt:desc", children: "Newest first" }),
|
|
8196
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("option", { value: "createdAt:asc", children: "Oldest first" })
|
|
8197
|
+
]
|
|
8198
|
+
}
|
|
8199
|
+
),
|
|
8200
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "inline-flex rounded-md border border-gray-300 overflow-hidden bg-white", children: [
|
|
8201
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
8202
|
+
"button",
|
|
8203
|
+
{
|
|
8204
|
+
type: "button",
|
|
8205
|
+
className: `px-2.5 py-2 text-xs inline-flex items-center gap-1 ${viewMode === "grid" ? "bg-gray-100 text-gray-900" : "text-gray-600"}`,
|
|
8206
|
+
onClick: () => setViewMode("grid"),
|
|
8207
|
+
title: "Grid view",
|
|
8208
|
+
children: [
|
|
8209
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.LayoutGrid, { className: "h-4 w-4" }),
|
|
8210
|
+
"Grid"
|
|
8211
|
+
]
|
|
8212
|
+
}
|
|
8213
|
+
),
|
|
8214
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
8215
|
+
"button",
|
|
8216
|
+
{
|
|
8217
|
+
type: "button",
|
|
8218
|
+
className: `px-2.5 py-2 text-xs inline-flex items-center gap-1 border-l border-gray-300 ${viewMode === "list" ? "bg-gray-100 text-gray-900" : "text-gray-600"}`,
|
|
8219
|
+
onClick: () => setViewMode("list"),
|
|
8220
|
+
title: "List view",
|
|
8221
|
+
children: [
|
|
8222
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.List, { className: "h-4 w-4" }),
|
|
8223
|
+
"List"
|
|
8224
|
+
]
|
|
8225
|
+
}
|
|
8226
|
+
)
|
|
8227
|
+
] })
|
|
7349
8228
|
] }),
|
|
7350
|
-
loading ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "flex justify-center py-12", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "animate-spin rounded-full h-8 w-8 border-2 border-gray-300 border-t-gray-600" }) }) : data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "text-center py-12 text-gray-500", children: "
|
|
7351
|
-
|
|
7352
|
-
|
|
8229
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "flex justify-center py-12", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "animate-spin rounded-full h-8 w-8 border-2 border-gray-300 border-t-gray-600" }) }) : data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "text-center py-12 text-gray-500", children: "This folder is empty. Create a folder or upload a file." }) : viewMode === "grid" ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4", children: data.map((item) => {
|
|
8230
|
+
const isF = item.kind === "folder";
|
|
8231
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
7353
8232
|
"div",
|
|
7354
8233
|
{
|
|
7355
8234
|
className: "border rounded-lg overflow-hidden bg-gray-50 hover:bg-gray-100 transition-colors group",
|
|
7356
8235
|
children: [
|
|
7357
|
-
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
8236
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
8237
|
+
"button",
|
|
8238
|
+
{
|
|
8239
|
+
type: "button",
|
|
8240
|
+
className: "w-full aspect-square flex items-center justify-center bg-gray-200 relative cursor-pointer",
|
|
8241
|
+
onClick: () => isF && enterFolder(item),
|
|
8242
|
+
children: [
|
|
8243
|
+
isImage(item.mimeType, item.kind, item.filename) ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8244
|
+
"img",
|
|
8245
|
+
{
|
|
8246
|
+
src: item.url,
|
|
8247
|
+
alt: item.alt || item.filename,
|
|
8248
|
+
className: "w-full h-full object-cover"
|
|
8249
|
+
}
|
|
8250
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TypeIcon, { mimeType: item.mimeType, kind: item.kind, filename: item.filename }),
|
|
8251
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "absolute inset-0 bg-black/0 group-hover:bg-black/40 transition-colors flex items-center justify-center gap-1 opacity-0 group-hover:opacity-100 flex-wrap", children: [
|
|
8252
|
+
!isF && isZipMedia(item.mimeType, item.filename) ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8253
|
+
Button,
|
|
8254
|
+
{
|
|
8255
|
+
size: "icon",
|
|
8256
|
+
variant: "outline",
|
|
8257
|
+
className: "h-8 w-8",
|
|
8258
|
+
title: "Extract zip into this folder",
|
|
8259
|
+
disabled: extractingId === item.id,
|
|
8260
|
+
onClick: (e) => {
|
|
8261
|
+
e.stopPropagation();
|
|
8262
|
+
handleExtractZip(item.id);
|
|
8263
|
+
},
|
|
8264
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Archive, { className: "h-3 w-3" })
|
|
8265
|
+
}
|
|
8266
|
+
) : null,
|
|
8267
|
+
!isF && item.url ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8268
|
+
Button,
|
|
8269
|
+
{
|
|
8270
|
+
size: "icon",
|
|
8271
|
+
variant: "outline",
|
|
8272
|
+
className: "h-8 w-8",
|
|
8273
|
+
onClick: (e) => {
|
|
8274
|
+
e.stopPropagation();
|
|
8275
|
+
copyUrl(item.url);
|
|
8276
|
+
},
|
|
8277
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Copy, { className: "h-3 w-3" })
|
|
8278
|
+
}
|
|
8279
|
+
) : null,
|
|
8280
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8281
|
+
Button,
|
|
8282
|
+
{
|
|
8283
|
+
size: "icon",
|
|
8284
|
+
variant: "outline",
|
|
8285
|
+
className: "h-8 w-8",
|
|
8286
|
+
onClick: (e) => {
|
|
8287
|
+
e.stopPropagation();
|
|
8288
|
+
openEdit(item);
|
|
8289
|
+
},
|
|
8290
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Edit2, { className: "h-3 w-3" })
|
|
8291
|
+
}
|
|
8292
|
+
),
|
|
8293
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8294
|
+
Button,
|
|
8295
|
+
{
|
|
8296
|
+
size: "icon",
|
|
8297
|
+
variant: "outline",
|
|
8298
|
+
className: "h-8 w-8 border-red-300 text-red-600 hover:text-red-700",
|
|
8299
|
+
onClick: (e) => {
|
|
8300
|
+
e.stopPropagation();
|
|
8301
|
+
setDeleteTarget(item);
|
|
8302
|
+
},
|
|
8303
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Trash2, { className: "h-3 w-3" })
|
|
8304
|
+
}
|
|
8305
|
+
)
|
|
8306
|
+
] })
|
|
8307
|
+
]
|
|
8308
|
+
}
|
|
8309
|
+
),
|
|
7390
8310
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "p-2", children: [
|
|
7391
|
-
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "text-xs font-medium text-gray-900 truncate", title: item.filename, children: item.filename }),
|
|
8311
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "text-xs font-medium text-gray-900 truncate text-left", title: item.filename, children: item.filename }),
|
|
7392
8312
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex items-center justify-between mt-1", children: [
|
|
7393
8313
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "text-xs text-gray-500", children: formatDate(item.createdAt) }),
|
|
7394
|
-
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "text-xs px-1.5 py-0.5 rounded bg-gray-200 text-gray-600", children: getTypeLabel(item.mimeType) })
|
|
8314
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "text-xs px-1.5 py-0.5 rounded bg-gray-200 text-gray-600", children: getTypeLabel(item.mimeType, item.kind, item.filename) })
|
|
7395
8315
|
] }),
|
|
7396
|
-
item.isPublic && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "text-xs text-green-600 mt-0.5 block", children: "Public" })
|
|
8316
|
+
item.isPublic && !isF && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "text-xs text-green-600 mt-0.5 block", children: "Public" }),
|
|
8317
|
+
isF && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8318
|
+
"button",
|
|
8319
|
+
{
|
|
8320
|
+
type: "button",
|
|
8321
|
+
className: "text-xs text-blue-600 mt-1 hover:underline",
|
|
8322
|
+
onClick: () => enterFolder(item),
|
|
8323
|
+
children: "Open"
|
|
8324
|
+
}
|
|
8325
|
+
)
|
|
7397
8326
|
] })
|
|
7398
8327
|
]
|
|
7399
8328
|
},
|
|
7400
8329
|
item.id
|
|
7401
|
-
)
|
|
7402
|
-
|
|
8330
|
+
);
|
|
8331
|
+
}) }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "overflow-x-auto rounded-md border border-gray-200 bg-white", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("table", { className: "w-full text-sm", children: [
|
|
8332
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("tr", { className: "border-b bg-gray-50", children: [
|
|
8333
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("th", { className: "p-3 text-left font-medium", children: "Name" }),
|
|
8334
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("th", { className: "p-3 text-left font-medium", children: "Type" }),
|
|
8335
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("th", { className: "p-3 text-left font-medium", children: "Created" }),
|
|
8336
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("th", { className: "p-3 text-left font-medium", children: "Size" }),
|
|
8337
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("th", { className: "p-3 text-right font-medium", children: "Actions" })
|
|
8338
|
+
] }) }),
|
|
8339
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("tbody", { children: listViewData.map((item) => {
|
|
8340
|
+
const isF = item.kind === "folder";
|
|
8341
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("tr", { className: "border-b border-gray-100 hover:bg-gray-50", children: [
|
|
8342
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("td", { className: "p-3", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
8343
|
+
"button",
|
|
8344
|
+
{
|
|
8345
|
+
type: "button",
|
|
8346
|
+
className: `inline-flex items-center gap-2 ${isF ? "text-blue-600 hover:underline" : "text-gray-900"}`,
|
|
8347
|
+
onClick: () => isF && enterFolder(item),
|
|
8348
|
+
children: [
|
|
8349
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TypeIcon, { mimeType: item.mimeType, kind: item.kind, filename: item.filename }),
|
|
8350
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "truncate max-w-[260px]", title: item.filename, children: item.filename })
|
|
8351
|
+
]
|
|
8352
|
+
}
|
|
8353
|
+
) }),
|
|
8354
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("td", { className: "p-3 text-gray-600", children: getTypeLabel(item.mimeType, item.kind, item.filename) }),
|
|
8355
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("td", { className: "p-3 text-gray-600", children: formatDate(item.createdAt) }),
|
|
8356
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("td", { className: "p-3 text-gray-600", children: isF ? "\u2014" : `${Math.round((item.size || 0) / 1024)} KB` }),
|
|
8357
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("td", { className: "p-3", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex items-center justify-end gap-1", children: [
|
|
8358
|
+
!isF && isZipMedia(item.mimeType, item.filename) && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { size: "icon", variant: "outline", className: "h-8 w-8", onClick: () => handleExtractZip(item.id), disabled: extractingId === item.id, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Archive, { className: "h-3 w-3" }) }),
|
|
8359
|
+
!isF && item.url && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { size: "icon", variant: "outline", className: "h-8 w-8", onClick: () => copyUrl(item.url), children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Copy, { className: "h-3 w-3" }) }),
|
|
8360
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { size: "icon", variant: "outline", className: "h-8 w-8", onClick: () => openEdit(item), children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Edit2, { className: "h-3 w-3" }) }),
|
|
8361
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { size: "icon", variant: "outline", className: "h-8 w-8 border-red-300 text-red-600 hover:text-red-700", onClick: () => setDeleteTarget(item), children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react29.Trash2, { className: "h-3 w-3" }) })
|
|
8362
|
+
] }) })
|
|
8363
|
+
] }, item.id);
|
|
8364
|
+
}) })
|
|
8365
|
+
] }) }),
|
|
7403
8366
|
totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Pagination, { className: "mt-6", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(PaginationContent, { children: [
|
|
7404
8367
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(PaginationItem, { children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
7405
8368
|
PaginationPrevious,
|
|
@@ -7421,9 +8384,28 @@ function MediaLibraryPage() {
|
|
|
7421
8384
|
) })
|
|
7422
8385
|
] }) })
|
|
7423
8386
|
] }),
|
|
8387
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Dialog, { open: newFolderOpen, onOpenChange: setNewFolderOpen, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(DialogContent, { children: [
|
|
8388
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(DialogTitle, { children: "New folder" }) }),
|
|
8389
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8390
|
+
Input,
|
|
8391
|
+
{
|
|
8392
|
+
placeholder: "Folder name",
|
|
8393
|
+
value: newFolderName,
|
|
8394
|
+
onChange: (e) => setNewFolderName(e.target.value),
|
|
8395
|
+
onKeyDown: (e) => e.key === "Enter" && createFolder()
|
|
8396
|
+
}
|
|
8397
|
+
),
|
|
8398
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(DialogFooter, { children: [
|
|
8399
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { variant: "outline", onClick: () => setNewFolderOpen(false), children: "Cancel" }),
|
|
8400
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { onClick: createFolder, children: "Create" })
|
|
8401
|
+
] })
|
|
8402
|
+
] }) }),
|
|
7424
8403
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Dialog, { open: !!editModal, onOpenChange: (open) => !open && setEditModal(null), children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(DialogContent, { children: [
|
|
7425
|
-
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(DialogTitle, { children: "Edit media" }) }),
|
|
7426
|
-
editModal && /* @__PURE__ */ (0, import_jsx_runtime53.
|
|
8404
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(DialogTitle, { children: editModal?.kind === "folder" ? "Rename folder" : "Edit media" }) }),
|
|
8405
|
+
editModal && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "space-y-4 py-2", children: editModal.kind === "folder" ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
|
|
8406
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("label", { className: "text-sm font-medium", children: "Name" }),
|
|
8407
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Input, { value: editFilename, onChange: (e) => setEditFilename(e.target.value), className: "mt-1" })
|
|
8408
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
|
|
7427
8409
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
|
|
7428
8410
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("label", { className: "text-sm font-medium", children: "Alt text" }),
|
|
7429
8411
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
@@ -7448,20 +8430,37 @@ function MediaLibraryPage() {
|
|
|
7448
8430
|
),
|
|
7449
8431
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("label", { htmlFor: "edit-public", className: "text-sm", children: "Public (visible on site)" })
|
|
7450
8432
|
] })
|
|
7451
|
-
] }),
|
|
8433
|
+
] }) }),
|
|
7452
8434
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(DialogFooter, { children: [
|
|
7453
8435
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { variant: "outline", onClick: () => setEditModal(null), children: "Cancel" }),
|
|
7454
8436
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { onClick: handleSaveEdit, children: "Save" })
|
|
7455
8437
|
] })
|
|
8438
|
+
] }) }),
|
|
8439
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Dialog, { open: !!deleteTarget, onOpenChange: (open) => !open && setDeleteTarget(null), children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(DialogContent, { children: [
|
|
8440
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(DialogTitle, { children: "Confirm Delete" }) }),
|
|
8441
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "text-sm text-gray-600", children: deleteTarget?.kind === "folder" ? "Delete this folder and everything inside it?" : "Delete this file?" }),
|
|
8442
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(DialogFooter, { children: [
|
|
8443
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { variant: "outline", onClick: () => setDeleteTarget(null), children: "Cancel" }),
|
|
8444
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8445
|
+
Button,
|
|
8446
|
+
{
|
|
8447
|
+
variant: "destructive",
|
|
8448
|
+
onClick: () => {
|
|
8449
|
+
if (deleteTarget) handleDelete(deleteTarget);
|
|
8450
|
+
},
|
|
8451
|
+
children: "Delete"
|
|
8452
|
+
}
|
|
8453
|
+
)
|
|
8454
|
+
] })
|
|
7456
8455
|
] }) })
|
|
7457
8456
|
] });
|
|
7458
8457
|
}
|
|
7459
8458
|
|
|
7460
8459
|
// src/admin/pages/PageBuilderPage.tsx
|
|
7461
|
-
var
|
|
8460
|
+
var import_react39 = require("react");
|
|
7462
8461
|
var import_core = require("@craftjs/core");
|
|
7463
8462
|
var import_lucide_react30 = require("lucide-react");
|
|
7464
|
-
var
|
|
8463
|
+
var import_navigation17 = require("next/navigation");
|
|
7465
8464
|
|
|
7466
8465
|
// src/theme/registry.ts
|
|
7467
8466
|
function buildResolver(theme) {
|
|
@@ -7486,7 +8485,7 @@ function getCatalog(theme) {
|
|
|
7486
8485
|
|
|
7487
8486
|
// src/admin/pages/PageBuilderPage.tsx
|
|
7488
8487
|
var LucideIcons = __toESM(require("lucide-react"), 1);
|
|
7489
|
-
var
|
|
8488
|
+
var import_react40 = __toESM(require("react"), 1);
|
|
7490
8489
|
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
7491
8490
|
function createSelectable(Comp) {
|
|
7492
8491
|
function SelectableWrapper(props) {
|
|
@@ -7531,16 +8530,16 @@ function DraggableCatalogItem({
|
|
|
7531
8530
|
Icon: Icon2,
|
|
7532
8531
|
description
|
|
7533
8532
|
}) {
|
|
7534
|
-
const elRef = (0,
|
|
7535
|
-
(0,
|
|
8533
|
+
const elRef = (0, import_react39.useRef)(null);
|
|
8534
|
+
(0, import_react39.useEffect)(() => {
|
|
7536
8535
|
if (!elRef.current) return;
|
|
7537
8536
|
if (meta.canContainChildren) {
|
|
7538
8537
|
connectors.create(
|
|
7539
8538
|
elRef.current,
|
|
7540
|
-
|
|
8539
|
+
import_react40.default.createElement(import_core.Element, { is: Comp, canvas: true, ...meta.defaultProps })
|
|
7541
8540
|
);
|
|
7542
8541
|
} else {
|
|
7543
|
-
connectors.create(elRef.current,
|
|
8542
|
+
connectors.create(elRef.current, import_react40.default.createElement(Comp, meta.defaultProps));
|
|
7544
8543
|
}
|
|
7545
8544
|
}, [connectors, Comp, meta.defaultProps, meta.name, meta.canContainChildren]);
|
|
7546
8545
|
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
@@ -7559,7 +8558,7 @@ function DraggableCatalogItem({
|
|
|
7559
8558
|
function ComponentPickerContent({ theme, resolver }) {
|
|
7560
8559
|
const { connectors } = (0, import_core.useEditor)();
|
|
7561
8560
|
const catalog = getCatalog(theme);
|
|
7562
|
-
const [collapsed, setCollapsed] = (0,
|
|
8561
|
+
const [collapsed, setCollapsed] = (0, import_react39.useState)({});
|
|
7563
8562
|
const toggleCategory = (cat) => {
|
|
7564
8563
|
setCollapsed((prev) => ({ ...prev, [cat]: !prev[cat] }));
|
|
7565
8564
|
};
|
|
@@ -7764,7 +8763,7 @@ function LayersPanelContent() {
|
|
|
7764
8763
|
nodes: state.nodes,
|
|
7765
8764
|
selectedSet: state.events.selected
|
|
7766
8765
|
}));
|
|
7767
|
-
const [expanded, setExpanded] = (0,
|
|
8766
|
+
const [expanded, setExpanded] = (0, import_react39.useState)({});
|
|
7768
8767
|
const nodeMap = nodes || {};
|
|
7769
8768
|
const rootId = (() => {
|
|
7770
8769
|
const ids = Object.keys(nodeMap);
|
|
@@ -7886,10 +8885,10 @@ function CollapsibleSection({
|
|
|
7886
8885
|
] });
|
|
7887
8886
|
}
|
|
7888
8887
|
function RightSidebar({ theme, resolver, activeTab, setActiveTab, seoProps }) {
|
|
7889
|
-
const [componentsOpen, setComponentsOpen] = (0,
|
|
7890
|
-
const [propertiesOpen, setPropertiesOpen] = (0,
|
|
7891
|
-
const [layoutOpen, setLayoutOpen] = (0,
|
|
7892
|
-
const [layersOpen, setLayersOpen] = (0,
|
|
8888
|
+
const [componentsOpen, setComponentsOpen] = (0, import_react39.useState)(true);
|
|
8889
|
+
const [propertiesOpen, setPropertiesOpen] = (0, import_react39.useState)(true);
|
|
8890
|
+
const [layoutOpen, setLayoutOpen] = (0, import_react39.useState)(true);
|
|
8891
|
+
const [layersOpen, setLayersOpen] = (0, import_react39.useState)(true);
|
|
7893
8892
|
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex flex-col flex-1 overflow-hidden", children: [
|
|
7894
8893
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "flex border-b flex-shrink-0", children: ["designer", "seo"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
7895
8894
|
"button",
|
|
@@ -7957,7 +8956,7 @@ function SaveButton({
|
|
|
7957
8956
|
className
|
|
7958
8957
|
}) {
|
|
7959
8958
|
const { query } = (0, import_core.useEditor)();
|
|
7960
|
-
const [saving, setSaving] = (0,
|
|
8959
|
+
const [saving, setSaving] = (0, import_react39.useState)(false);
|
|
7961
8960
|
const handleSave = async () => {
|
|
7962
8961
|
setSaving(true);
|
|
7963
8962
|
try {
|
|
@@ -8029,22 +9028,22 @@ function SaveButton({
|
|
|
8029
9028
|
);
|
|
8030
9029
|
}
|
|
8031
9030
|
function PageBuilderPage({ pageId }) {
|
|
8032
|
-
const { theme } = (0,
|
|
8033
|
-
const router = (0,
|
|
8034
|
-
const [title, setTitle] = (0,
|
|
8035
|
-
const [slug, setSlug] = (0,
|
|
8036
|
-
const [published, setPublished] = (0,
|
|
8037
|
-
const [initialContent, setInitialContent] = (0,
|
|
8038
|
-
const [loading, setLoading] = (0,
|
|
8039
|
-
const [rightTab, setRightTab] = (0,
|
|
8040
|
-
const [seoTitle, setSeoTitle] = (0,
|
|
8041
|
-
const [seoDescription, setSeoDescription] = (0,
|
|
8042
|
-
const [seoKeywords, setSeoKeywords] = (0,
|
|
8043
|
-
const [seoOgTitle, setSeoOgTitle] = (0,
|
|
8044
|
-
const [seoOgDescription, setSeoOgDescription] = (0,
|
|
8045
|
-
const [seoOgImage, setSeoOgImage] = (0,
|
|
8046
|
-
const [pageSeoId, setPageSeoId] = (0,
|
|
8047
|
-
(0,
|
|
9031
|
+
const { theme } = (0, import_react39.useContext)(AdminConfigContext);
|
|
9032
|
+
const router = (0, import_navigation17.useRouter)();
|
|
9033
|
+
const [title, setTitle] = (0, import_react39.useState)("");
|
|
9034
|
+
const [slug, setSlug] = (0, import_react39.useState)("");
|
|
9035
|
+
const [published, setPublished] = (0, import_react39.useState)(false);
|
|
9036
|
+
const [initialContent, setInitialContent] = (0, import_react39.useState)(null);
|
|
9037
|
+
const [loading, setLoading] = (0, import_react39.useState)(!!pageId);
|
|
9038
|
+
const [rightTab, setRightTab] = (0, import_react39.useState)("designer");
|
|
9039
|
+
const [seoTitle, setSeoTitle] = (0, import_react39.useState)("");
|
|
9040
|
+
const [seoDescription, setSeoDescription] = (0, import_react39.useState)("");
|
|
9041
|
+
const [seoKeywords, setSeoKeywords] = (0, import_react39.useState)("");
|
|
9042
|
+
const [seoOgTitle, setSeoOgTitle] = (0, import_react39.useState)("");
|
|
9043
|
+
const [seoOgDescription, setSeoOgDescription] = (0, import_react39.useState)("");
|
|
9044
|
+
const [seoOgImage, setSeoOgImage] = (0, import_react39.useState)("");
|
|
9045
|
+
const [pageSeoId, setPageSeoId] = (0, import_react39.useState)(null);
|
|
9046
|
+
(0, import_react39.useEffect)(() => {
|
|
8048
9047
|
if (!pageId) {
|
|
8049
9048
|
setInitialContent(null);
|
|
8050
9049
|
setPageSeoId(null);
|
|
@@ -8073,7 +9072,7 @@ function PageBuilderPage({ pageId }) {
|
|
|
8073
9072
|
}
|
|
8074
9073
|
}).finally(() => setLoading(false));
|
|
8075
9074
|
}, [pageId]);
|
|
8076
|
-
(0,
|
|
9075
|
+
(0, import_react39.useEffect)(() => {
|
|
8077
9076
|
if (title && !slug) {
|
|
8078
9077
|
setSlug(
|
|
8079
9078
|
title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "")
|
|
@@ -8118,19 +9117,49 @@ function PageBuilderPage({ pageId }) {
|
|
|
8118
9117
|
onSaved: (id) => {
|
|
8119
9118
|
if (!pageId) router.replace(`/admin/pages/${id}`);
|
|
8120
9119
|
},
|
|
8121
|
-
className: "
|
|
9120
|
+
className: "md:hidden h-8 w-8 p-0 bg-white text-gray-800 hover:bg-gray-100 border-0",
|
|
9121
|
+
children: [
|
|
9122
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react30.Save, { className: "h-4 w-4" }),
|
|
9123
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "sr-only", children: "Save" })
|
|
9124
|
+
]
|
|
9125
|
+
}
|
|
9126
|
+
),
|
|
9127
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
9128
|
+
SaveButton,
|
|
9129
|
+
{
|
|
9130
|
+
pageId,
|
|
9131
|
+
existingSeoId: pageSeoId,
|
|
9132
|
+
onSeoIdChange: setPageSeoId,
|
|
9133
|
+
pageData: { title, slug, published, seoTitle, seoDescription, seoKeywords, seoOgTitle, seoOgDescription, seoOgImage },
|
|
9134
|
+
onSaved: (id) => {
|
|
9135
|
+
if (!pageId) router.replace(`/admin/pages/${id}`);
|
|
9136
|
+
},
|
|
9137
|
+
className: "hidden md:inline-flex items-center bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
8122
9138
|
children: [
|
|
8123
9139
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react30.Save, { className: "h-4 w-4 mr-1" }),
|
|
8124
9140
|
" Save"
|
|
8125
9141
|
]
|
|
8126
9142
|
}
|
|
8127
9143
|
),
|
|
9144
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
9145
|
+
Button,
|
|
9146
|
+
{
|
|
9147
|
+
variant: "outline",
|
|
9148
|
+
size: "icon",
|
|
9149
|
+
className: "md:hidden h-8 w-8 bg-white text-gray-800 hover:bg-gray-100 border-0",
|
|
9150
|
+
onClick: () => router.push("/admin/pages"),
|
|
9151
|
+
children: [
|
|
9152
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react30.X, { className: "h-4 w-4" }),
|
|
9153
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "sr-only", children: "Close" })
|
|
9154
|
+
]
|
|
9155
|
+
}
|
|
9156
|
+
),
|
|
8128
9157
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
8129
9158
|
Button,
|
|
8130
9159
|
{
|
|
8131
9160
|
variant: "outline",
|
|
8132
9161
|
size: "sm",
|
|
8133
|
-
className: "flex items-center bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
9162
|
+
className: "hidden md:inline-flex items-center bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
8134
9163
|
onClick: () => router.push("/admin/pages"),
|
|
8135
9164
|
children: [
|
|
8136
9165
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react30.X, { className: "h-4 w-4 mr-1" }),
|
|
@@ -8191,7 +9220,7 @@ function PageBuilderPage({ pageId }) {
|
|
|
8191
9220
|
}
|
|
8192
9221
|
|
|
8193
9222
|
// src/admin/pages/PluginsPage.tsx
|
|
8194
|
-
var
|
|
9223
|
+
var import_react41 = require("react");
|
|
8195
9224
|
var import_lucide_react32 = require("lucide-react");
|
|
8196
9225
|
|
|
8197
9226
|
// src/lib/email-recipients.ts
|
|
@@ -8239,7 +9268,7 @@ var Checkbox = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__
|
|
|
8239
9268
|
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
|
8240
9269
|
|
|
8241
9270
|
// src/admin/pages/PluginsPage.tsx
|
|
8242
|
-
var
|
|
9271
|
+
var import_sonner7 = require("sonner");
|
|
8243
9272
|
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
8244
9273
|
function normalizeChatMode(raw) {
|
|
8245
9274
|
if (raw === "external" || raw === "llm") return raw;
|
|
@@ -8305,7 +9334,7 @@ function EmailRecipientTags({
|
|
|
8305
9334
|
onChange,
|
|
8306
9335
|
placeholder
|
|
8307
9336
|
}) {
|
|
8308
|
-
const [draft, setDraft] = (0,
|
|
9337
|
+
const [draft, setDraft] = (0, import_react41.useState)("");
|
|
8309
9338
|
const commitDraft = () => {
|
|
8310
9339
|
const parts = splitInputToEmails(draft);
|
|
8311
9340
|
if (!parts.length) return;
|
|
@@ -8381,36 +9410,36 @@ function PluginSettingsPanel({
|
|
|
8381
9410
|
const isEmail = settingsGroup === "email";
|
|
8382
9411
|
const isErp = settingsGroup === "erp";
|
|
8383
9412
|
const isSms = settingsGroup === "sms";
|
|
8384
|
-
const [enabled, setEnabled] = (0,
|
|
8385
|
-
const [botName, setBotName] = (0,
|
|
8386
|
-
const [icon, setIcon] = (0,
|
|
8387
|
-
const [iconImageUrl, setIconImageUrl] = (0,
|
|
8388
|
-
const [iconBackgroundColor, setIconBackgroundColor] = (0,
|
|
8389
|
-
const [headerColor, setHeaderColor] = (0,
|
|
8390
|
-
const [salesTeamEmails, setSalesTeamEmails] = (0,
|
|
8391
|
-
const [fulfilmentTeamEmails, setFulfilmentTeamEmails] = (0,
|
|
8392
|
-
const [crmEmails, setCrmEmails] = (0,
|
|
8393
|
-
const [logoUrl, setLogoUrl] = (0,
|
|
8394
|
-
const [companyName, setCompanyName] = (0,
|
|
8395
|
-
const [supportEmail, setSupportEmail] = (0,
|
|
8396
|
-
const [supportPhone, setSupportPhone] = (0,
|
|
8397
|
-
const [followUsTitle, setFollowUsTitle] = (0,
|
|
8398
|
-
const [socialLinkRows, setSocialLinkRows] = (0,
|
|
8399
|
-
const [footerDisclaimer, setFooterDisclaimer] = (0,
|
|
8400
|
-
const [chatMode, setChatMode] = (0,
|
|
8401
|
-
const [whatsappPhone, setWhatsappPhone] = (0,
|
|
8402
|
-
const [externalChatSnippet, setExternalChatSnippet] = (0,
|
|
8403
|
-
const [erpPipelineName, setErpPipelineName] = (0,
|
|
8404
|
-
const [erpPipelineStageName, setErpPipelineStageName] = (0,
|
|
8405
|
-
const [erpFormsCatalog, setErpFormsCatalog] = (0,
|
|
8406
|
-
const [erpOpportunityFormIds, setErpOpportunityFormIds] = (0,
|
|
8407
|
-
const [erpOpportunityIdsKeyPresent, setErpOpportunityIdsKeyPresent] = (0,
|
|
8408
|
-
const [smsProviderChoice, setSmsProviderChoice] = (0,
|
|
8409
|
-
const [msg91ApiMode, setMsg91ApiMode] = (0,
|
|
8410
|
-
const [smsTplItems, setSmsTplItems] = (0,
|
|
8411
|
-
const [loading, setLoading] = (0,
|
|
8412
|
-
const [saving, setSaving] = (0,
|
|
8413
|
-
(0,
|
|
9413
|
+
const [enabled, setEnabled] = (0, import_react41.useState)(true);
|
|
9414
|
+
const [botName, setBotName] = (0, import_react41.useState)("");
|
|
9415
|
+
const [icon, setIcon] = (0, import_react41.useState)("");
|
|
9416
|
+
const [iconImageUrl, setIconImageUrl] = (0, import_react41.useState)("");
|
|
9417
|
+
const [iconBackgroundColor, setIconBackgroundColor] = (0, import_react41.useState)("#6366f1");
|
|
9418
|
+
const [headerColor, setHeaderColor] = (0, import_react41.useState)("#6366f1");
|
|
9419
|
+
const [salesTeamEmails, setSalesTeamEmails] = (0, import_react41.useState)([]);
|
|
9420
|
+
const [fulfilmentTeamEmails, setFulfilmentTeamEmails] = (0, import_react41.useState)([]);
|
|
9421
|
+
const [crmEmails, setCrmEmails] = (0, import_react41.useState)([]);
|
|
9422
|
+
const [logoUrl, setLogoUrl] = (0, import_react41.useState)("");
|
|
9423
|
+
const [companyName, setCompanyName] = (0, import_react41.useState)("");
|
|
9424
|
+
const [supportEmail, setSupportEmail] = (0, import_react41.useState)("");
|
|
9425
|
+
const [supportPhone, setSupportPhone] = (0, import_react41.useState)("");
|
|
9426
|
+
const [followUsTitle, setFollowUsTitle] = (0, import_react41.useState)("Follow Us");
|
|
9427
|
+
const [socialLinkRows, setSocialLinkRows] = (0, import_react41.useState)([{ ...EMPTY_SOCIAL_ROW }]);
|
|
9428
|
+
const [footerDisclaimer, setFooterDisclaimer] = (0, import_react41.useState)("");
|
|
9429
|
+
const [chatMode, setChatMode] = (0, import_react41.useState)("whatsapp");
|
|
9430
|
+
const [whatsappPhone, setWhatsappPhone] = (0, import_react41.useState)("");
|
|
9431
|
+
const [externalChatSnippet, setExternalChatSnippet] = (0, import_react41.useState)("");
|
|
9432
|
+
const [erpPipelineName, setErpPipelineName] = (0, import_react41.useState)("");
|
|
9433
|
+
const [erpPipelineStageName, setErpPipelineStageName] = (0, import_react41.useState)("");
|
|
9434
|
+
const [erpFormsCatalog, setErpFormsCatalog] = (0, import_react41.useState)([]);
|
|
9435
|
+
const [erpOpportunityFormIds, setErpOpportunityFormIds] = (0, import_react41.useState)([]);
|
|
9436
|
+
const [erpOpportunityIdsKeyPresent, setErpOpportunityIdsKeyPresent] = (0, import_react41.useState)(false);
|
|
9437
|
+
const [smsProviderChoice, setSmsProviderChoice] = (0, import_react41.useState)("auto");
|
|
9438
|
+
const [msg91ApiMode, setMsg91ApiMode] = (0, import_react41.useState)("auto");
|
|
9439
|
+
const [smsTplItems, setSmsTplItems] = (0, import_react41.useState)([]);
|
|
9440
|
+
const [loading, setLoading] = (0, import_react41.useState)(true);
|
|
9441
|
+
const [saving, setSaving] = (0, import_react41.useState)(false);
|
|
9442
|
+
(0, import_react41.useEffect)(() => {
|
|
8414
9443
|
setLoading(true);
|
|
8415
9444
|
fetch(`/api/settings/${settingsGroup}`).then((r) => r.ok ? r.json() : {}).then(async (data) => {
|
|
8416
9445
|
setEnabled(data.enabled !== "false");
|
|
@@ -8467,7 +9496,7 @@ function PluginSettingsPanel({
|
|
|
8467
9496
|
}
|
|
8468
9497
|
}).finally(() => setLoading(false));
|
|
8469
9498
|
}, [settingsGroup, isLlm, isEmail, isErp, isSms]);
|
|
8470
|
-
(0,
|
|
9499
|
+
(0, import_react41.useEffect)(() => {
|
|
8471
9500
|
if (!isErp || loading) return;
|
|
8472
9501
|
fetch("/api/forms?limit=500&sortField=name&sortOrder=asc").then((r) => r.ok ? r.json() : { data: [] }).then((res) => {
|
|
8473
9502
|
const rows = (res.data ?? []).map((f) => ({
|
|
@@ -8551,10 +9580,10 @@ function PluginSettingsPanel({
|
|
|
8551
9580
|
});
|
|
8552
9581
|
if (!res2.ok) throw new Error();
|
|
8553
9582
|
}
|
|
8554
|
-
|
|
9583
|
+
import_sonner7.toast.success("Settings saved");
|
|
8555
9584
|
onSaved?.();
|
|
8556
9585
|
} catch {
|
|
8557
|
-
|
|
9586
|
+
import_sonner7.toast.error("Failed to save");
|
|
8558
9587
|
} finally {
|
|
8559
9588
|
setSaving(false);
|
|
8560
9589
|
}
|
|
@@ -9170,10 +10199,10 @@ function PluginListItem({
|
|
|
9170
10199
|
);
|
|
9171
10200
|
}
|
|
9172
10201
|
function PluginsPage() {
|
|
9173
|
-
const { pluginDescriptors = [] } = (0,
|
|
9174
|
-
const [selectedName, setSelectedName] = (0,
|
|
9175
|
-
const [enabledMap, setEnabledMap] = (0,
|
|
9176
|
-
(0,
|
|
10202
|
+
const { pluginDescriptors = [] } = (0, import_react41.useContext)(AdminConfigContext);
|
|
10203
|
+
const [selectedName, setSelectedName] = (0, import_react41.useState)(null);
|
|
10204
|
+
const [enabledMap, setEnabledMap] = (0, import_react41.useState)({});
|
|
10205
|
+
(0, import_react41.useEffect)(() => {
|
|
9177
10206
|
pluginDescriptors.forEach((p) => {
|
|
9178
10207
|
if (!p.settingsGroup) return;
|
|
9179
10208
|
fetch(`/api/settings/${p.settingsGroup}`).then((r) => r.ok ? r.json() : {}).then(
|
|
@@ -9234,8 +10263,8 @@ function PluginsPage() {
|
|
|
9234
10263
|
}
|
|
9235
10264
|
|
|
9236
10265
|
// src/admin/pages/BrandEditPage.tsx
|
|
9237
|
-
var
|
|
9238
|
-
var
|
|
10266
|
+
var import_react42 = require("react");
|
|
10267
|
+
var import_navigation18 = require("next/navigation");
|
|
9239
10268
|
var import_lucide_react33 = require("lucide-react");
|
|
9240
10269
|
|
|
9241
10270
|
// src/components/Admin/SeoSection.tsx
|
|
@@ -9330,20 +10359,20 @@ async function fetchSeo(seoId) {
|
|
|
9330
10359
|
var import_jsx_runtime58 = require("react/jsx-runtime");
|
|
9331
10360
|
var isCreate = (id) => id === "create";
|
|
9332
10361
|
function BrandEditPage({ brandId }) {
|
|
9333
|
-
const router = (0,
|
|
10362
|
+
const router = (0, import_navigation18.useRouter)();
|
|
9334
10363
|
const create = isCreate(brandId);
|
|
9335
|
-
const [loading, setLoading] = (0,
|
|
9336
|
-
const [saving, setSaving] = (0,
|
|
9337
|
-
const [errors, setErrors] = (0,
|
|
9338
|
-
const [name, setName] = (0,
|
|
9339
|
-
const [slug, setSlug] = (0,
|
|
9340
|
-
const [description, setDescription] = (0,
|
|
9341
|
-
const [logo, setLogo] = (0,
|
|
9342
|
-
const [active, setActive] = (0,
|
|
9343
|
-
const [sortOrder, setSortOrder] = (0,
|
|
9344
|
-
const [seoId, setSeoId] = (0,
|
|
9345
|
-
const [seo, setSeo] = (0,
|
|
9346
|
-
(0,
|
|
10364
|
+
const [loading, setLoading] = (0, import_react42.useState)(!create);
|
|
10365
|
+
const [saving, setSaving] = (0, import_react42.useState)(false);
|
|
10366
|
+
const [errors, setErrors] = (0, import_react42.useState)([]);
|
|
10367
|
+
const [name, setName] = (0, import_react42.useState)("");
|
|
10368
|
+
const [slug, setSlug] = (0, import_react42.useState)("");
|
|
10369
|
+
const [description, setDescription] = (0, import_react42.useState)("");
|
|
10370
|
+
const [logo, setLogo] = (0, import_react42.useState)("");
|
|
10371
|
+
const [active, setActive] = (0, import_react42.useState)(true);
|
|
10372
|
+
const [sortOrder, setSortOrder] = (0, import_react42.useState)(0);
|
|
10373
|
+
const [seoId, setSeoId] = (0, import_react42.useState)(null);
|
|
10374
|
+
const [seo, setSeo] = (0, import_react42.useState)({ seoTitle: "", seoDescription: "", seoKeywords: "", seoOgTitle: "", seoOgDescription: "", seoOgImage: "" });
|
|
10375
|
+
(0, import_react42.useEffect)(() => {
|
|
9347
10376
|
if (create) return;
|
|
9348
10377
|
let cancelled = false;
|
|
9349
10378
|
(async () => {
|
|
@@ -9423,8 +10452,8 @@ function BrandEditPage({ brandId }) {
|
|
|
9423
10452
|
subtitle: create ? "Create a new brand" : "Update brand details",
|
|
9424
10453
|
closeHref: "/admin/brands",
|
|
9425
10454
|
menuItems: [
|
|
9426
|
-
{ label: saving ? "Saving..." : "Save", onClick: handleSave },
|
|
9427
|
-
{ label: active ? "Deactivate" : "Activate", onClick: () => setActive(!active) }
|
|
10455
|
+
{ label: saving ? "Saving..." : "Save", icon: import_lucide_react33.Save, onClick: handleSave },
|
|
10456
|
+
{ label: active ? "Deactivate" : "Activate", icon: import_lucide_react33.Power, onClick: () => setActive(!active) }
|
|
9428
10457
|
]
|
|
9429
10458
|
}
|
|
9430
10459
|
),
|
|
@@ -9532,12 +10561,12 @@ function BrandEditPage({ brandId }) {
|
|
|
9532
10561
|
}
|
|
9533
10562
|
|
|
9534
10563
|
// src/admin/pages/ProductEditPage.tsx
|
|
9535
|
-
var
|
|
9536
|
-
var
|
|
10564
|
+
var import_react44 = require("react");
|
|
10565
|
+
var import_navigation19 = require("next/navigation");
|
|
9537
10566
|
var import_lucide_react34 = require("lucide-react");
|
|
9538
10567
|
|
|
9539
10568
|
// src/components/Admin/AttributeFacetNameInput.tsx
|
|
9540
|
-
var
|
|
10569
|
+
var import_react43 = require("react");
|
|
9541
10570
|
var import_jsx_runtime59 = require("react/jsx-runtime");
|
|
9542
10571
|
function slugFromName(name) {
|
|
9543
10572
|
const s = name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -9548,13 +10577,16 @@ function AttributeFacetNameInput({
|
|
|
9548
10577
|
onChange,
|
|
9549
10578
|
inputClassName
|
|
9550
10579
|
}) {
|
|
9551
|
-
const [draft, setDraft] = (0,
|
|
9552
|
-
const [open, setOpen] = (0,
|
|
9553
|
-
const [list, setList] = (0,
|
|
9554
|
-
(0,
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
10580
|
+
const [draft, setDraft] = (0, import_react43.useState)(value);
|
|
10581
|
+
const [open, setOpen] = (0, import_react43.useState)(false);
|
|
10582
|
+
const [list, setList] = (0, import_react43.useState)([]);
|
|
10583
|
+
const isFocusedRef = (0, import_react43.useRef)(false);
|
|
10584
|
+
(0, import_react43.useEffect)(() => {
|
|
10585
|
+
if (!isFocusedRef.current && value !== draft) {
|
|
10586
|
+
setDraft(value);
|
|
10587
|
+
}
|
|
10588
|
+
}, [value, draft]);
|
|
10589
|
+
(0, import_react43.useEffect)(() => {
|
|
9558
10590
|
const q = draft.trim();
|
|
9559
10591
|
if (!q) {
|
|
9560
10592
|
setList([]);
|
|
@@ -9616,8 +10648,12 @@ function AttributeFacetNameInput({
|
|
|
9616
10648
|
setDraft(e.target.value);
|
|
9617
10649
|
setOpen(true);
|
|
9618
10650
|
},
|
|
9619
|
-
onFocus: () =>
|
|
10651
|
+
onFocus: () => {
|
|
10652
|
+
setOpen(true);
|
|
10653
|
+
isFocusedRef.current = true;
|
|
10654
|
+
},
|
|
9620
10655
|
onBlur: () => setTimeout(() => {
|
|
10656
|
+
isFocusedRef.current = false;
|
|
9621
10657
|
setOpen(false);
|
|
9622
10658
|
onChange(draft.trim());
|
|
9623
10659
|
}, 200),
|
|
@@ -9705,37 +10741,37 @@ function pickOtherMetadata(m) {
|
|
|
9705
10741
|
return rest;
|
|
9706
10742
|
}
|
|
9707
10743
|
function ProductEditPage({ productId }) {
|
|
9708
|
-
const router = (0,
|
|
10744
|
+
const router = (0, import_navigation19.useRouter)();
|
|
9709
10745
|
const create = isCreate2(productId);
|
|
9710
|
-
const [loading, setLoading] = (0,
|
|
9711
|
-
const [saving, setSaving] = (0,
|
|
9712
|
-
const [errors, setErrors] = (0,
|
|
9713
|
-
const [collections, setCollections] = (0,
|
|
9714
|
-
const [brands, setBrands] = (0,
|
|
9715
|
-
const [categories, setCategories] = (0,
|
|
9716
|
-
const [name, setName] = (0,
|
|
9717
|
-
const [productSlug, setProductSlug] = (0,
|
|
9718
|
-
const [sku, setSku] = (0,
|
|
9719
|
-
const [hsn, setHsn] = (0,
|
|
9720
|
-
const [uom, setUom] = (0,
|
|
9721
|
-
const [productType, setProductType] = (0,
|
|
9722
|
-
const [collectionId, setCollectionId] = (0,
|
|
9723
|
-
const [brandId, setBrandId] = (0,
|
|
9724
|
-
const [categoryId, setCategoryId] = (0,
|
|
9725
|
-
const [price, setPrice] = (0,
|
|
9726
|
-
const [compareAtPrice, setCompareAtPrice] = (0,
|
|
9727
|
-
const [quantity, setQuantity] = (0,
|
|
9728
|
-
const [status, setStatus] = (0,
|
|
9729
|
-
const [featured, setFeatured] = (0,
|
|
9730
|
-
const [description, setDescription] = (0,
|
|
9731
|
-
const [images, setImages] = (0,
|
|
9732
|
-
const [specifications, setSpecifications] = (0,
|
|
9733
|
-
const [otherMetadata, setOtherMetadata] = (0,
|
|
9734
|
-
const [facetRows, setFacetRows] = (0,
|
|
9735
|
-
const [taxMasterList, setTaxMasterList] = (0,
|
|
9736
|
-
const [taxRows, setTaxRows] = (0,
|
|
9737
|
-
const [seoId, setSeoId] = (0,
|
|
9738
|
-
const [seo, setSeo] = (0,
|
|
10746
|
+
const [loading, setLoading] = (0, import_react44.useState)(!create);
|
|
10747
|
+
const [saving, setSaving] = (0, import_react44.useState)(false);
|
|
10748
|
+
const [errors, setErrors] = (0, import_react44.useState)([]);
|
|
10749
|
+
const [collections, setCollections] = (0, import_react44.useState)([]);
|
|
10750
|
+
const [brands, setBrands] = (0, import_react44.useState)([]);
|
|
10751
|
+
const [categories, setCategories] = (0, import_react44.useState)([]);
|
|
10752
|
+
const [name, setName] = (0, import_react44.useState)("");
|
|
10753
|
+
const [productSlug, setProductSlug] = (0, import_react44.useState)("");
|
|
10754
|
+
const [sku, setSku] = (0, import_react44.useState)("");
|
|
10755
|
+
const [hsn, setHsn] = (0, import_react44.useState)("");
|
|
10756
|
+
const [uom, setUom] = (0, import_react44.useState)("");
|
|
10757
|
+
const [productType, setProductType] = (0, import_react44.useState)("product");
|
|
10758
|
+
const [collectionId, setCollectionId] = (0, import_react44.useState)(null);
|
|
10759
|
+
const [brandId, setBrandId] = (0, import_react44.useState)(null);
|
|
10760
|
+
const [categoryId, setCategoryId] = (0, import_react44.useState)(null);
|
|
10761
|
+
const [price, setPrice] = (0, import_react44.useState)("");
|
|
10762
|
+
const [compareAtPrice, setCompareAtPrice] = (0, import_react44.useState)("");
|
|
10763
|
+
const [quantity, setQuantity] = (0, import_react44.useState)(1);
|
|
10764
|
+
const [status, setStatus] = (0, import_react44.useState)("draft");
|
|
10765
|
+
const [featured, setFeatured] = (0, import_react44.useState)(false);
|
|
10766
|
+
const [description, setDescription] = (0, import_react44.useState)("");
|
|
10767
|
+
const [images, setImages] = (0, import_react44.useState)([{ url: "", alt: "", isDefault: true }]);
|
|
10768
|
+
const [specifications, setSpecifications] = (0, import_react44.useState)([{ key: "", value: "" }]);
|
|
10769
|
+
const [otherMetadata, setOtherMetadata] = (0, import_react44.useState)({});
|
|
10770
|
+
const [facetRows, setFacetRows] = (0, import_react44.useState)([{ name: "", value: "" }]);
|
|
10771
|
+
const [taxMasterList, setTaxMasterList] = (0, import_react44.useState)([]);
|
|
10772
|
+
const [taxRows, setTaxRows] = (0, import_react44.useState)([{ taxId: "", rate: "" }]);
|
|
10773
|
+
const [seoId, setSeoId] = (0, import_react44.useState)(null);
|
|
10774
|
+
const [seo, setSeo] = (0, import_react44.useState)({
|
|
9739
10775
|
seoTitle: "",
|
|
9740
10776
|
seoDescription: "",
|
|
9741
10777
|
seoKeywords: "",
|
|
@@ -9743,7 +10779,7 @@ function ProductEditPage({ productId }) {
|
|
|
9743
10779
|
seoOgDescription: "",
|
|
9744
10780
|
seoOgImage: ""
|
|
9745
10781
|
});
|
|
9746
|
-
(0,
|
|
10782
|
+
(0, import_react44.useEffect)(() => {
|
|
9747
10783
|
let cancelled = false;
|
|
9748
10784
|
(async () => {
|
|
9749
10785
|
try {
|
|
@@ -9861,7 +10897,7 @@ function ProductEditPage({ productId }) {
|
|
|
9861
10897
|
cancelled = true;
|
|
9862
10898
|
};
|
|
9863
10899
|
}, [productId, create]);
|
|
9864
|
-
(0,
|
|
10900
|
+
(0, import_react44.useEffect)(() => {
|
|
9865
10901
|
if (!create || !name.trim() || productSlug.trim()) return;
|
|
9866
10902
|
setProductSlug(
|
|
9867
10903
|
name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "")
|
|
@@ -10073,8 +11109,8 @@ function ProductEditPage({ productId }) {
|
|
|
10073
11109
|
subtitle: create ? "Create a new product" : "Update product details",
|
|
10074
11110
|
closeHref: "/admin/products",
|
|
10075
11111
|
menuItems: [
|
|
10076
|
-
{ label: saving ? "Saving..." : "Save", onClick: handleSave },
|
|
10077
|
-
{ label: featured ? "Unfeature" : "Feature", onClick: () => setFeatured(!featured) }
|
|
11112
|
+
{ label: saving ? "Saving..." : "Save", icon: import_lucide_react34.Save, onClick: handleSave },
|
|
11113
|
+
{ label: featured ? "Unfeature" : "Feature", icon: import_lucide_react34.Star, onClick: () => setFeatured(!featured) }
|
|
10078
11114
|
]
|
|
10079
11115
|
}
|
|
10080
11116
|
),
|
|
@@ -10392,8 +11428,8 @@ function ProductEditPage({ productId }) {
|
|
|
10392
11428
|
}
|
|
10393
11429
|
|
|
10394
11430
|
// src/admin/pages/CollectionEditPage.tsx
|
|
10395
|
-
var
|
|
10396
|
-
var
|
|
11431
|
+
var import_react45 = require("react");
|
|
11432
|
+
var import_navigation20 = require("next/navigation");
|
|
10397
11433
|
var import_lucide_react35 = require("lucide-react");
|
|
10398
11434
|
var import_jsx_runtime61 = require("react/jsx-runtime");
|
|
10399
11435
|
var isCreate3 = (id) => id === "create";
|
|
@@ -10403,29 +11439,29 @@ var sectionCls2 = "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4
|
|
|
10403
11439
|
var labelCls2 = "block text-xs font-medium text-gray-600 mb-1";
|
|
10404
11440
|
var inputCls2 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm";
|
|
10405
11441
|
function CollectionEditPage({ collectionId }) {
|
|
10406
|
-
const router = (0,
|
|
11442
|
+
const router = (0, import_navigation20.useRouter)();
|
|
10407
11443
|
const create = isCreate3(collectionId);
|
|
10408
|
-
const [loading, setLoading] = (0,
|
|
10409
|
-
const [saving, setSaving] = (0,
|
|
10410
|
-
const [errors, setErrors] = (0,
|
|
10411
|
-
const [categories, setCategories] = (0,
|
|
10412
|
-
const [brands, setBrands] = (0,
|
|
10413
|
-
const [name, setName] = (0,
|
|
10414
|
-
const [slug, setSlug] = (0,
|
|
10415
|
-
const [hsn, setHsn] = (0,
|
|
10416
|
-
const [categoryId, setCategoryId] = (0,
|
|
10417
|
-
const [brandId, setBrandId] = (0,
|
|
10418
|
-
const [description, setDescription] = (0,
|
|
10419
|
-
const [image, setImage] = (0,
|
|
10420
|
-
const [active, setActive] = (0,
|
|
10421
|
-
const [sortOrder, setSortOrder] = (0,
|
|
10422
|
-
const [advancedOpen, setAdvancedOpen] = (0,
|
|
10423
|
-
const [heroSlides, setHeroSlides] = (0,
|
|
10424
|
-
const [variants, setVariants] = (0,
|
|
10425
|
-
const [experienceDescription, setExperienceDescription] = (0,
|
|
10426
|
-
const [brochureUrl, setBrochureUrl] = (0,
|
|
10427
|
-
const [seoId, setSeoId] = (0,
|
|
10428
|
-
const [seo, setSeo] = (0,
|
|
11444
|
+
const [loading, setLoading] = (0, import_react45.useState)(!create);
|
|
11445
|
+
const [saving, setSaving] = (0, import_react45.useState)(false);
|
|
11446
|
+
const [errors, setErrors] = (0, import_react45.useState)([]);
|
|
11447
|
+
const [categories, setCategories] = (0, import_react45.useState)([]);
|
|
11448
|
+
const [brands, setBrands] = (0, import_react45.useState)([]);
|
|
11449
|
+
const [name, setName] = (0, import_react45.useState)("");
|
|
11450
|
+
const [slug, setSlug] = (0, import_react45.useState)("");
|
|
11451
|
+
const [hsn, setHsn] = (0, import_react45.useState)("");
|
|
11452
|
+
const [categoryId, setCategoryId] = (0, import_react45.useState)(null);
|
|
11453
|
+
const [brandId, setBrandId] = (0, import_react45.useState)(null);
|
|
11454
|
+
const [description, setDescription] = (0, import_react45.useState)("");
|
|
11455
|
+
const [image, setImage] = (0, import_react45.useState)("");
|
|
11456
|
+
const [active, setActive] = (0, import_react45.useState)(true);
|
|
11457
|
+
const [sortOrder, setSortOrder] = (0, import_react45.useState)(0);
|
|
11458
|
+
const [advancedOpen, setAdvancedOpen] = (0, import_react45.useState)(false);
|
|
11459
|
+
const [heroSlides, setHeroSlides] = (0, import_react45.useState)([emptySlide()]);
|
|
11460
|
+
const [variants, setVariants] = (0, import_react45.useState)([emptyVariant()]);
|
|
11461
|
+
const [experienceDescription, setExperienceDescription] = (0, import_react45.useState)("");
|
|
11462
|
+
const [brochureUrl, setBrochureUrl] = (0, import_react45.useState)("");
|
|
11463
|
+
const [seoId, setSeoId] = (0, import_react45.useState)(null);
|
|
11464
|
+
const [seo, setSeo] = (0, import_react45.useState)({
|
|
10429
11465
|
seoTitle: "",
|
|
10430
11466
|
seoDescription: "",
|
|
10431
11467
|
seoKeywords: "",
|
|
@@ -10433,7 +11469,7 @@ function CollectionEditPage({ collectionId }) {
|
|
|
10433
11469
|
seoOgDescription: "",
|
|
10434
11470
|
seoOgImage: ""
|
|
10435
11471
|
});
|
|
10436
|
-
(0,
|
|
11472
|
+
(0, import_react45.useEffect)(() => {
|
|
10437
11473
|
let cancelled = false;
|
|
10438
11474
|
(async () => {
|
|
10439
11475
|
try {
|
|
@@ -10606,8 +11642,8 @@ function CollectionEditPage({ collectionId }) {
|
|
|
10606
11642
|
subtitle: create ? "Create a new collection" : "Update collection and page content",
|
|
10607
11643
|
closeHref: "/admin/collections",
|
|
10608
11644
|
menuItems: [
|
|
10609
|
-
{ label: saving ? "Saving..." : "Save", onClick: handleSave },
|
|
10610
|
-
{ label: active ? "Deactivate" : "Activate", onClick: () => setActive(!active) }
|
|
11645
|
+
{ label: saving ? "Saving..." : "Save", icon: import_lucide_react35.Save, onClick: handleSave },
|
|
11646
|
+
{ label: active ? "Deactivate" : "Activate", icon: import_lucide_react35.Power, onClick: () => setActive(!active) }
|
|
10611
11647
|
]
|
|
10612
11648
|
}
|
|
10613
11649
|
),
|
|
@@ -10750,8 +11786,8 @@ function CollectionEditPage({ collectionId }) {
|
|
|
10750
11786
|
}
|
|
10751
11787
|
|
|
10752
11788
|
// src/admin/pages/RolesPage.tsx
|
|
10753
|
-
var
|
|
10754
|
-
var
|
|
11789
|
+
var import_react46 = require("react");
|
|
11790
|
+
var import_react47 = require("next-auth/react");
|
|
10755
11791
|
var import_lucide_react36 = require("lucide-react");
|
|
10756
11792
|
|
|
10757
11793
|
// src/auth/permission-entities.ts
|
|
@@ -10782,18 +11818,19 @@ function RoleListItem({
|
|
|
10782
11818
|
);
|
|
10783
11819
|
}
|
|
10784
11820
|
function RolesPage() {
|
|
10785
|
-
const { data: session, status } = (0,
|
|
11821
|
+
const { data: session, status } = (0, import_react47.useSession)();
|
|
10786
11822
|
const u = session?.user;
|
|
10787
11823
|
const canManage = !!u?.isRBACAdmin;
|
|
10788
|
-
const [entities, setEntities] = (0,
|
|
10789
|
-
const [groups, setGroups] = (0,
|
|
10790
|
-
const [selectedId, setSelectedId] = (0,
|
|
10791
|
-
const [matrix, setMatrix] = (0,
|
|
10792
|
-
const [loading, setLoading] = (0,
|
|
10793
|
-
const [saving, setSaving] = (0,
|
|
10794
|
-
const [newName, setNewName] = (0,
|
|
10795
|
-
const [
|
|
10796
|
-
const
|
|
11824
|
+
const [entities, setEntities] = (0, import_react46.useState)([]);
|
|
11825
|
+
const [groups, setGroups] = (0, import_react46.useState)([]);
|
|
11826
|
+
const [selectedId, setSelectedId] = (0, import_react46.useState)(null);
|
|
11827
|
+
const [matrix, setMatrix] = (0, import_react46.useState)({});
|
|
11828
|
+
const [loading, setLoading] = (0, import_react46.useState)(true);
|
|
11829
|
+
const [saving, setSaving] = (0, import_react46.useState)(false);
|
|
11830
|
+
const [newName, setNewName] = (0, import_react46.useState)("");
|
|
11831
|
+
const [deleteRoleOpen, setDeleteRoleOpen] = (0, import_react46.useState)(false);
|
|
11832
|
+
const [error, setError] = (0, import_react46.useState)(null);
|
|
11833
|
+
const load = (0, import_react46.useCallback)(async () => {
|
|
10797
11834
|
setLoading(true);
|
|
10798
11835
|
setError(null);
|
|
10799
11836
|
try {
|
|
@@ -10818,11 +11855,11 @@ function RolesPage() {
|
|
|
10818
11855
|
setLoading(false);
|
|
10819
11856
|
}
|
|
10820
11857
|
}, []);
|
|
10821
|
-
(0,
|
|
11858
|
+
(0, import_react46.useEffect)(() => {
|
|
10822
11859
|
if (status === "authenticated" && canManage) load();
|
|
10823
11860
|
}, [status, canManage, load]);
|
|
10824
11861
|
const selected = groups.find((g) => g.id === selectedId);
|
|
10825
|
-
(0,
|
|
11862
|
+
(0, import_react46.useEffect)(() => {
|
|
10826
11863
|
if (!selected || !entities.length) {
|
|
10827
11864
|
setMatrix({});
|
|
10828
11865
|
return;
|
|
@@ -10847,6 +11884,45 @@ function RolesPage() {
|
|
|
10847
11884
|
[entity]: { ...prev[entity], [key]: !prev[entity][key] }
|
|
10848
11885
|
}));
|
|
10849
11886
|
};
|
|
11887
|
+
const PERM_KEYS = [
|
|
11888
|
+
"canCreate",
|
|
11889
|
+
"canRead",
|
|
11890
|
+
"canUpdate",
|
|
11891
|
+
"canDelete"
|
|
11892
|
+
];
|
|
11893
|
+
const isColumnAllChecked = (key) => entities.length > 0 && entities.every((entity) => matrix[entity]?.[key]);
|
|
11894
|
+
const toggleColumn = (key) => {
|
|
11895
|
+
const nextValue = !isColumnAllChecked(key);
|
|
11896
|
+
setMatrix((prev) => {
|
|
11897
|
+
const next = { ...prev };
|
|
11898
|
+
for (const entity of entities) {
|
|
11899
|
+
if (!next[entity]) continue;
|
|
11900
|
+
next[entity] = { ...next[entity], [key]: nextValue };
|
|
11901
|
+
}
|
|
11902
|
+
return next;
|
|
11903
|
+
});
|
|
11904
|
+
};
|
|
11905
|
+
const isAllChecked = entities.length > 0 && entities.every((entity) => {
|
|
11906
|
+
const row = matrix[entity];
|
|
11907
|
+
return row ? PERM_KEYS.every((k) => row[k]) : false;
|
|
11908
|
+
});
|
|
11909
|
+
const toggleAll = () => {
|
|
11910
|
+
const nextValue = !isAllChecked;
|
|
11911
|
+
setMatrix((prev) => {
|
|
11912
|
+
const next = { ...prev };
|
|
11913
|
+
for (const entity of entities) {
|
|
11914
|
+
if (!next[entity]) continue;
|
|
11915
|
+
next[entity] = {
|
|
11916
|
+
...next[entity],
|
|
11917
|
+
canCreate: nextValue,
|
|
11918
|
+
canRead: nextValue,
|
|
11919
|
+
canUpdate: nextValue,
|
|
11920
|
+
canDelete: nextValue
|
|
11921
|
+
};
|
|
11922
|
+
}
|
|
11923
|
+
return next;
|
|
11924
|
+
});
|
|
11925
|
+
};
|
|
10850
11926
|
const saveMatrix = async () => {
|
|
10851
11927
|
if (!selectedId) return;
|
|
10852
11928
|
setSaving(true);
|
|
@@ -10895,7 +11971,6 @@ function RolesPage() {
|
|
|
10895
11971
|
};
|
|
10896
11972
|
const deleteGroup = async () => {
|
|
10897
11973
|
if (!selectedId || !selected || isSuperAdminGroupName(selected.name)) return;
|
|
10898
|
-
if (!confirm(`Delete group "${selected.name}"?`)) return;
|
|
10899
11974
|
try {
|
|
10900
11975
|
const res = await fetch(`/api/admin/roles/${selectedId}`, { method: "DELETE" });
|
|
10901
11976
|
if (!res.ok) {
|
|
@@ -10904,6 +11979,7 @@ function RolesPage() {
|
|
|
10904
11979
|
return;
|
|
10905
11980
|
}
|
|
10906
11981
|
setSelectedId(null);
|
|
11982
|
+
setDeleteRoleOpen(false);
|
|
10907
11983
|
await load();
|
|
10908
11984
|
} catch {
|
|
10909
11985
|
setError("Delete failed");
|
|
@@ -10957,18 +12033,33 @@ function RolesPage() {
|
|
|
10957
12033
|
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react36.Save, { className: "h-3.5 w-3.5" }),
|
|
10958
12034
|
saving ? "Saving\u2026" : "Save"
|
|
10959
12035
|
] }),
|
|
10960
|
-
selected && !isSuperAdminGroupName(selected.name) && /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(Button, { size: "sm", variant: "outline", className: "gap-1 text-red-600", onClick:
|
|
12036
|
+
selected && !isSuperAdminGroupName(selected.name) && /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(Button, { size: "sm", variant: "outline", className: "gap-1 text-red-600", onClick: () => setDeleteRoleOpen(true), children: [
|
|
10961
12037
|
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react36.Trash2, { className: "h-3.5 w-3.5" }),
|
|
10962
12038
|
"Delete role"
|
|
10963
12039
|
] })
|
|
10964
12040
|
] }),
|
|
10965
12041
|
entities.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "overflow-x-auto rounded-md border border-gray-200 dark:border-gray-600", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("table", { className: "w-full text-sm", children: [
|
|
10966
12042
|
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("tr", { className: "border-b bg-gray-50 dark:bg-gray-900/50", children: [
|
|
10967
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("th", { className: "p-3 text-left font-medium", children: "
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("th", { className: "p-2", children: "
|
|
12043
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("th", { className: "p-3 text-left font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12044
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("input", { type: "checkbox", checked: isAllChecked, onChange: toggleAll }),
|
|
12045
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: "Resource" })
|
|
12046
|
+
] }) }),
|
|
12047
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("th", { className: "p-2", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
|
|
12048
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: "C" }),
|
|
12049
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("input", { type: "checkbox", checked: isColumnAllChecked("canCreate"), onChange: () => toggleColumn("canCreate") })
|
|
12050
|
+
] }) }),
|
|
12051
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("th", { className: "p-2", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
|
|
12052
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: "R" }),
|
|
12053
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("input", { type: "checkbox", checked: isColumnAllChecked("canRead"), onChange: () => toggleColumn("canRead") })
|
|
12054
|
+
] }) }),
|
|
12055
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("th", { className: "p-2", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
|
|
12056
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: "U" }),
|
|
12057
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("input", { type: "checkbox", checked: isColumnAllChecked("canUpdate"), onChange: () => toggleColumn("canUpdate") })
|
|
12058
|
+
] }) }),
|
|
12059
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("th", { className: "p-2", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
|
|
12060
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: "D" }),
|
|
12061
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("input", { type: "checkbox", checked: isColumnAllChecked("canDelete"), onChange: () => toggleColumn("canDelete") })
|
|
12062
|
+
] }) })
|
|
10972
12063
|
] }) }),
|
|
10973
12064
|
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("tbody", { children: entities.map((entity) => {
|
|
10974
12065
|
const row = matrix[entity];
|
|
@@ -10992,7 +12083,15 @@ function RolesPage() {
|
|
|
10992
12083
|
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Input, { placeholder: "New role name", value: newName, onChange: (e) => setNewName(e.target.value), onKeyDown: (e) => e.key === "Enter" && createGroup() }),
|
|
10993
12084
|
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Button, { type: "button", onClick: createGroup, children: "Add role" })
|
|
10994
12085
|
] })
|
|
10995
|
-
] })
|
|
12086
|
+
] }),
|
|
12087
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Dialog, { open: deleteRoleOpen, onOpenChange: setDeleteRoleOpen, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(DialogContent, { children: [
|
|
12088
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(DialogTitle, { children: "Delete Role" }) }),
|
|
12089
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: "text-sm text-gray-600", children: selected ? `Delete group "${selected.name}"?` : "Delete selected role?" }),
|
|
12090
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(DialogFooter, { children: [
|
|
12091
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Button, { variant: "outline", onClick: () => setDeleteRoleOpen(false), children: "Cancel" }),
|
|
12092
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Button, { variant: "destructive", onClick: deleteGroup, children: "Delete" })
|
|
12093
|
+
] })
|
|
12094
|
+
] }) })
|
|
10996
12095
|
] });
|
|
10997
12096
|
}
|
|
10998
12097
|
|
|
@@ -11270,9 +12369,9 @@ var CRUD_CONFIGS = {
|
|
|
11270
12369
|
}
|
|
11271
12370
|
};
|
|
11272
12371
|
function BlogEditorWrapper({ blogId }) {
|
|
11273
|
-
const [blog, setBlog] = (0,
|
|
11274
|
-
const [loading, setLoading] = (0,
|
|
11275
|
-
(0,
|
|
12372
|
+
const [blog, setBlog] = (0, import_react48.useState)(null);
|
|
12373
|
+
const [loading, setLoading] = (0, import_react48.useState)(!!blogId);
|
|
12374
|
+
(0, import_react48.useEffect)(() => {
|
|
11276
12375
|
if (!blogId) return;
|
|
11277
12376
|
fetch(`/api/blogs/${blogId}`).then((res) => res.ok ? res.json() : null).then((data) => setBlog(data)).finally(() => setLoading(false));
|
|
11278
12377
|
}, [blogId]);
|
|
@@ -11285,10 +12384,10 @@ function BlogEditorWrapper({ blogId }) {
|
|
|
11285
12384
|
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(BlogEditor, { existingBlog: blog });
|
|
11286
12385
|
}
|
|
11287
12386
|
function AdminPageResolver({ slug }) {
|
|
11288
|
-
const router = (0,
|
|
11289
|
-
const { customCrudConfigs, storeEnabled } = (0,
|
|
12387
|
+
const router = (0, import_navigation21.useRouter)();
|
|
12388
|
+
const { customCrudConfigs, storeEnabled } = (0, import_react48.useContext)(AdminConfigContext);
|
|
11290
12389
|
const key = slug?.[0] || "dashboard";
|
|
11291
|
-
(0,
|
|
12390
|
+
(0, import_react48.useEffect)(() => {
|
|
11292
12391
|
if (key === "layout-settings") {
|
|
11293
12392
|
router.replace("/admin/settings?tab=navbar");
|
|
11294
12393
|
}
|
|
@@ -11348,7 +12447,7 @@ function AdminPageResolver({ slug }) {
|
|
|
11348
12447
|
{ field: "orderCount", displayName: "Orders" },
|
|
11349
12448
|
{ field: "totalPaid", displayName: "Total paid" }
|
|
11350
12449
|
] : crud.columns;
|
|
11351
|
-
const extraListParams = (0,
|
|
12450
|
+
const extraListParams = (0, import_react48.useMemo)(
|
|
11352
12451
|
() => isContactsWithStore ? { includeSummary: "1" } : void 0,
|
|
11353
12452
|
[isContactsWithStore]
|
|
11354
12453
|
);
|
|
@@ -11371,22 +12470,22 @@ function AdminPageResolver({ slug }) {
|
|
|
11371
12470
|
}
|
|
11372
12471
|
|
|
11373
12472
|
// src/admin/pages/LayoutSettingsPage.tsx
|
|
11374
|
-
var
|
|
12473
|
+
var import_react49 = require("react");
|
|
11375
12474
|
var import_lucide_react37 = require("lucide-react");
|
|
11376
12475
|
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
11377
12476
|
function LayoutSettingsPage() {
|
|
11378
|
-
const { theme } = (0,
|
|
11379
|
-
const [activeTab, setActiveTab] = (0,
|
|
11380
|
-
const [navbarConfig, setNavbarConfig] = (0,
|
|
12477
|
+
const { theme } = (0, import_react49.useContext)(AdminConfigContext);
|
|
12478
|
+
const [activeTab, setActiveTab] = (0, import_react49.useState)("navbar");
|
|
12479
|
+
const [navbarConfig, setNavbarConfig] = (0, import_react49.useState)({
|
|
11381
12480
|
logo: "",
|
|
11382
12481
|
items: [],
|
|
11383
12482
|
ctaLabel: "",
|
|
11384
12483
|
ctaUrl: ""
|
|
11385
12484
|
});
|
|
11386
|
-
const [footerValues, setFooterValues] = (0,
|
|
11387
|
-
const [saving, setSaving] = (0,
|
|
11388
|
-
const [loading, setLoading] = (0,
|
|
11389
|
-
(0,
|
|
12485
|
+
const [footerValues, setFooterValues] = (0, import_react49.useState)({});
|
|
12486
|
+
const [saving, setSaving] = (0, import_react49.useState)(false);
|
|
12487
|
+
const [loading, setLoading] = (0, import_react49.useState)(true);
|
|
12488
|
+
(0, import_react49.useEffect)(() => {
|
|
11390
12489
|
fetch("/api/settings/theme").then((r) => r.ok ? r.json() : null).then((data) => {
|
|
11391
12490
|
if (!data) return;
|
|
11392
12491
|
if (data.navbar) {
|
|
@@ -11496,14 +12595,14 @@ var DEFAULT_ADMIN_NAV = [
|
|
|
11496
12595
|
];
|
|
11497
12596
|
|
|
11498
12597
|
// src/admin/CmsProviders.tsx
|
|
11499
|
-
var
|
|
12598
|
+
var import_react50 = require("next-auth/react");
|
|
11500
12599
|
var import_next_themes = require("next-themes");
|
|
11501
|
-
var
|
|
12600
|
+
var import_sonner8 = require("sonner");
|
|
11502
12601
|
var import_jsx_runtime65 = require("react/jsx-runtime");
|
|
11503
12602
|
function CmsProviders({ children }) {
|
|
11504
|
-
return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
12603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react50.SessionProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(import_next_themes.ThemeProvider, { attribute: "class", defaultTheme: "system", enableSystem: true, children: [
|
|
11505
12604
|
children,
|
|
11506
|
-
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
12605
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_sonner8.Toaster, { position: "top-right" })
|
|
11507
12606
|
] }) });
|
|
11508
12607
|
}
|
|
11509
12608
|
// Annotate the CommonJS export names for ESM import in node:
|