datastake-daf 0.6.712 → 0.6.713

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.
@@ -2224,6 +2224,21 @@ class DashboardService extends BaseService {
2224
2224
  isApp: true
2225
2225
  });
2226
2226
  }
2227
+ getUserGrowth(activeFilter) {
2228
+ return this.apiGet({
2229
+ url: `/accounts/dashboard/user-growth`,
2230
+ isUserManager: true,
2231
+ params: {
2232
+ activeFilter
2233
+ }
2234
+ });
2235
+ }
2236
+ getAdminDashboard() {
2237
+ return this.apiGet({
2238
+ url: `/accounts/dashboard`,
2239
+ isUserManager: true
2240
+ });
2241
+ }
2227
2242
  }
2228
2243
  var DashboardService$1 = createLazyService(DashboardService);
2229
2244
 
@@ -2273,8 +2288,85 @@ const useWidgetFetch = ({
2273
2288
  };
2274
2289
  };
2275
2290
 
2291
+ /**
2292
+ * Generic hook for fetching admin dashboard data
2293
+ *
2294
+ * @param {Object} config - Configuration object
2295
+ * @param {Object} config.dashboardService - Service object with getDashboardData method
2296
+ * @param {Function} config.onError - Error handler function
2297
+ *
2298
+ * @returns {Object} Dashboard data and loading states
2299
+ *
2300
+ * @example
2301
+ * const { data, loading, userGrowthData, fetchUserGrowth } = useAdminDashboard({
2302
+ * dashboardService: {
2303
+ * getDashboardData: () => DashboardService.getAdminStats(),
2304
+ * getUserGrowth: (params) => DashboardService.getUserGrowth(params)
2305
+ * },
2306
+ * onError: (err) => console.error(err)
2307
+ * });
2308
+ */
2309
+ function useAdminDashboard({
2310
+ dashboardService,
2311
+ onError
2312
+ }) {
2313
+ const [data, setData] = React.useState({});
2314
+ const [loading, setLoading] = React.useState(false);
2315
+ const [userGrowthData, setUserGrowthData] = React.useState([]);
2316
+ const [userGrowthDataLoading, setUserGrowthDataLoading] = React.useState(false);
2317
+ const fetchDashboardData = React.useCallback(async () => {
2318
+ if (!dashboardService?.getDashboardData) {
2319
+ console.warn("dashboardService.getDashboardData not provided");
2320
+ return;
2321
+ }
2322
+ setLoading(true);
2323
+ try {
2324
+ const response = await dashboardService.getDashboardData();
2325
+ setData(response || {});
2326
+ } catch (err) {
2327
+ if (onError) {
2328
+ onError(err);
2329
+ } else {
2330
+ console.error("Error fetching dashboard data:", err);
2331
+ }
2332
+ } finally {
2333
+ setLoading(false);
2334
+ }
2335
+ }, [dashboardService, onError]);
2336
+ const fetchUserGrowth = React.useCallback(async params => {
2337
+ if (!dashboardService?.getUserGrowth) {
2338
+ console.warn("dashboardService.getUserGrowth not provided");
2339
+ return;
2340
+ }
2341
+ setUserGrowthDataLoading(true);
2342
+ try {
2343
+ const response = await dashboardService.getUserGrowth(params);
2344
+ setUserGrowthData(response || []);
2345
+ } catch (err) {
2346
+ if (onError) {
2347
+ onError(err);
2348
+ } else {
2349
+ console.error("Error fetching user growth:", err);
2350
+ }
2351
+ } finally {
2352
+ setUserGrowthDataLoading(false);
2353
+ }
2354
+ }, [dashboardService, onError]);
2355
+ React.useEffect(() => {
2356
+ fetchDashboardData();
2357
+ }, [fetchDashboardData]);
2358
+ return {
2359
+ data,
2360
+ loading,
2361
+ userGrowthData,
2362
+ fetchUserGrowth,
2363
+ userGrowthDataLoading
2364
+ };
2365
+ }
2366
+
2276
2367
  exports.checkPermission = checkPermission;
2277
2368
  exports.checkPermissionList = checkPermissionList;
2369
+ exports.useAdminDashboard = useAdminDashboard;
2278
2370
  exports.useFilters = useFilters;
2279
2371
  exports.useFirebase = useFirebase;
2280
2372
  exports.useHeight = useHeight;
@@ -6322,6 +6322,21 @@ class DashboardService extends BaseService {
6322
6322
  isApp: true
6323
6323
  });
6324
6324
  }
6325
+ getUserGrowth(activeFilter) {
6326
+ return this.apiGet({
6327
+ url: `/accounts/dashboard/user-growth`,
6328
+ isUserManager: true,
6329
+ params: {
6330
+ activeFilter
6331
+ }
6332
+ });
6333
+ }
6334
+ getAdminDashboard() {
6335
+ return this.apiGet({
6336
+ url: `/accounts/dashboard`,
6337
+ isUserManager: true
6338
+ });
6339
+ }
6325
6340
  }
