@goplusvn/core 0.1.0 → 0.1.1
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/package.json +2 -1
- package/src/assets/erp_wallpaper.png +0 -0
- package/src/assets/goeat_logo.png +0 -0
- package/src/audit/audit-manager.ts +139 -0
- package/src/audit/index.ts +11 -0
- package/src/audit/memory-audit-logger.ts +86 -0
- package/src/audit/types.ts +50 -0
- package/src/auth/auth-service.ts +97 -0
- package/src/auth/index.ts +266 -0
- package/src/code-generation/index.ts +69 -0
- package/src/configs/auth-routes.ts +17 -0
- package/src/configs/crud.ts +136 -0
- package/src/configs/data/navigations.ts +781 -0
- package/src/configs/data/oauth-links.ts +10 -0
- package/src/configs/entities/material-categories.config.ts +125 -0
- package/src/configs/i18n.ts +12 -0
- package/src/configs/index.ts +26 -0
- package/src/configs/status.ts +25 -0
- package/src/configs/themes.ts +100 -0
- package/src/crud/components/crud-bulk-actions.tsx +91 -0
- package/src/crud/components/crud-card-view.tsx +241 -0
- package/src/crud/components/crud-context.tsx +122 -0
- package/src/crud/components/crud-delete-dialog.tsx +145 -0
- package/src/crud/components/crud-dialog.tsx +406 -0
- package/src/crud/components/crud-empty-state.tsx +104 -0
- package/src/crud/components/crud-export-button.tsx +170 -0
- package/src/crud/components/crud-field-renderer.tsx +653 -0
- package/src/crud/components/crud-filter-chips.tsx +102 -0
- package/src/crud/components/crud-filters/checkbox-filter.tsx +97 -0
- package/src/crud/components/crud-filters/datetime-filter.tsx +83 -0
- package/src/crud/components/crud-filters/filter-builder.tsx +66 -0
- package/src/crud/components/crud-filters/index.tsx +76 -0
- package/src/crud/components/crud-filters/radio-filter.tsx +86 -0
- package/src/crud/components/crud-filters/select-filter.tsx +141 -0
- package/src/crud/components/crud-filters/text-filter.tsx +86 -0
- package/src/crud/components/crud-form.tsx +642 -0
- package/src/crud/components/crud-import-dialog.tsx +440 -0
- package/src/crud/components/crud-infinite-scroll.tsx +116 -0
- package/src/crud/components/crud-page.tsx +1017 -0
- package/src/crud/components/crud-provider.tsx +277 -0
- package/src/crud/components/crud-row-actions.tsx +189 -0
- package/src/crud/components/crud-search.tsx +82 -0
- package/src/crud/components/crud-sheet.tsx +336 -0
- package/src/crud/components/crud-table-skeleton.tsx +26 -0
- package/src/crud/components/crud-table-toolbar.tsx +91 -0
- package/src/crud/components/crud-table.tsx +352 -0
- package/src/crud/components/crud-virtual-table.tsx +55 -0
- package/src/crud/components/index.tsx +20 -0
- package/src/crud/crud-filters/checkbox-filter.tsx +87 -0
- package/src/crud/crud-filters/datetime-filter.tsx +82 -0
- package/src/crud/crud-filters/filter-builder.tsx +64 -0
- package/src/crud/crud-filters/index.tsx +78 -0
- package/src/crud/crud-filters/radio-filter.tsx +79 -0
- package/src/crud/crud-filters/select-filter.tsx +148 -0
- package/src/crud/crud-filters/text-filter.tsx +81 -0
- package/src/crud/index.ts +43 -0
- package/src/crud/lib/crud-service.test.ts +334 -0
- package/src/crud/lib/crud-service.ts +358 -0
- package/src/crud/lib/crud-utils.test.ts +354 -0
- package/src/crud/lib/crud-utils.ts +299 -0
- package/src/crud/lib/crud-validator.ts +247 -0
- package/src/crud/lib/data-loader.ts +234 -0
- package/src/crud/lib/field-calculator.ts +241 -0
- package/src/crud/lib/field-formatter.ts +240 -0
- package/src/crud/lib/import-export-service.test.ts +290 -0
- package/src/crud/lib/import-export-service.ts +352 -0
- package/src/crud/lib/import-server-utils.ts +109 -0
- package/src/crud/lib/lazy-loader.ts +241 -0
- package/src/crud/lib/parse-filters.ts +85 -0
- package/src/crud/lib/permissions.ts +52 -0
- package/src/crud/lib/serialize-config.ts +60 -0
- package/src/crud/lib/stream-loader.ts +145 -0
- package/src/crud/lib/translate-config.ts +335 -0
- package/src/crud/lib/types.ts +11 -0
- package/src/crud/pages/entity-crud-page.tsx +144 -0
- package/src/crud/server.ts +8 -0
- package/src/home/constants.tsx +142 -0
- package/src/home/feature-showcase.tsx +171 -0
- package/src/home/home-page.tsx +191 -0
- package/src/home/hooks/index.ts +1 -0
- package/src/home/hooks/useWidgetPreferences.ts +167 -0
- package/src/home/index.ts +33 -0
- package/src/home/quick-access-dialog.tsx +271 -0
- package/src/home/quick-access-menu.tsx +267 -0
- package/src/home/types.ts +140 -0
- package/src/home/welcome-card.tsx +92 -0
- package/src/home/widget-container.tsx +258 -0
- package/src/home/widgets/base-widget.tsx +200 -0
- package/src/home/widgets/customers-widget.tsx +74 -0
- package/src/home/widgets/index.ts +6 -0
- package/src/home/widgets/orders-widget.tsx +87 -0
- package/src/home/widgets/revenue-widget.tsx +71 -0
- package/src/home/widgets/stock-widget.tsx +109 -0
- package/src/hooks/index.tsx +598 -0
- package/src/hooks/use-tenant.test.tsx +30 -0
- package/src/hooks/use-tenant.ts +5 -0
- package/src/index.ts +17 -0
- package/src/infrastructure/__tests__/architecture-verification.spec.ts +103 -0
- package/src/infrastructure/api-service.ts +317 -0
- package/src/infrastructure/cache/cache-manager.ts +107 -0
- package/src/infrastructure/cache/cache.ts +120 -0
- package/src/infrastructure/cache/index.ts +8 -0
- package/src/infrastructure/cache/types.ts +48 -0
- package/src/infrastructure/cron/cron-manager.ts +239 -0
- package/src/infrastructure/cron/index.ts +6 -0
- package/src/infrastructure/cron/types.ts +41 -0
- package/src/infrastructure/event-bus/event-bus.ts +145 -0
- package/src/infrastructure/event-bus/index.ts +2 -0
- package/src/infrastructure/event-bus/types.ts +22 -0
- package/src/infrastructure/index.ts +32 -0
- package/src/infrastructure/lock/decorators.ts +67 -0
- package/src/infrastructure/lock/index.ts +2 -0
- package/src/infrastructure/lock/lock-manager.ts +33 -0
- package/src/infrastructure/logger/index.ts +2 -0
- package/src/infrastructure/logger/logger.ts +96 -0
- package/src/infrastructure/logger/types.ts +25 -0
- package/src/layout/index.tsx +185 -0
- package/src/navigation/index.ts +91 -0
- package/src/notification/index.ts +14 -0
- package/src/notification/notification-service.ts +120 -0
- package/src/notification/storage/in-memory.ts +56 -0
- package/src/notification/storage/index.ts +1 -0
- package/src/notification/types.ts +51 -0
- package/src/organization/branch-service.ts +299 -0
- package/src/organization/branches.config.ts +154 -0
- package/src/organization/index.ts +5 -0
- package/src/plugin/apps-registry.ts +97 -0
- package/src/plugin/index.ts +5 -0
- package/src/plugin/types.ts +41 -0
- package/src/providers/index.tsx +109 -0
- package/src/providers/tenant-provider.tsx +45 -0
- package/src/rbac/components/roles/role-card.tsx +158 -0
- package/src/rbac/components/roles/role-stats-cards.tsx +29 -0
- package/src/rbac/components/roles/role-toolbar.tsx +123 -0
- package/src/rbac/hooks/use-role-operations.ts +159 -0
- package/src/rbac/hooks/use-roles-data.ts +59 -0
- package/src/rbac/index.ts +297 -0
- package/src/rbac/lib/permission-helpers.ts +63 -0
- package/src/rbac/pages/action-list-page.tsx +25 -0
- package/src/rbac/pages/resource-list-page.tsx +25 -0
- package/src/rbac/pages/role-list-page.tsx +378 -0
- package/src/rbac/permission-service.ts +140 -0
- package/src/rbac/permissions.ts +135 -0
- package/src/rbac/resource-service.ts +115 -0
- package/src/rbac/resource-validator.ts +119 -0
- package/src/rbac/role-service.ts +165 -0
- package/src/rbac/server.ts +16 -0
- package/src/rbac/types.ts +38 -0
- package/src/schemas/action.schema.ts +66 -0
- package/src/schemas/branch.schema.ts +52 -0
- package/src/schemas/coming-soon-schema.ts +9 -0
- package/src/schemas/company.schema.ts +44 -0
- package/src/schemas/forgot-passward-schema.ts +9 -0
- package/src/schemas/index.ts +30 -0
- package/src/schemas/material-category.schema.ts +43 -0
- package/src/schemas/material-pricing.schema.ts +74 -0
- package/src/schemas/material.schema.ts +76 -0
- package/src/schemas/materials.ts +52 -0
- package/src/schemas/new-passward-schema.ts +15 -0
- package/src/schemas/partner-company.schema.ts +149 -0
- package/src/schemas/register-schema.ts +36 -0
- package/src/schemas/resource.schema.ts +133 -0
- package/src/schemas/role.schema.ts +11 -0
- package/src/schemas/sign-in-schema.ts +24 -0
- package/src/schemas/supplier-pricing.schema.ts +15 -0
- package/src/schemas/supplier.schema.ts +120 -0
- package/src/schemas/system-category-group.schema.ts +67 -0
- package/src/schemas/system-category.schema.ts +77 -0
- package/src/schemas/system-config.schema.ts +118 -0
- package/src/schemas/uom.schema.ts +75 -0
- package/src/schemas/user-supplier.schema.ts +179 -0
- package/src/schemas/user.schema.ts +18 -0
- package/src/schemas/verify-email-schema.ts +9 -0
- package/src/schemas/warehouse.schema.ts +49 -0
- package/src/system/components/categories/category-list.tsx +529 -0
- package/src/system/components/categories/category-manager.tsx +89 -0
- package/src/system/components/categories/group-sidebar.tsx +308 -0
- package/src/system/components/settings/setting-dialogs.tsx +197 -0
- package/src/system/components/settings/setting-field.tsx +291 -0
- package/src/system/components/settings/setting-form-dialog.tsx +308 -0
- package/src/system/components/settings/settings-groups.ts +80 -0
- package/src/system/components/settings/settings-search.tsx +71 -0
- package/src/system/components/settings/settings-section.tsx +74 -0
- package/src/system/components/settings/settings-sidebar.tsx +81 -0
- package/src/system/constants.ts +3 -0
- package/src/system/index.ts +150 -0
- package/src/system/job-manager.ts +176 -0
- package/src/system/pages/components/categories/category-list.tsx +537 -0
- package/src/system/pages/components/categories/category-manager.tsx +90 -0
- package/src/system/pages/components/categories/group-sidebar.tsx +311 -0
- package/src/system/pages/components/settings/sales-rules-settings.tsx +222 -0
- package/src/system/pages/components/settings/setting-dialogs.tsx +197 -0
- package/src/system/pages/components/settings/setting-field.tsx +292 -0
- package/src/system/pages/components/settings/setting-form-dialog.tsx +308 -0
- package/src/system/pages/components/settings/settings-groups.ts +87 -0
- package/src/system/pages/components/settings/settings-page.tsx +372 -0
- package/src/system/pages/components/settings/settings-search.tsx +71 -0
- package/src/system/pages/components/settings/settings-section.tsx +74 -0
- package/src/system/pages/components/settings/settings-sidebar.tsx +81 -0
- package/src/system/pages/components/settings/system-settings.tsx +244 -0
- package/src/system/pages/system-category-page.tsx +15 -0
- package/src/system/pages/system-settings-page.tsx +380 -0
- package/src/system/schemas/system-category-group.schema.ts +46 -0
- package/src/system/schemas/system-category.schema.ts +56 -0
- package/src/system/services/settings-service.ts +127 -0
- package/src/system/services/system-category-service.ts +63 -0
- package/src/system/types.ts +45 -0
- package/src/types/index.ts +703 -0
- package/src/ui/auth/auth-layout.tsx +135 -0
- package/src/ui/auth/forgot-password-form.tsx +98 -0
- package/src/ui/auth/index.tsx +7 -0
- package/src/ui/auth/new-password-form.tsx +107 -0
- package/src/ui/auth/oauth-links.tsx +30 -0
- package/src/ui/auth/register-form.tsx +202 -0
- package/src/ui/auth/sign-in-form.tsx +238 -0
- package/src/ui/auth/verify-email-form.tsx +104 -0
- package/src/ui/crud/index.tsx +10 -0
- package/src/ui/data-display/accordion.tsx +65 -0
- package/src/ui/data-display/aspect-ratio.tsx +11 -0
- package/src/ui/data-display/avatar.tsx +163 -0
- package/src/ui/data-display/bento-grid.tsx +77 -0
- package/src/ui/data-display/carousel.tsx +249 -0
- package/src/ui/data-display/chart.tsx +363 -0
- package/src/ui/data-display/code-block-highlight.tsx +54 -0
- package/src/ui/data-display/collapsible.tsx +42 -0
- package/src/ui/data-display/compact-stat-bar.tsx +149 -0
- package/src/ui/data-display/data-table/data-table-context.tsx +255 -0
- package/src/ui/data-display/data-table/data-table-empty-state.tsx +133 -0
- package/src/ui/data-display/data-table/data-table-skeleton.tsx +145 -0
- package/src/ui/data-display/data-table/data-table-toolbar.tsx +353 -0
- package/src/ui/data-display/data-table/data-table.tsx +597 -0
- package/src/ui/data-display/data-table/index.ts +44 -0
- package/src/ui/data-display/data-table-column-header.tsx +75 -0
- package/src/ui/data-display/data-table-pagination.tsx +130 -0
- package/src/ui/data-display/data-table-view-options.tsx +59 -0
- package/src/ui/data-display/formatted-number-input.tsx +210 -0
- package/src/ui/data-display/highlight.tsx +20 -0
- package/src/ui/data-display/hover-card.tsx +48 -0
- package/src/ui/data-display/index.tsx +50 -0
- package/src/ui/data-display/iphone-15-pro.tsx +114 -0
- package/src/ui/data-display/kanban/index.ts +4 -0
- package/src/ui/data-display/kanban/kanban-board.tsx +192 -0
- package/src/ui/data-display/kanban/kanban-column.tsx +74 -0
- package/src/ui/data-display/kanban/kanban-item.tsx +50 -0
- package/src/ui/data-display/kanban/kanban-types.ts +21 -0
- package/src/ui/data-display/kpi-card.tsx +68 -0
- package/src/ui/data-display/media-grid.tsx +110 -0
- package/src/ui/data-display/safari.tsx +175 -0
- package/src/ui/data-display/show-more-text.tsx +55 -0
- package/src/ui/data-display/tabs.tsx +68 -0
- package/src/ui/data-display/timeline.tsx +256 -0
- package/src/ui/feedback/alert.tsx +60 -0
- package/src/ui/feedback/context-menu.tsx +245 -0
- package/src/ui/feedback/drawer.tsx +132 -0
- package/src/ui/feedback/error-dialog.tsx +273 -0
- package/src/ui/feedback/index.tsx +183 -0
- package/src/ui/feedback/progress.tsx +32 -0
- package/src/ui/feedback/sheet.tsx +148 -0
- package/src/ui/feedback/sonner.tsx +36 -0
- package/src/ui/forms/command.tsx +157 -0
- package/src/ui/forms/date-picker.tsx +73 -0
- package/src/ui/forms/date-range-picker.tsx +76 -0
- package/src/ui/forms/date-time-picker.tsx +109 -0
- package/src/ui/forms/editor/editor-menu-bar.tsx +394 -0
- package/src/ui/forms/editor/index.tsx +130 -0
- package/src/ui/forms/editor/multi-select-example.tsx +1234 -0
- package/src/ui/forms/emoji-picker.tsx +109 -0
- package/src/ui/forms/file-dropzone.tsx +169 -0
- package/src/ui/forms/file-thumbnail.tsx +29 -0
- package/src/ui/forms/index.tsx +201 -0
- package/src/ui/forms/input-file.tsx +99 -0
- package/src/ui/forms/input-group.tsx +46 -0
- package/src/ui/forms/input-otp.tsx +81 -0
- package/src/ui/forms/input-phone.tsx +172 -0
- package/src/ui/forms/input-spin.tsx +116 -0
- package/src/ui/forms/input-tags.tsx +219 -0
- package/src/ui/forms/input-time.tsx +42 -0
- package/src/ui/forms/multi-select.tsx +629 -0
- package/src/ui/forms/multiple-date-picker.tsx +74 -0
- package/src/ui/forms/radio-group.tsx +42 -0
- package/src/ui/forms/rating.tsx +158 -0
- package/src/ui/forms/time-picker.tsx +57 -0
- package/src/ui/index.tsx +17 -0
- package/src/ui/layout/animated-list.tsx +77 -0
- package/src/ui/layout/animated-sidebar.tsx +294 -0
- package/src/ui/layout/command-menu.tsx +355 -0
- package/src/ui/layout/customizer.tsx +324 -0
- package/src/ui/layout/footer.tsx +43 -0
- package/src/ui/layout/full-screen-toggle.tsx +52 -0
- package/src/ui/layout/header-breadcrumb.tsx +77 -0
- package/src/ui/layout/horizontal-layout-header.tsx +83 -0
- package/src/ui/layout/horizontal-layout.tsx +50 -0
- package/src/ui/layout/index.tsx +25 -0
- package/src/ui/layout/language-dropdown.tsx +103 -0
- package/src/ui/layout/logo.tsx +63 -0
- package/src/ui/layout/main-layout.tsx +57 -0
- package/src/ui/layout/mode-dropdown.tsx +58 -0
- package/src/ui/layout/notification-dropdown.tsx +127 -0
- package/src/ui/layout/page-tabs.tsx +306 -0
- package/src/ui/layout/route-cache.tsx +214 -0
- package/src/ui/layout/sidebar-group-icon-menu.tsx +195 -0
- package/src/ui/layout/sidebar.tsx +279 -0
- package/src/ui/layout/tab-content-cache.tsx +201 -0
- package/src/ui/layout/tab-navigation-provider.tsx +536 -0
- package/src/ui/layout/toggle-mobile-sidebar.tsx +33 -0
- package/src/ui/layout/top-bar-header-menubar.tsx +412 -0
- package/src/ui/layout/user-dropdown.tsx +188 -0
- package/src/ui/layout/vertical-layout-header.tsx +65 -0
- package/src/ui/layout/vertical-layout.tsx +47 -0
- package/src/ui/management/audit-log-page.tsx +209 -0
- package/src/ui/management/cache-management.tsx +349 -0
- package/src/ui/management/index.ts +3 -0
- package/src/ui/management/job-management.tsx +308 -0
- package/src/ui/pages/not-found.tsx +30 -0
- package/src/ui/primitives/badge.tsx +66 -0
- package/src/ui/primitives/breadcrumb.tsx +103 -0
- package/src/ui/primitives/button.tsx +129 -0
- package/src/ui/primitives/calendar.tsx +74 -0
- package/src/ui/primitives/card.tsx +86 -0
- package/src/ui/primitives/checkbox.tsx +31 -0
- package/src/ui/primitives/client.ts +30 -0
- package/src/ui/primitives/combobox.tsx +290 -0
- package/src/ui/primitives/dialog.tsx +121 -0
- package/src/ui/primitives/dropdown-menu.tsx +239 -0
- package/src/ui/primitives/dynamic-icon.tsx +24 -0
- package/src/ui/primitives/index.tsx +134 -0
- package/src/ui/primitives/input-number.tsx +131 -0
- package/src/ui/primitives/input.tsx +22 -0
- package/src/ui/primitives/keyboard.tsx +23 -0
- package/src/ui/primitives/label.tsx +24 -0
- package/src/ui/primitives/menubar.tsx +262 -0
- package/src/ui/primitives/navigation-menu.tsx +157 -0
- package/src/ui/primitives/pagination.tsx +118 -0
- package/src/ui/primitives/popover.tsx +56 -0
- package/src/ui/primitives/prefetch-link.tsx +60 -0
- package/src/ui/primitives/resizable.tsx +59 -0
- package/src/ui/primitives/scroll-area.tsx +63 -0
- package/src/ui/primitives/select.tsx +172 -0
- package/src/ui/primitives/separator.tsx +51 -0
- package/src/ui/primitives/sidebar.tsx +844 -0
- package/src/ui/primitives/slider.tsx +27 -0
- package/src/ui/primitives/status-badge.tsx +47 -0
- package/src/ui/primitives/sticky-layout.tsx +50 -0
- package/src/ui/primitives/switch.tsx +29 -0
- package/src/ui/primitives/table.tsx +116 -0
- package/src/ui/primitives/tabs.tsx +55 -0
- package/src/ui/primitives/toggle-group.tsx +70 -0
- package/src/ui/primitives/toggle.tsx +47 -0
- package/src/ui/primitives/tooltip.tsx +59 -0
- package/src/user/components/dangerous-zone.tsx +34 -0
- package/src/user/components/delete-account-form.tsx +40 -0
- package/src/user/components/index.ts +4 -0
- package/src/user/components/profile-info-form.tsx +390 -0
- package/src/user/components/profile-info.tsx +32 -0
- package/src/user/components/unified-profile-dialog.tsx +1019 -0
- package/src/user/components/user-stats.tsx +27 -0
- package/src/user/components/user-toolbar.tsx +137 -0
- package/src/user/components/users-card-view.tsx +253 -0
- package/src/user/index.ts +11 -0
- package/src/user/pages/user-list-page.tsx +234 -0
- package/src/user/pages/users-client-page.tsx +385 -0
- package/src/user/profile-page.tsx +19 -0
- package/src/user/schemas.ts +68 -0
- package/src/user/types.ts +34 -0
- package/src/user/user-service.ts +538 -0
- package/src/utils/index.ts +906 -0
- package/src/workflow/activity-timeline.tsx +412 -0
- package/src/workflow/approval-workflow.tsx +31 -0
- package/src/workflow/index.ts +2 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRUD Translation Utilities
|
|
3
|
+
* Translate EntityConfig ở server-side trước khi pass xuống client
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { DictionaryType } from "../../hooks";
|
|
7
|
+
import type { EntityConfig, FieldConfig, FilterConfig } from "../../types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get nested value from object bằng dot notation
|
|
11
|
+
*/
|
|
12
|
+
function getNestedValue(obj: Record<string, unknown>, path: string): unknown {
|
|
13
|
+
return path.split(".").reduce((current, key) => {
|
|
14
|
+
return current && typeof current === "object" && key in current
|
|
15
|
+
? (current as Record<string, unknown>)[key]
|
|
16
|
+
: undefined;
|
|
17
|
+
}, obj as unknown);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Translate a string với fallback
|
|
22
|
+
*/
|
|
23
|
+
function translate(
|
|
24
|
+
key: string,
|
|
25
|
+
dictionary: Record<string, unknown>,
|
|
26
|
+
fallback: string,
|
|
27
|
+
): string {
|
|
28
|
+
const value = getNestedValue(dictionary, key);
|
|
29
|
+
return typeof value === "string" ? value : fallback;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Translate EntityConfig với dictionary
|
|
34
|
+
* Chạy ở server-side trước khi pass xuống client
|
|
35
|
+
*/
|
|
36
|
+
export function translateEntityConfig(
|
|
37
|
+
config: EntityConfig,
|
|
38
|
+
dictionary: DictionaryType,
|
|
39
|
+
locale: string,
|
|
40
|
+
entityName?: string,
|
|
41
|
+
): EntityConfig {
|
|
42
|
+
const crudDict = (dictionary as Record<string, unknown>).crud as
|
|
43
|
+
| Record<string, unknown>
|
|
44
|
+
| undefined;
|
|
45
|
+
// Use entityName from URL (e.g., "materials") instead of config.name (e.g., "material")
|
|
46
|
+
// This ensures we match the dictionary key correctly
|
|
47
|
+
const dictKey = entityName || config.name;
|
|
48
|
+
const entitiesDict = (crudDict?.entities as Record<string, unknown>) || {};
|
|
49
|
+
const entityDict = entitiesDict[dictKey] as
|
|
50
|
+
| Record<string, unknown>
|
|
51
|
+
| undefined;
|
|
52
|
+
const commonDict = (crudDict?.common as Record<string, unknown>) || {};
|
|
53
|
+
|
|
54
|
+
// Translate entity-level labels
|
|
55
|
+
const translatedConfig: EntityConfig = {
|
|
56
|
+
...config,
|
|
57
|
+
label:
|
|
58
|
+
(entityDict?.label as string) ||
|
|
59
|
+
translate(`crud.entities.${dictKey}.label`, dictionary, config.label),
|
|
60
|
+
pluralLabel:
|
|
61
|
+
(entityDict?.pluralLabel as string) ||
|
|
62
|
+
translate(
|
|
63
|
+
`crud.entities.${dictKey}.pluralLabel`,
|
|
64
|
+
dictionary,
|
|
65
|
+
config.pluralLabel,
|
|
66
|
+
),
|
|
67
|
+
description:
|
|
68
|
+
(entityDict?.description as string) ||
|
|
69
|
+
translate(
|
|
70
|
+
`crud.entities.${dictKey}.description`,
|
|
71
|
+
dictionary,
|
|
72
|
+
config.description || "",
|
|
73
|
+
),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Translate fields
|
|
77
|
+
translatedConfig.fields = config.fields.map((field) => {
|
|
78
|
+
const fieldDict = (entityDict?.fields as Record<string, unknown>)?.[
|
|
79
|
+
field.name
|
|
80
|
+
] as Record<string, unknown> | undefined;
|
|
81
|
+
|
|
82
|
+
const translatedField: FieldConfig = {
|
|
83
|
+
...field,
|
|
84
|
+
label:
|
|
85
|
+
(fieldDict?.label as string) ||
|
|
86
|
+
translate(
|
|
87
|
+
`crud.entities.${dictKey}.fields.${field.name}.label`,
|
|
88
|
+
dictionary,
|
|
89
|
+
field.label,
|
|
90
|
+
),
|
|
91
|
+
placeholder:
|
|
92
|
+
(fieldDict?.placeholder as string) ||
|
|
93
|
+
translate(
|
|
94
|
+
`crud.entities.${dictKey}.fields.${field.name}.placeholder`,
|
|
95
|
+
dictionary,
|
|
96
|
+
field.placeholder || "",
|
|
97
|
+
),
|
|
98
|
+
helpText:
|
|
99
|
+
(fieldDict?.helpText as string) ||
|
|
100
|
+
translate(
|
|
101
|
+
`crud.entities.${dictKey}.fields.${field.name}.helpText`,
|
|
102
|
+
dictionary,
|
|
103
|
+
field.helpText || "",
|
|
104
|
+
),
|
|
105
|
+
description:
|
|
106
|
+
(fieldDict?.description as string) ||
|
|
107
|
+
translate(
|
|
108
|
+
`crud.entities.${dictKey}.fields.${field.name}.description`,
|
|
109
|
+
dictionary,
|
|
110
|
+
field.description || "",
|
|
111
|
+
),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Translate options if they exist
|
|
115
|
+
if (field.options && field.options.length > 0) {
|
|
116
|
+
const optionsDict = (fieldDict?.options as Record<string, string>) || {};
|
|
117
|
+
// Fallback to common options
|
|
118
|
+
const commonOptionsDict =
|
|
119
|
+
(commonDict?.options as Record<string, string>) || {};
|
|
120
|
+
|
|
121
|
+
translatedField.options = field.options.map((opt) => {
|
|
122
|
+
const isObject = typeof opt === "object" && opt !== null;
|
|
123
|
+
const optValue = isObject ? opt.value : opt;
|
|
124
|
+
const optLabel = isObject ? opt.label : String(opt);
|
|
125
|
+
const valueStr = String(optValue);
|
|
126
|
+
|
|
127
|
+
if (!isObject) {
|
|
128
|
+
return (
|
|
129
|
+
optionsDict[valueStr] ||
|
|
130
|
+
commonOptionsDict[valueStr] ||
|
|
131
|
+
translate(
|
|
132
|
+
`crud.entities.${dictKey}.fields.${field.name}.options.${valueStr}`,
|
|
133
|
+
dictionary,
|
|
134
|
+
optLabel,
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
...opt,
|
|
141
|
+
label:
|
|
142
|
+
optionsDict[valueStr] ||
|
|
143
|
+
commonOptionsDict[valueStr] ||
|
|
144
|
+
translate(
|
|
145
|
+
`crud.entities.${dictKey}.fields.${field.name}.options.${valueStr}`,
|
|
146
|
+
dictionary,
|
|
147
|
+
optLabel.startsWith("crud.")
|
|
148
|
+
? translate(optLabel, dictionary, optLabel)
|
|
149
|
+
: optLabel,
|
|
150
|
+
),
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return translatedField;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Translate filters
|
|
159
|
+
if (config.filters && config.filters.length > 0) {
|
|
160
|
+
translatedConfig.filters = config.filters.map((filter) => {
|
|
161
|
+
const filterDict = (entityDict?.filters as Record<string, unknown>)?.[
|
|
162
|
+
filter.name
|
|
163
|
+
] as Record<string, unknown> | undefined;
|
|
164
|
+
|
|
165
|
+
const translatedFilter: FilterConfig = {
|
|
166
|
+
...filter,
|
|
167
|
+
label:
|
|
168
|
+
(filterDict?.label as string) ||
|
|
169
|
+
translate(
|
|
170
|
+
`crud.entities.${dictKey}.filters.${filter.name}.label`,
|
|
171
|
+
dictionary,
|
|
172
|
+
filter.label,
|
|
173
|
+
),
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// Translate filter options
|
|
177
|
+
if (filter.options && filter.options.length > 0) {
|
|
178
|
+
const optionsDict =
|
|
179
|
+
(filterDict?.options as Record<string, string>) || {};
|
|
180
|
+
translatedFilter.options = filter.options.map((opt) => {
|
|
181
|
+
const isObject = typeof opt === "object" && opt !== null;
|
|
182
|
+
const optValue = isObject ? opt.value : opt;
|
|
183
|
+
const optLabel = isObject ? opt.label : String(opt);
|
|
184
|
+
const valueStr = String(optValue);
|
|
185
|
+
|
|
186
|
+
if (!isObject) {
|
|
187
|
+
return {
|
|
188
|
+
label:
|
|
189
|
+
optionsDict[valueStr] ||
|
|
190
|
+
translate(
|
|
191
|
+
`crud.entities.${dictKey}.filters.${filter.name}.options.${valueStr}`,
|
|
192
|
+
dictionary,
|
|
193
|
+
optLabel,
|
|
194
|
+
),
|
|
195
|
+
value: optValue,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
...opt,
|
|
201
|
+
label:
|
|
202
|
+
optionsDict[valueStr] ||
|
|
203
|
+
translate(
|
|
204
|
+
`crud.entities.${dictKey}.filters.${filter.name}.options.${valueStr}`,
|
|
205
|
+
dictionary,
|
|
206
|
+
optLabel.startsWith("crud.")
|
|
207
|
+
? translate(optLabel, dictionary, optLabel)
|
|
208
|
+
: optLabel,
|
|
209
|
+
),
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return translatedFilter;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Translate rowActions
|
|
219
|
+
if (config.rowActions && config.rowActions.length > 0) {
|
|
220
|
+
const actionsDict =
|
|
221
|
+
(entityDict?.actions as Record<string, Record<string, string>>) || {};
|
|
222
|
+
translatedConfig.rowActions = config.rowActions.map((action) => {
|
|
223
|
+
const actionDict = actionsDict[action.action];
|
|
224
|
+
return {
|
|
225
|
+
...action,
|
|
226
|
+
label:
|
|
227
|
+
actionDict?.label ||
|
|
228
|
+
translate(
|
|
229
|
+
`crud.entities.${dictKey}.actions.${action.action}.label`,
|
|
230
|
+
dictionary,
|
|
231
|
+
action.label,
|
|
232
|
+
),
|
|
233
|
+
};
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Translate formSections
|
|
238
|
+
if (config.formSections && config.formSections.length > 0) {
|
|
239
|
+
const sectionsDict =
|
|
240
|
+
(entityDict?.sections as Record<string, Record<string, string>>) || {};
|
|
241
|
+
translatedConfig.formSections = config.formSections.map((section) => {
|
|
242
|
+
const sectionDict = sectionsDict[section.title] || {};
|
|
243
|
+
return {
|
|
244
|
+
...section,
|
|
245
|
+
title:
|
|
246
|
+
sectionDict.title ||
|
|
247
|
+
translate(
|
|
248
|
+
`crud.entities.${dictKey}.sections.${section.title}.title`,
|
|
249
|
+
dictionary,
|
|
250
|
+
section.title,
|
|
251
|
+
),
|
|
252
|
+
description:
|
|
253
|
+
sectionDict.description ||
|
|
254
|
+
translate(
|
|
255
|
+
`crud.entities.${dictKey}.sections.${section.title}.description`,
|
|
256
|
+
dictionary,
|
|
257
|
+
section.description || "",
|
|
258
|
+
),
|
|
259
|
+
fields: section.fields, // Field names không cần translate
|
|
260
|
+
};
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Strip non-serializable properties to avoid Next.js serialization errors
|
|
265
|
+
// These should be handled by identifiers (strings) on the client
|
|
266
|
+
const { icon: _icon, ...serializableConfig } = translatedConfig;
|
|
267
|
+
|
|
268
|
+
// Cleanup fields
|
|
269
|
+
serializableConfig.fields = translatedConfig.fields.map((field) => {
|
|
270
|
+
const {
|
|
271
|
+
renderCell: _renderCell,
|
|
272
|
+
renderForm: _renderForm,
|
|
273
|
+
renderInput: _renderInput,
|
|
274
|
+
validation: _validation,
|
|
275
|
+
...serializableField
|
|
276
|
+
} = field;
|
|
277
|
+
return serializableField;
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// Cleanup row actions
|
|
281
|
+
if (translatedConfig.rowActions) {
|
|
282
|
+
serializableConfig.rowActions = translatedConfig.rowActions.map(
|
|
283
|
+
(action) => {
|
|
284
|
+
const {
|
|
285
|
+
handler: _handler,
|
|
286
|
+
visibleWhen: _visibleWhen,
|
|
287
|
+
...serializableAction
|
|
288
|
+
} = action;
|
|
289
|
+
return serializableAction;
|
|
290
|
+
},
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return serializableConfig as EntityConfig;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Get common CRUD translations
|
|
299
|
+
*/
|
|
300
|
+
export function getCrudCommonTranslations(
|
|
301
|
+
dictionary: DictionaryType,
|
|
302
|
+
): Record<string, string> {
|
|
303
|
+
const crudDict = (dictionary as Record<string, unknown>).crud as
|
|
304
|
+
| Record<string, unknown>
|
|
305
|
+
| undefined;
|
|
306
|
+
return (crudDict?.common as Record<string, string>) || {};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Translate CRUD message với parameters
|
|
311
|
+
*/
|
|
312
|
+
export function translateCrudMessage(
|
|
313
|
+
dictionary: DictionaryType,
|
|
314
|
+
key: string,
|
|
315
|
+
params?: Record<string, string | number>,
|
|
316
|
+
): string {
|
|
317
|
+
const crudDict = (dictionary as Record<string, unknown>).crud as
|
|
318
|
+
| Record<string, unknown>
|
|
319
|
+
| undefined;
|
|
320
|
+
const commonDict = (crudDict?.common as Record<string, unknown>) || {};
|
|
321
|
+
const messagesDict = (commonDict.messages as Record<string, string>) || {};
|
|
322
|
+
let message = messagesDict[key] || key;
|
|
323
|
+
|
|
324
|
+
// Replace parameters
|
|
325
|
+
if (params) {
|
|
326
|
+
Object.entries(params).forEach(([param, value]) => {
|
|
327
|
+
message = message.replace(
|
|
328
|
+
new RegExp(`\\{\\{${param}\\}\\}`, "g"),
|
|
329
|
+
String(value),
|
|
330
|
+
);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return message;
|
|
335
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { cache } from "react";
|
|
2
|
+
import type { EntityConfig, FilterConfig, LocaleType } from "../../types";
|
|
3
|
+
import { CrudPage } from "../components/crud-page";
|
|
4
|
+
import { mergePermissions } from "../lib/permissions";
|
|
5
|
+
import { translateEntityConfig } from "../lib/translate-config";
|
|
6
|
+
|
|
7
|
+
interface EntityCrudPageProps {
|
|
8
|
+
entity: string;
|
|
9
|
+
lang: string;
|
|
10
|
+
config: EntityConfig;
|
|
11
|
+
session: any;
|
|
12
|
+
dictionary: any;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Serialize config to make it safe for Client Components
|
|
16
|
+
// Removes non-serializable React components and functions
|
|
17
|
+
function serializeConfig(config: EntityConfig): Omit<EntityConfig, "icon"> {
|
|
18
|
+
const { icon, fields, filters, ...rest } = config;
|
|
19
|
+
|
|
20
|
+
// If icon exists but iconName doesn't, try to extract icon name from displayName
|
|
21
|
+
if (icon && !rest.iconName) {
|
|
22
|
+
const iconComponent = icon as { displayName?: string };
|
|
23
|
+
if (iconComponent.displayName) {
|
|
24
|
+
rest.iconName = iconComponent.displayName;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Serialize fields
|
|
29
|
+
const serializedFields = fields.map((field) => {
|
|
30
|
+
const {
|
|
31
|
+
renderCell: _renderCell,
|
|
32
|
+
renderForm: _renderForm,
|
|
33
|
+
renderInput: _renderInput,
|
|
34
|
+
validation: _validation,
|
|
35
|
+
dataSource,
|
|
36
|
+
...fieldRest
|
|
37
|
+
} = field;
|
|
38
|
+
|
|
39
|
+
if (dataSource?.transform) {
|
|
40
|
+
const { transform: _transform, ...dataSourceRest } = dataSource;
|
|
41
|
+
return {
|
|
42
|
+
...fieldRest,
|
|
43
|
+
dataSource: dataSourceRest,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return dataSource ? { ...fieldRest, dataSource } : fieldRest;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Serialize filters
|
|
51
|
+
const serializedFilters = filters?.map((filter) => {
|
|
52
|
+
const { renderFilter: _renderFilter, ...filterRest } = filter;
|
|
53
|
+
return filterRest as Omit<FilterConfig, "renderFilter">;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Serialize rowActions
|
|
57
|
+
const serializedRowActions = rest.rowActions?.map((action) => {
|
|
58
|
+
const {
|
|
59
|
+
handler: _handler,
|
|
60
|
+
transformData: _transformData,
|
|
61
|
+
visibleWhen: _visibleWhen,
|
|
62
|
+
...actionRest
|
|
63
|
+
} = action;
|
|
64
|
+
return actionRest;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
...rest,
|
|
69
|
+
fields: serializedFields,
|
|
70
|
+
filters: serializedFilters,
|
|
71
|
+
rowActions: serializedRowActions,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Process config (translate + serialize)
|
|
76
|
+
const getProcessedConfig = cache(
|
|
77
|
+
async (
|
|
78
|
+
config: EntityConfig,
|
|
79
|
+
entity: string,
|
|
80
|
+
lang: string,
|
|
81
|
+
dictionary: any,
|
|
82
|
+
) => {
|
|
83
|
+
// Translate config
|
|
84
|
+
const translatedConfig = translateEntityConfig(
|
|
85
|
+
config,
|
|
86
|
+
dictionary,
|
|
87
|
+
lang,
|
|
88
|
+
entity,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Serialize translated config
|
|
92
|
+
const serializedConfig = serializeConfig(translatedConfig);
|
|
93
|
+
|
|
94
|
+
return serializedConfig;
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
export async function EntityCrudPage({
|
|
99
|
+
entity,
|
|
100
|
+
lang,
|
|
101
|
+
config,
|
|
102
|
+
session,
|
|
103
|
+
dictionary,
|
|
104
|
+
}: EntityCrudPageProps) {
|
|
105
|
+
try {
|
|
106
|
+
const serializedConfig = await getProcessedConfig(
|
|
107
|
+
config,
|
|
108
|
+
entity,
|
|
109
|
+
lang,
|
|
110
|
+
dictionary,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// Get user permissions for this entity if available in session or passed explicitly?
|
|
114
|
+
// In vinhhoa/page.tsx: getCrudPermissions(session, entity) is called.
|
|
115
|
+
// We should probably rely on `session` having what we need OR generic permissions logic.
|
|
116
|
+
// The `mergePermissions` below merges generic config perms with USER perms.
|
|
117
|
+
// We need user perms.
|
|
118
|
+
|
|
119
|
+
// We can import getCrudPermissions from ../lib/permissions if it effectively uses session
|
|
120
|
+
const { getCrudPermissions } = await import("../lib/permissions");
|
|
121
|
+
const userPermissions = await getCrudPermissions(session, entity);
|
|
122
|
+
|
|
123
|
+
const permissions = mergePermissions(config.permissions, userPermissions);
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<CrudPage
|
|
127
|
+
config={serializedConfig as EntityConfig}
|
|
128
|
+
permissions={permissions}
|
|
129
|
+
entityName={entity}
|
|
130
|
+
dictionary={dictionary}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error(`Error loading CRUD page for ${entity}:`, error);
|
|
135
|
+
return (
|
|
136
|
+
<div className="p-4">
|
|
137
|
+
<h1 className="text-2xl font-bold">Error</h1>
|
|
138
|
+
<p className="text-muted-foreground">
|
|
139
|
+
{error instanceof Error ? error.message : "Failed to load page"}
|
|
140
|
+
</p>
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
// Icon mapping for common actions
|
|
4
|
+
export const iconMap: Record<string, React.ReactNode> = {
|
|
5
|
+
"shopping-cart": (
|
|
6
|
+
<svg
|
|
7
|
+
className="h-5 w-5"
|
|
8
|
+
fill="none"
|
|
9
|
+
stroke="currentColor"
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
>
|
|
12
|
+
<path
|
|
13
|
+
strokeLinecap="round"
|
|
14
|
+
strokeLinejoin="round"
|
|
15
|
+
strokeWidth={2}
|
|
16
|
+
d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"
|
|
17
|
+
/>
|
|
18
|
+
</svg>
|
|
19
|
+
),
|
|
20
|
+
users: (
|
|
21
|
+
<svg
|
|
22
|
+
className="h-5 w-5"
|
|
23
|
+
fill="none"
|
|
24
|
+
stroke="currentColor"
|
|
25
|
+
viewBox="0 0 24 24"
|
|
26
|
+
>
|
|
27
|
+
<path
|
|
28
|
+
strokeLinecap="round"
|
|
29
|
+
strokeLinejoin="round"
|
|
30
|
+
strokeWidth={2}
|
|
31
|
+
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
|
|
32
|
+
/>
|
|
33
|
+
</svg>
|
|
34
|
+
),
|
|
35
|
+
package: (
|
|
36
|
+
<svg
|
|
37
|
+
className="h-5 w-5"
|
|
38
|
+
fill="none"
|
|
39
|
+
stroke="currentColor"
|
|
40
|
+
viewBox="0 0 24 24"
|
|
41
|
+
>
|
|
42
|
+
<path
|
|
43
|
+
strokeLinecap="round"
|
|
44
|
+
strokeLinejoin="round"
|
|
45
|
+
strokeWidth={2}
|
|
46
|
+
d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"
|
|
47
|
+
/>
|
|
48
|
+
</svg>
|
|
49
|
+
),
|
|
50
|
+
"chart-bar": (
|
|
51
|
+
<svg
|
|
52
|
+
className="h-5 w-5"
|
|
53
|
+
fill="none"
|
|
54
|
+
stroke="currentColor"
|
|
55
|
+
viewBox="0 0 24 24"
|
|
56
|
+
>
|
|
57
|
+
<path
|
|
58
|
+
strokeLinecap="round"
|
|
59
|
+
strokeLinejoin="round"
|
|
60
|
+
strokeWidth={2}
|
|
61
|
+
d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
|
|
62
|
+
/>
|
|
63
|
+
</svg>
|
|
64
|
+
),
|
|
65
|
+
"document-text": (
|
|
66
|
+
<svg
|
|
67
|
+
className="h-5 w-5"
|
|
68
|
+
fill="none"
|
|
69
|
+
stroke="currentColor"
|
|
70
|
+
viewBox="0 0 24 24"
|
|
71
|
+
>
|
|
72
|
+
<path
|
|
73
|
+
strokeLinecap="round"
|
|
74
|
+
strokeLinejoin="round"
|
|
75
|
+
strokeWidth={2}
|
|
76
|
+
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
77
|
+
/>
|
|
78
|
+
</svg>
|
|
79
|
+
),
|
|
80
|
+
cog: (
|
|
81
|
+
<svg
|
|
82
|
+
className="h-5 w-5"
|
|
83
|
+
fill="none"
|
|
84
|
+
stroke="currentColor"
|
|
85
|
+
viewBox="0 0 24 24"
|
|
86
|
+
>
|
|
87
|
+
<path
|
|
88
|
+
strokeLinecap="round"
|
|
89
|
+
strokeLinejoin="round"
|
|
90
|
+
strokeWidth={2}
|
|
91
|
+
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
|
92
|
+
/>
|
|
93
|
+
<path
|
|
94
|
+
strokeLinecap="round"
|
|
95
|
+
strokeLinejoin="round"
|
|
96
|
+
strokeWidth={2}
|
|
97
|
+
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
98
|
+
/>
|
|
99
|
+
</svg>
|
|
100
|
+
),
|
|
101
|
+
"currency-dollar": (
|
|
102
|
+
<svg
|
|
103
|
+
className="h-5 w-5"
|
|
104
|
+
fill="none"
|
|
105
|
+
stroke="currentColor"
|
|
106
|
+
viewBox="0 0 24 24"
|
|
107
|
+
>
|
|
108
|
+
<path
|
|
109
|
+
strokeLinecap="round"
|
|
110
|
+
strokeLinejoin="round"
|
|
111
|
+
strokeWidth={2}
|
|
112
|
+
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
113
|
+
/>
|
|
114
|
+
</svg>
|
|
115
|
+
),
|
|
116
|
+
"clipboard-list": (
|
|
117
|
+
<svg
|
|
118
|
+
className="h-5 w-5"
|
|
119
|
+
fill="none"
|
|
120
|
+
stroke="currentColor"
|
|
121
|
+
viewBox="0 0 24 24"
|
|
122
|
+
>
|
|
123
|
+
<path
|
|
124
|
+
strokeLinecap="round"
|
|
125
|
+
strokeLinejoin="round"
|
|
126
|
+
strokeWidth={2}
|
|
127
|
+
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"
|
|
128
|
+
/>
|
|
129
|
+
</svg>
|
|
130
|
+
),
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const colorClasses: Record<string, string> = {
|
|
134
|
+
blue: "bg-blue-500 hover:bg-blue-600 text-white",
|
|
135
|
+
green: "bg-green-500 hover:bg-green-600 text-white",
|
|
136
|
+
purple: "bg-purple-500 hover:bg-purple-600 text-white",
|
|
137
|
+
orange: "bg-orange-500 hover:bg-orange-600 text-white",
|
|
138
|
+
pink: "bg-pink-500 hover:bg-pink-600 text-white",
|
|
139
|
+
indigo: "bg-indigo-500 hover:bg-indigo-600 text-white",
|
|
140
|
+
teal: "bg-teal-500 hover:bg-teal-600 text-white",
|
|
141
|
+
red: "bg-red-500 hover:bg-red-600 text-white",
|
|
142
|
+
};
|