6326
6341
  var DashboardService$1 = createLazyService(DashboardService);
6327
6342
 
@@ -1200,6 +1200,21 @@ class DashboardService extends BaseService {
1200
1200
  isApp: true
1201
1201
  });
1202
1202
  }
1203
+ getUserGrowth(activeFilter) {
1204
+ return this.apiGet({
1205
+ url: `/accounts/dashboard/user-growth`,
1206
+ isUserManager: true,
1207
+ params: {
1208
+ activeFilter
1209
+ }
1210
+ });
1211
+ }
1212
+ getAdminDashboard() {
1213
+ return this.apiGet({
1214
+ url: `/accounts/dashboard`,
1215
+ isUserManager: true
1216
+ });
1217
+ }
1203
1218
  }
1204
1219
  var DashboardService$1 = createLazyService(DashboardService);
1205
1220
 
@@ -1542,13 +1542,13 @@ ul.ant-menu.ant-menu-dark.ant-menu-root.ant-menu-vertical::-webkit-scrollbar-thu
1542
1542
  }
1543
1543
 
1544
1544
  .components-layout:not(.nested) .sidenav-sider:not(.custom) .sidenav-cont .menus-cont.not-collapsed .sidemenu-cont .ant-menu.ant-menu-root.ant-menu-inline.ant-menu-dark
1545
- .ant-menu-item:not(.ant-menu-item-selected) svg path
1545
+ .ant-menu-item:not(.ant-menu-item-selected):not(.ant-menu-item-disabled) svg path
1546
1546
  {
1547
1547
  stroke: #ffffff !important;
1548
1548
  }
1549
1549
 
1550
1550
  .components-layout:not(.nested) .sidenav-sider:not(.custom) .sidenav-cont .menus-cont.not-collapsed .sidemenu-cont .ant-menu.ant-menu-root.ant-menu-inline.ant-menu-dark
1551
- .ant-menu-item:not(.ant-menu-item-selected) .ant-menu-title-content {
1551
+ .ant-menu-item:not(.ant-menu-item-selected):not(.ant-menu-item-disabled) .ant-menu-title-content {
1552
1552
  color: #ffffff !important;
1553
1553
  }
1554
1554
 
@@ -5127,6 +5127,9 @@ const cleanJSON = json => {
5127
5127
  }
5128
5128
  return json;
5129
5129
  };
5130
+ function formatToKebabCase$1(str) {
5131
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
5132
+ }
5130
5133
 
5131
5134
  function _checkValue$1(wantedValue, match, fieldValue) {
5132
5135
  match = match ? match.trim() : null;
@@ -14123,11 +14126,129 @@ const getDivergenceOrEqual = (data, keys) => {
14123
14126
  return data;
14124
14127
  };
14125
14128
 
14129
+ /**
14130
+ * Utility functions for building admin dashboard configurations
14131
+ * These functions transform simple data arrays into full configuration objects
14132
+ */
14133
+
14134
+ /**
14135
+ * Format string to kebab-case
14136
+ * @param {string} str - String to format
14137
+ * @returns {string} Kebab-cased string
14138
+ */
14139
+ function formatToKebabCase(str) {
14140
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
14141
+ }
14142
+
14143
+ /**
14144
+ * Build action widgets configuration
14145
+ *
14146
+ * @param {Object} params
14147
+ * @param {Array} params.widgets - Array of widget definitions
14148
+ * @param {Function} params.getRedirectLink - Function to transform paths
14149
+ * @param {Function} params.t - Translation function
14150
+ *
14151
+ * @returns {Array} Configured action widgets
14152
+ *
14153
+ * @example
14154
+ * const widgets = buildActionWidgetsConfig({
14155
+ * widgets: [
14156
+ * { icon: "Search", title: "review-requests", path: "/accounts?pending=true" }
14157
+ * ],
14158
+ * getRedirectLink: (path) => `/app${path}`,
14159
+ * t: (key) => translations[key]
14160
+ * });
14161
+ */
14162
+ function buildActionWidgetsConfig({
14163
+ widgets = [],
14164
+ getRedirectLink,
14165
+ t
14166
+ }) {
14167
+ return widgets.map(widget => ({
14168
+ icon: widget.icon,
14169
+ title: widget.title,
14170
+ goToPath: getRedirectLink ? getRedirectLink(widget.path) : widget.path,
14171
+ disabled: widget.disabled || false
14172
+ }));
14173
+ }
14174
+
14175
+ /**
14176
+ * Build key indicators configuration
14177
+ *
14178
+ * @param {Object} params
14179
+ * @param {Object} params.keyIndicatorsData - Object with indicator keys and values
14180
+ * @param {Array} params.paths - Array of paths corresponding to each indicator
14181
+ * @param {Function} params.getRedirectLink - Function to transform paths
14182
+ *
14183
+ * @returns {Array} Configured key indicators
14184
+ *
14185
+ * @example
14186
+ * const indicators = buildKeyIndicatorsConfig({
14187
+ * keyIndicatorsData: { totalUsers: 100, totalAccounts: 50 },
14188
+ * paths: ["/users", "/accounts"],
14189
+ * getRedirectLink: (path) => `/app${path}`
14190
+ * });
14191
+ */
14192
+ function buildKeyIndicatorsConfig({
14193
+ keyIndicatorsData = {},
14194
+ paths = [],
14195
+ getRedirectLink
14196
+ }) {
14197
+ const keys = Object.keys(keyIndicatorsData);
14198
+ return keys.map((key, index) => ({
14199
+ title: formatToKebabCase(key),
14200
+ valueToShow: keyIndicatorsData[key],
14201
+ goToPath: getRedirectLink && paths[index] ? getRedirectLink(paths[index]) : paths[index] || "#"
14202
+ }));
14203
+ }
14204
+
14205
+ /**
14206
+ * Build breadcrumbs configuration
14207
+ *
14208
+ * @param {Object} params
14209
+ * @param {string} params.view - View type (e.g., "accounts", "users")
14210
+ * @param {Function} params.t - Translation function
14211
+ * @param {Function} params.goTo - Navigation function
14212
+ * @param {boolean} params.isView - Is in view mode
14213
+ * @param {boolean} params.isEdit - Is in edit mode
14214
+ * @param {string} params.id - Entity ID
14215
+ * @param {string} params.mode - Current mode
14216
+ * @param {string} params.group - Current group/section
14217
+ * @param {string} params.basePath - Base path for the view
14218
+ *
14219
+ * @returns {Array} Breadcrumb configuration
14220
+ */
14221
+ function buildBreadcrumbs({
14222
+ view,
14223
+ t,
14224
+ goTo,
14225
+ isView,
14226
+ isEdit,
14227
+ id,
14228
+ mode,
14229
+ group,
14230
+ basePath = "/app"
14231
+ }) {
14232
+ return [{
14233
+ label: t("Admin"),
14234
+ path: basePath
14235
+ }, {
14236
+ label: t(view.charAt(0).toUpperCase() + view.slice(1)),
14237
+ path: `${basePath}/${view}`
14238
+ }, {
14239
+ label: isView ? t("View") : t("Edit"),
14240
+ path: `${basePath}/${view}/${mode}/${id}/${group}`
14241
+ }];
14242
+ }
14243
+
14126
14244
  exports.ErrorFormat = ErrorFormat;
14127
14245
  exports.MessageTypes = MessageTypes;
14128
14246
  exports.StorageManager = StorageManager;
14129
14247
  exports.assignParamsToUrl = assignParamsToUrl;
14130
14248
  exports.btn = button;
14249
+ exports.buildActionWidgetsConfig = buildActionWidgetsConfig;
14250
+ exports.buildBreadcrumbs = buildBreadcrumbs;
14251
+ exports.buildKeyIndicatorsConfig = buildKeyIndicatorsConfig;
14131
14252
  exports.buildQueryString = buildQueryString;
14132
14253
  exports.camelCaseToTitle = camelCaseToTitle;
14133
14254
  exports.capitalize = capitalize;
@@ -14155,6 +14276,7 @@ exports.filterSelectOptions = filterSelectOptions;
14155
14276
  exports.filterString = filterString;
14156
14277
  exports.findOptions = findOptions;
14157
14278
  exports.formatErrors = formatErrors;
14279
+ exports.formatToKebabCase = formatToKebabCase$1;
14158
14280
  exports.getDefaultActiveFilters = getDefaultActiveFilters;
14159
14281
  exports.getDivergenceOrEqual = getDivergenceOrEqual;
14160
14282
  exports.getImageUploadViewValue = getImageUploadViewValue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.712",
3
+ "version": "0.6.713",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -0,0 +1,15 @@
1
+ const config = {
2
+ viewBox: "0 0 105 105",
3
+ children: (
4
+ <>
5
+ <svg width="105" height="105" viewBox="0 0 105 105" fill="none" xmlns="http://www.w3.org/2000/svg">
6
+ <path d="M26.25 26.25L45.9375 45.9375L26.25 26.25Z" fill="white"/>
7
+ <path d="M13.125 8.75L26.25 13.125V26.25H13.125L8.75 13.125L13.125 8.75Z" fill="white"/>
8
+ <path d="M84.2581 11.9919L72.7622 23.4878C71.0297 25.2203 70.1634 26.0866 69.8388 27.0856C69.5533 27.9642 69.5533 28.9108 69.8388 29.7894C70.1634 30.7884 71.0297 31.6547 72.7622 33.3872L73.8003 34.4253C75.5328 36.1578 76.3991 37.0241 77.398 37.3487C78.2767 37.6342 79.2233 37.6342 80.102 37.3487C81.1009 37.0241 81.9672 36.1578 83.6997 34.4253L94.4531 23.6719C95.6113 26.4901 96.25 29.5767 96.25 32.8125C96.25 46.1019 85.4768 56.875 72.1875 56.875C70.5853 56.875 69.0197 56.7184 67.5052 56.4197C65.3783 56.0003 64.3149 55.7905 63.6702 55.8548C62.9848 55.923 62.647 56.0258 62.0397 56.3508C61.4685 56.6565 60.8955 57.2295 59.7495 58.3755L28.4375 89.6874C24.8131 93.3118 18.9369 93.3118 15.3125 89.6874C11.6881 86.0631 11.6881 80.1868 15.3125 76.5624L46.6245 45.2505C47.7705 44.1045 48.3435 43.5315 48.6492 42.9603C48.9742 42.353 49.077 42.0152 49.1452 41.3298C49.2095 40.6851 48.9997 39.6217 48.5803 37.4948C48.2816 35.9803 48.125 34.4147 48.125 32.8125C48.125 19.5231 58.8981 8.75 72.1875 8.75C76.5866 8.75 80.7099 9.93048 84.2581 11.9919Z" fill="white"/>
9
+ <path d="M52.5002 65.6248L76.5625 89.687C80.1868 93.3114 86.0631 93.3114 89.6874 89.687C93.3118 86.0627 93.3118 80.1864 89.6874 76.562L69.892 56.7669C68.4907 56.6343 67.1243 56.3815 65.8034 56.019C64.1013 55.5518 62.2341 55.8909 60.986 57.139L52.5002 65.6248Z" fill="white"/>
10
+ <path d="M26.25 26.25L45.9375 45.9375M26.25 26.25H13.125L8.75 13.125L13.125 8.75L26.25 13.125V26.25ZM84.2581 11.9919L72.7622 23.4878C71.0297 25.2203 70.1634 26.0866 69.8388 27.0855C69.5533 27.9642 69.5533 28.9108 69.8388 29.7895C70.1634 30.7884 71.0297 31.6547 72.7622 33.3872L73.8003 34.4253C75.5328 36.1578 76.3991 37.0241 77.398 37.3487C78.2767 37.6342 79.2233 37.6342 80.102 37.3487C81.1009 37.0241 81.9672 36.1578 83.6997 34.4253L94.4531 23.6719C95.6113 26.4901 96.25 29.5767 96.25 32.8125C96.25 46.1019 85.4768 56.875 72.1875 56.875C70.5853 56.875 69.0197 56.7184 67.5052 56.4197C65.3783 56.0003 64.3149 55.7905 63.6702 55.8548C62.9848 55.9231 62.647 56.0258 62.0397 56.3508C61.4685 56.6565 60.8955 57.2295 59.7495 58.3755L28.4375 89.6874C24.8131 93.3118 18.9369 93.3118 15.3125 89.6874C11.6881 86.0631 11.6881 80.1868 15.3125 76.5624L46.6245 45.2505C47.7705 44.1045 48.3435 43.5315 48.6492 42.9603C48.9742 42.353 49.0769 42.0152 49.1452 41.3298C49.2095 40.6851 48.9997 39.6217 48.5803 37.4948C48.2816 35.9803 48.125 34.4147 48.125 32.8125C48.125 19.5231 58.8981 8.75 72.1875 8.75C76.5866 8.75 80.7099 9.93048 84.2581 11.9919ZM52.5002 65.6248L76.5625 89.687C80.1868 93.3114 86.0631 93.3114 89.6874 89.687C93.3118 86.0627 93.3118 80.1864 89.6874 76.562L69.892 56.7669C68.4907 56.6343 67.1243 56.3815 65.8034 56.019C64.1013 55.5518 62.2341 55.8909 60.986 57.139L52.5002 65.6248Z" stroke="#AD8A47" stroke-width="3.6" stroke-linecap="round" stroke-linejoin="round"/>
11
+ </svg>
12
+
13
+ </>
14
+ )
15
+ }
@@ -8,7 +8,7 @@ import AdminAccountsViewScreen from "./AdminScreens/AccountsView.jsx";
8
8
  * Generate Admin Routes for any application
9
9
  *
10
10
  * This function returns a complete set of admin routes that can be used directly
11
- * in your application's route configuration. Just provide the configuration and
11
+ * in application's route configuration. Just provide the configuration and
12
12
  * you get back ready-to-use routes.
13
13
  *
14
14
  * @param {Object} config - Application-specific configuration
@@ -0,0 +1,84 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+
3
+ /**
4
+ * Generic hook for fetching admin dashboard data
5
+ *
6
+ * @param {Object} config - Configuration object
7
+ * @param {Object} config.dashboardService - Service object with getDashboardData method
8
+ * @param {Function} config.onError - Error handler function
9
+ *
10
+ * @returns {Object} Dashboard data and loading states
11
+ *
12
+ * @example
13
+ * const { data, loading, userGrowthData, fetchUserGrowth } = useAdminDashboard({
14
+ * dashboardService: {
15
+ * getDashboardData: () => DashboardService.getAdminStats(),
16
+ * getUserGrowth: (params) => DashboardService.getUserGrowth(params)
17
+ * },
18
+ * onError: (err) => console.error(err)
19
+ * });
20
+ */
21
+ export function useAdminDashboard({ dashboardService, onError }) {
22
+ const [data, setData] = useState({});
23
+ const [loading, setLoading] = useState(false);
24
+ const [userGrowthData, setUserGrowthData] = useState([]);
25
+ const [userGrowthDataLoading, setUserGrowthDataLoading] = useState(false);
26
+
27
+ const fetchDashboardData = useCallback(async () => {
28
+ if (!dashboardService?.getDashboardData) {
29
+ console.warn("dashboardService.getDashboardData not provided");
30
+ return;
31
+ }
32
+
33
+ setLoading(true);
34
+ try {
35
+ const response = await dashboardService.getDashboardData();
36
+ setData(response || {});
37
+ } catch (err) {
38
+ if (onError) {
39
+ onError(err);
40
+ } else {
41
+ console.error("Error fetching dashboard data:", err);
42
+ }
43
+ } finally {
44
+ setLoading(false);
45
+ }
46
+ }, [dashboardService, onError]);
47
+
48
+ const fetchUserGrowth = useCallback(
49
+ async (params) => {
50
+ if (!dashboardService?.getUserGrowth) {
51
+ console.warn("dashboardService.getUserGrowth not provided");
52
+ return;
53
+ }
54
+
55
+ setUserGrowthDataLoading(true);
56
+ try {
57
+ const response = await dashboardService.getUserGrowth(params);
58
+ setUserGrowthData(response || []);
59
+ } catch (err) {
60
+ if (onError) {
61
+ onError(err);
62
+ } else {
63
+ console.error("Error fetching user growth:", err);
64
+ }
65
+ } finally {
66
+ setUserGrowthDataLoading(false);
67
+ }
68
+ },
69
+ [dashboardService, onError]
70
+ );
71
+
72
+ useEffect(() => {
73
+ fetchDashboardData();
74
+ }, [fetchDashboardData]);
75
+
76
+ return {
77
+ data,
78
+ loading,
79
+ userGrowthData,
80
+ fetchUserGrowth,
81
+ userGrowthDataLoading,
82
+ };
83
+ }
84
+
@@ -9,6 +9,21 @@ class DashboardService extends BaseService {
9
9
  isApp: true,
10
10
  });
11
11
  }
12
+
13
+ getUserGrowth(activeFilter) {
14
+ return this.apiGet({
15
+ url: `/accounts/dashboard/user-growth`,
16
+ isUserManager: true,
17
+ params: { activeFilter },
18
+ });
19
+ }
20
+
21
+ getAdminDashboard() {
22
+ return this.apiGet({
23
+ url: `/accounts/dashboard`,
24
+ isUserManager: true,
25
+ });
26
+ }
12
27
  }
13
28
 
14
29
  export default createLazyService(DashboardService);
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Utility functions for building admin dashboard configurations
3
+ * These functions transform simple data arrays into full configuration objects
4
+ */
5
+
6
+ /**
7
+ * Format string to kebab-case
8
+ * @param {string} str - String to format
9
+ * @returns {string} Kebab-cased string
10
+ */
11
+ export function formatToKebabCase(str) {
12
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
13
+ }
14
+
15
+ /**
16
+ * Build action widgets configuration
17
+ *
18
+ * @param {Object} params
19
+ * @param {Array} params.widgets - Array of widget definitions
20
+ * @param {Function} params.getRedirectLink - Function to transform paths
21
+ * @param {Function} params.t - Translation function
22
+ *
23
+ * @returns {Array} Configured action widgets
24
+ *
25
+ * @example
26
+ * const widgets = buildActionWidgetsConfig({
27
+ * widgets: [
28
+ * { icon: "Search", title: "review-requests", path: "/accounts?pending=true" }
29
+ * ],
30
+ * getRedirectLink: (path) => `/app${path}`,
31
+ * t: (key) => translations[key]
32
+ * });
33
+ */
34
+ export function buildActionWidgetsConfig({ widgets = [], getRedirectLink, t }) {
35
+ return widgets.map((widget) => ({
36
+ icon: widget.icon,
37
+ title: widget.title,
38
+ goToPath: getRedirectLink ? getRedirectLink(widget.path) : widget.path,
39
+ disabled: widget.disabled || false,
40
+ }));
41
+ }
42
+
43
+ /**
44
+ * Build key indicators configuration
45
+ *
46
+ * @param {Object} params
47
+ * @param {Object} params.keyIndicatorsData - Object with indicator keys and values
48
+ * @param {Array} params.paths - Array of paths corresponding to each indicator
49
+ * @param {Function} params.getRedirectLink - Function to transform paths
50
+ *
51
+ * @returns {Array} Configured key indicators
52
+ *
53
+ * @example
54
+ * const indicators = buildKeyIndicatorsConfig({
55
+ * keyIndicatorsData: { totalUsers: 100, totalAccounts: 50 },
56
+ * paths: ["/users", "/accounts"],
57
+ * getRedirectLink: (path) => `/app${path}`
58
+ * });
59
+ */
60
+ export function buildKeyIndicatorsConfig({ keyIndicatorsData = {}, paths = [], getRedirectLink }) {
61
+ const keys = Object.keys(keyIndicatorsData);
62
+
63
+ return keys.map((key, index) => ({
64
+ title: formatToKebabCase(key),
65
+ valueToShow: keyIndicatorsData[key],
66
+ goToPath: getRedirectLink && paths[index] ? getRedirectLink(paths[index]) : paths[index] || "#",
67
+ }));
68
+ }
69
+
70
+ /**
71
+ * Build breadcrumbs configuration
72
+ *
73
+ * @param {Object} params
74
+ * @param {string} params.view - View type (e.g., "accounts", "users")
75
+ * @param {Function} params.t - Translation function
76
+ * @param {Function} params.goTo - Navigation function
77
+ * @param {boolean} params.isView - Is in view mode
78
+ * @param {boolean} params.isEdit - Is in edit mode
79
+ * @param {string} params.id - Entity ID
80
+ * @param {string} params.mode - Current mode
81
+ * @param {string} params.group - Current group/section
82
+ * @param {string} params.basePath - Base path for the view
83
+ *
84
+ * @returns {Array} Breadcrumb configuration
85
+ */
86
+ export function buildBreadcrumbs({ view, t, goTo, isView, isEdit, id, mode, group, basePath = "/app" }) {
87
+ return [
88
+ {
89
+ label: t("Admin"),
90
+ path: basePath,
91
+ },
92
+ {
93
+ label: t(view.charAt(0).toUpperCase() + view.slice(1)),
94
+ path: `${basePath}/${view}`,
95
+ },
96
+ {
97
+ label: isView ? t("View") : t("Edit"),
98
+ path: `${basePath}/${view}/${mode}/${id}/${group}`,
99
+ },
100
+ ];
101
+ }
102
+
@@ -184,4 +184,10 @@ export const cleanJSON = (json) => {
184
184
  */
185
185
  }
186
186
  return json;
187
+ }
188
+
189
+ export function formatToKebabCase(str) {
190
+ return str
191
+ .replace(/([a-z])([A-Z])/g, "$1-$2")
192
+ .toLowerCase();
187
193
  }
package/src/hooks.js CHANGED
@@ -11,4 +11,5 @@ export { useMapOnExpandableWidget } from "./@daf/hooks/useMapOnExpandableWidget"
11
11
  export { checkPermission, checkPermissionList, usePermissions } from "./@daf/hooks/usePermissions";
12
12
  export { useFirebase } from "./@daf/hooks/useFirebase.js"
13
13
  export { useIsDatastake } from "./@daf/hooks/useIsDatastake.js"
14
- export { useWidgetFetch } from "./@daf/hooks/useWidgetFetch.js"
14
+ export { useWidgetFetch } from "./@daf/hooks/useWidgetFetch.js"
15
+ export { useAdminDashboard } from "./@daf/hooks/useAdminDashboard.js"
@@ -1542,13 +1542,13 @@ ul.ant-menu.ant-menu-dark.ant-menu-root.ant-menu-vertical::-webkit-scrollbar-thu
1542
1542
  }
1543
1543
 
1544
1544
  .components-layout:not(.nested) .sidenav-sider:not(.custom) .sidenav-cont .menus-cont.not-collapsed .sidemenu-cont .ant-menu.ant-menu-root.ant-menu-inline.ant-menu-dark
1545
- .ant-menu-item:not(.ant-menu-item-selected) svg path
1545
+ .ant-menu-item:not(.ant-menu-item-selected):not(.ant-menu-item-disabled) svg path
1546
1546
  {
1547
1547
  stroke: #ffffff !important;
1548
1548
  }
1549
1549
 
1550
1550
  .components-layout:not(.nested) .sidenav-sider:not(.custom) .sidenav-cont .menus-cont.not-collapsed .sidemenu-cont .ant-menu.ant-menu-root.ant-menu-inline.ant-menu-dark
1551
- .ant-menu-item:not(.ant-menu-item-selected) .ant-menu-title-content {
1551
+ .ant-menu-item:not(.ant-menu-item-selected):not(.ant-menu-item-disabled) .ant-menu-title-content {
1552
1552
  color: #ffffff !important;
1553
1553
  }
1554
1554
 
package/src/utils.js CHANGED
@@ -9,7 +9,7 @@ export { renderTooltip, renderTooltipJsx } from './@daf/utils/tooltip'
9
9
  export { getRangeOfTicks } from './helpers/chart'
10
10
 
11
11
  export { propHasValue } from './helpers/deepFind'
12
- export { isEmptyOrSpaces, capitalizeAll, capitalize, camelCaseToTitle, snakeCaseToTitleCase, titleToCamelCase, findOptions, getOptionAsObject, nowToIso, renderTemplateString, renderTemplateStringInObject, truncateString, splitStringInMultipleLines, safeJsonParse, cleanJSON } from './helpers/StringHelper.js'
12
+ export { isEmptyOrSpaces, capitalizeAll, capitalize, camelCaseToTitle, snakeCaseToTitleCase, titleToCamelCase, findOptions, getOptionAsObject, nowToIso, renderTemplateString, renderTemplateStringInObject, truncateString, splitStringInMultipleLines, safeJsonParse, cleanJSON, formatToKebabCase } from './helpers/StringHelper.js'
13
13
  export { getNkey, groupSubsections, getImageUploadViewValue } from './@daf/core/components/ViewForm/helper'
14
14
  export { renderRows } from './@daf/core/components/Table/helper'
15
15
  export { filterOptions, filterString, hasNotChanged, filterSelectOptions, mapSubGroupsInSubmit, mapSubGroupsInGet, filterCreateData, changeInputMeta, renderDateFormatted } from './helpers/Forms'
@@ -52,4 +52,10 @@ export { createTheme, createAdminTheme } from './helpers/theme.js';
52
52
 
53
53
  export { getRedirectLink } from "./@daf/hooks/useIsDatastake.js"
54
54
 
55
- export { getSourceString, getDivergenceOrEqual } from './helpers/stringHelper.jsx'
55
+ export { getSourceString, getDivergenceOrEqual } from './helpers/stringHelper.jsx'
56
+
57
+ export {
58
+ buildActionWidgetsConfig,
59
+ buildKeyIndicatorsConfig,
60
+ buildBreadcrumbs
61
+ } from './@daf/utils/adminConfigBuilders.js'
@@ -1,216 +0,0 @@
1
- # Admin Screens - Reusable Admin Panel Components
2
-
3
- This module provides ready-to-use admin panel screens that can be easily configured for any application.
4
-
5
- ## 🎯 Purpose
6
-
7
- The admin panel is mostly static across applications - it only needs configuration changes (app name, services, etc.). These components allow you to:
8
-
9
- 1. **Export admin routes from DAF** instead of duplicating code per application
10
- 2. **Configure via props** instead of rewriting components
11
- 3. **Maintain consistency** across all applications using DAF
12
-
13
- ## 📦 Available Components
14
-
15
- ### 1. `AdminDashboardScreen`
16
- The main admin dashboard with key indicators, action widgets, and statistics.
17
-
18
- **Configuration:**
19
- ```javascript
20
- {
21
- appName: "wazi", // App name for translations
22
- goTo: useNavigate(), // Navigation function
23
- t: useTranslation(), // Translation function
24
- getRedirectLink: (path) => path, // Redirect link generator
25
- getActionWidgetsConfig: (opts) => [], // Action widgets config
26
- getKeyIndicatorsConfig: (opts) => [], // Key indicators config
27
- useWidgetFetch: () => {} // Hook to fetch dashboard data
28
- }
29
- ```
30
-
31
- ### 2. `AdminUsersScreen`
32
- User management table with impersonation, password reset, etc.
33
-
34
- **Configuration:**
35
- ```javascript
36
- {
37
- appName: "wazi",
38
- module: APP, // App identifier
39
- goTo: useNavigate(),
40
- t: useTranslation(),
41
- location: useLocation(),
42
- isMobile: false,
43
- userRoles: [], // User roles config
44
- accountTypes: [], // Account types config
45
- getRedirectLink: (path) => path,
46
- AdminService: {}, // Admin service methods
47
- AuthenticationService: {}, // Auth service methods
48
- handleError: (err) => {}, // Error handler
49
- getAppRedirect: ({token}) => "" // App redirect for impersonation
50
- }
51
- ```
52
-
53
- ### 3. `AdminAccountsScreen`
54
- Accounts management table with invitation management.
55
-
56
- **Configuration:**
57
- ```javascript
58
- {
59
- appName: "wazi",
60
- module: APP,
61
- goTo: useNavigate(),
62
- t: useTranslation(),
63
- location: useLocation(),
64
- isMobile: false,
65
- accountTypes: [],
66
- getRedirectLink: (path) => path,
67
- AdminService: {},
68
- options: { countries: [] }, // Options with countries, etc.
69
- useQuery: () => {}, // Query params hook
70
- NewAccountModal: Component // Optional custom modal
71
- }
72
- ```
73
-
74
- ### 4. `AdminAccountsViewScreen`
75
- View/Edit individual accounts with user management.
76
-
77
- **Configuration:**
78
- ```javascript
79
- {
80
- module: APP,
81
- goTo: useNavigate(),
82
- t: useTranslation(),
83
- location: useLocation(),
84
- getRedirectLink: (path) => path,
85
- renderBreadCrumbs: (opts) => [], // Breadcrumbs renderer
86
- id: "account-id", // From route params
87
- mode: "view|edit", // From route params
88
- group: "general", // From route params
89
- userRoles: [],
90
- options: { countries: [] },
91
- accountTypes: [],
92
- accountStatuses: [],
93
- getAccountData: (opts) => {}, // Fetch account data
94
- updateAccount: (opts) => {}, // Update account
95
- handleError: (err) => {},
96
- toggleAccountStatus: (opts) => {}, // Toggle account status
97
- transferAdmin: (opts) => {} // Transfer admin rights
98
- }
99
- ```
100
-
101
- ## 🚀 Usage in Applications
102
-
103
- ### Step 1: Create Configuration Hooks
104
-
105
- Create a file `privateRoutes/adminConfig.js` in your application:
106
-
107
- ```javascript
108
- import { useNavigate, useLocation, useParams } from "react-router-dom";
109
- import { useTranslation } from "react-i18next";
110
- // ... import your services and hooks
111
-
112
- export function useAdminDashboardConfig() {
113
- const goTo = useNavigate();
114
- const { t } = useTranslation();
115
- // ... gather all needed config
116
-
117
- return {
118
- appName: "your-app",
119
- goTo,
120
- t,
121
- // ... all other config
122
- };
123
- }
124
-
125
- // Create similar hooks for other screens
126
- ```
127
-
128
- ### Step 2: Create Wrapper Components
129
-
130
- In your `privateRoutes/index.js`:
131
-
132
- ```javascript
133
- import {
134
- AdminDashboardScreen,
135
- AdminUsersScreen,
136
- AdminAccountsScreen,
137
- AdminAccountsViewScreen,
138
- } from "datastake-daf/dist/components";
139
- import {
140
- useAdminDashboardConfig,
141
- useAdminUsersConfig,
142
- useAdminAccountsConfig,
143
- useAdminAccountsViewConfig,
144
- } from "./adminConfig";
145
-
146
- function DashboardWrapper() {
147
- const config = useAdminDashboardConfig();
148
- return <AdminDashboardScreen config={config} />;
149
- }
150
-
151
- // Create similar wrappers for other screens
152
- ```
153
-
154
- ### Step 3: Define Routes
155
-
156
- ```javascript
157
- const routes = [
158
- {
159
- path: "",
160
- key: "APP_YOUR_APP_DASHBOARD",
161
- component: <DashboardWrapper />,
162
- visible: () => true,
163
- },
164
- {
165
- path: "accounts",
166
- key: "APP_YOUR_APP_ACCOUNTS",
167
- component: <AccountsWrapper />,
168
- visible: (user) => userIsAdmin(user),
169
- },
170
- // ... more routes
171
- ];
172
- ```
173
-
174
- ## ✅ Benefits
175
-
176
- 1. **No Code Duplication**: Write admin logic once in DAF, use everywhere
177
- 2. **Easy Maintenance**: Fix bugs once, applies to all apps
178
- 3. **Consistent UX**: Same admin experience across all applications
179
- 4. **Configurable**: Each app can customize behavior via config
180
- 5. **Type Safe**: Well-documented configuration interfaces
181
-
182
- ## 🔄 Migration from Old Pattern
183
-
184
- **Before** (duplicated code per app):
185
- ```
186
- wazi-frontend/src/screens/Admin/
187
- ├── Dashboard/index.js ❌ Duplicated
188
- ├── Users/index.js ❌ Duplicated
189
- └── Accounts/index.js ❌ Duplicated
190
- ```
191
-
192
- **After** (configuration only):
193
- ```
194
- wazi-frontend/src/privateRoutes/
195
- ├── index.js ✅ Route definitions
196
- └── adminConfig.js ✅ Configuration hooks
197
- ```
198
-
199
- ## 📚 Example: Complete Setup
200
-
201
- See `/wazi-frontend/src/privateRoutes/` for a complete working example of how to configure and use these admin screens.
202
-
203
- ## 🔧 Customization
204
-
205
- If you need custom behavior:
206
-
207
- 1. **Small changes**: Use configuration options
208
- 2. **Moderate changes**: Create a custom wrapper component
209
- 3. **Large changes**: Extend the base admin components
210
-
211
- ## 📝 Notes
212
-
213
- - All screens expect React Router hooks (useNavigate, useLocation, useParams)
214
- - Translation keys follow the pattern: `{appName}::key` and `admin::key`
215
- - Services should follow the AdminService interface from DAF
216
-