@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.
Files changed (369) hide show
  1. package/package.json +2 -1
  2. package/src/assets/erp_wallpaper.png +0 -0
  3. package/src/assets/goeat_logo.png +0 -0
  4. package/src/audit/audit-manager.ts +139 -0
  5. package/src/audit/index.ts +11 -0
  6. package/src/audit/memory-audit-logger.ts +86 -0
  7. package/src/audit/types.ts +50 -0
  8. package/src/auth/auth-service.ts +97 -0
  9. package/src/auth/index.ts +266 -0
  10. package/src/code-generation/index.ts +69 -0
  11. package/src/configs/auth-routes.ts +17 -0
  12. package/src/configs/crud.ts +136 -0
  13. package/src/configs/data/navigations.ts +781 -0
  14. package/src/configs/data/oauth-links.ts +10 -0
  15. package/src/configs/entities/material-categories.config.ts +125 -0
  16. package/src/configs/i18n.ts +12 -0
  17. package/src/configs/index.ts +26 -0
  18. package/src/configs/status.ts +25 -0
  19. package/src/configs/themes.ts +100 -0
  20. package/src/crud/components/crud-bulk-actions.tsx +91 -0
  21. package/src/crud/components/crud-card-view.tsx +241 -0
  22. package/src/crud/components/crud-context.tsx +122 -0
  23. package/src/crud/components/crud-delete-dialog.tsx +145 -0
  24. package/src/crud/components/crud-dialog.tsx +406 -0
  25. package/src/crud/components/crud-empty-state.tsx +104 -0
  26. package/src/crud/components/crud-export-button.tsx +170 -0
  27. package/src/crud/components/crud-field-renderer.tsx +653 -0
  28. package/src/crud/components/crud-filter-chips.tsx +102 -0
  29. package/src/crud/components/crud-filters/checkbox-filter.tsx +97 -0
  30. package/src/crud/components/crud-filters/datetime-filter.tsx +83 -0
  31. package/src/crud/components/crud-filters/filter-builder.tsx +66 -0
  32. package/src/crud/components/crud-filters/index.tsx +76 -0
  33. package/src/crud/components/crud-filters/radio-filter.tsx +86 -0
  34. package/src/crud/components/crud-filters/select-filter.tsx +141 -0
  35. package/src/crud/components/crud-filters/text-filter.tsx +86 -0
  36. package/src/crud/components/crud-form.tsx +642 -0
  37. package/src/crud/components/crud-import-dialog.tsx +440 -0
  38. package/src/crud/components/crud-infinite-scroll.tsx +116 -0
  39. package/src/crud/components/crud-page.tsx +1017 -0
  40. package/src/crud/components/crud-provider.tsx +277 -0
  41. package/src/crud/components/crud-row-actions.tsx +189 -0
  42. package/src/crud/components/crud-search.tsx +82 -0
  43. package/src/crud/components/crud-sheet.tsx +336 -0
  44. package/src/crud/components/crud-table-skeleton.tsx +26 -0
  45. package/src/crud/components/crud-table-toolbar.tsx +91 -0
  46. package/src/crud/components/crud-table.tsx +352 -0
  47. package/src/crud/components/crud-virtual-table.tsx +55 -0
  48. package/src/crud/components/index.tsx +20 -0
  49. package/src/crud/crud-filters/checkbox-filter.tsx +87 -0
  50. package/src/crud/crud-filters/datetime-filter.tsx +82 -0
  51. package/src/crud/crud-filters/filter-builder.tsx +64 -0
  52. package/src/crud/crud-filters/index.tsx +78 -0
  53. package/src/crud/crud-filters/radio-filter.tsx +79 -0
  54. package/src/crud/crud-filters/select-filter.tsx +148 -0
  55. package/src/crud/crud-filters/text-filter.tsx +81 -0
  56. package/src/crud/index.ts +43 -0
  57. package/src/crud/lib/crud-service.test.ts +334 -0
  58. package/src/crud/lib/crud-service.ts +358 -0
  59. package/src/crud/lib/crud-utils.test.ts +354 -0
  60. package/src/crud/lib/crud-utils.ts +299 -0
  61. package/src/crud/lib/crud-validator.ts +247 -0
  62. package/src/crud/lib/data-loader.ts +234 -0
  63. package/src/crud/lib/field-calculator.ts +241 -0
  64. package/src/crud/lib/field-formatter.ts +240 -0
  65. package/src/crud/lib/import-export-service.test.ts +290 -0
  66. package/src/crud/lib/import-export-service.ts +352 -0
  67. package/src/crud/lib/import-server-utils.ts +109 -0
  68. package/src/crud/lib/lazy-loader.ts +241 -0
  69. package/src/crud/lib/parse-filters.ts +85 -0
  70. package/src/crud/lib/permissions.ts +52 -0
  71. package/src/crud/lib/serialize-config.ts +60 -0
  72. package/src/crud/lib/stream-loader.ts +145 -0
  73. package/src/crud/lib/translate-config.ts +335 -0
  74. package/src/crud/lib/types.ts +11 -0
  75. package/src/crud/pages/entity-crud-page.tsx +144 -0
  76. package/src/crud/server.ts +8 -0
  77. package/src/home/constants.tsx +142 -0
  78. package/src/home/feature-showcase.tsx +171 -0
  79. package/src/home/home-page.tsx +191 -0
  80. package/src/home/hooks/index.ts +1 -0
  81. package/src/home/hooks/useWidgetPreferences.ts +167 -0
  82. package/src/home/index.ts +33 -0
  83. package/src/home/quick-access-dialog.tsx +271 -0
  84. package/src/home/quick-access-menu.tsx +267 -0
  85. package/src/home/types.ts +140 -0
  86. package/src/home/welcome-card.tsx +92 -0
  87. package/src/home/widget-container.tsx +258 -0
  88. package/src/home/widgets/base-widget.tsx +200 -0
  89. package/src/home/widgets/customers-widget.tsx +74 -0
  90. package/src/home/widgets/index.ts +6 -0
  91. package/src/home/widgets/orders-widget.tsx +87 -0
  92. package/src/home/widgets/revenue-widget.tsx +71 -0
  93. package/src/home/widgets/stock-widget.tsx +109 -0
  94. package/src/hooks/index.tsx +598 -0
  95. package/src/hooks/use-tenant.test.tsx +30 -0
  96. package/src/hooks/use-tenant.ts +5 -0
  97. package/src/index.ts +17 -0
  98. package/src/infrastructure/__tests__/architecture-verification.spec.ts +103 -0
  99. package/src/infrastructure/api-service.ts +317 -0
  100. package/src/infrastructure/cache/cache-manager.ts +107 -0
  101. package/src/infrastructure/cache/cache.ts +120 -0
  102. package/src/infrastructure/cache/index.ts +8 -0
  103. package/src/infrastructure/cache/types.ts +48 -0
  104. package/src/infrastructure/cron/cron-manager.ts +239 -0
  105. package/src/infrastructure/cron/index.ts +6 -0
  106. package/src/infrastructure/cron/types.ts +41 -0
  107. package/src/infrastructure/event-bus/event-bus.ts +145 -0
  108. package/src/infrastructure/event-bus/index.ts +2 -0
  109. package/src/infrastructure/event-bus/types.ts +22 -0
  110. package/src/infrastructure/index.ts +32 -0
  111. package/src/infrastructure/lock/decorators.ts +67 -0
  112. package/src/infrastructure/lock/index.ts +2 -0
  113. package/src/infrastructure/lock/lock-manager.ts +33 -0
  114. package/src/infrastructure/logger/index.ts +2 -0
  115. package/src/infrastructure/logger/logger.ts +96 -0
  116. package/src/infrastructure/logger/types.ts +25 -0
  117. package/src/layout/index.tsx +185 -0
  118. package/src/navigation/index.ts +91 -0
  119. package/src/notification/index.ts +14 -0
  120. package/src/notification/notification-service.ts +120 -0
  121. package/src/notification/storage/in-memory.ts +56 -0
  122. package/src/notification/storage/index.ts +1 -0
  123. package/src/notification/types.ts +51 -0
  124. package/src/organization/branch-service.ts +299 -0
  125. package/src/organization/branches.config.ts +154 -0
  126. package/src/organization/index.ts +5 -0
  127. package/src/plugin/apps-registry.ts +97 -0
  128. package/src/plugin/index.ts +5 -0
  129. package/src/plugin/types.ts +41 -0
  130. package/src/providers/index.tsx +109 -0
  131. package/src/providers/tenant-provider.tsx +45 -0
  132. package/src/rbac/components/roles/role-card.tsx +158 -0
  133. package/src/rbac/components/roles/role-stats-cards.tsx +29 -0
  134. package/src/rbac/components/roles/role-toolbar.tsx +123 -0
  135. package/src/rbac/hooks/use-role-operations.ts +159 -0
  136. package/src/rbac/hooks/use-roles-data.ts +59 -0
  137. package/src/rbac/index.ts +297 -0
  138. package/src/rbac/lib/permission-helpers.ts +63 -0
  139. package/src/rbac/pages/action-list-page.tsx +25 -0
  140. package/src/rbac/pages/resource-list-page.tsx +25 -0
  141. package/src/rbac/pages/role-list-page.tsx +378 -0
  142. package/src/rbac/permission-service.ts +140 -0
  143. package/src/rbac/permissions.ts +135 -0
  144. package/src/rbac/resource-service.ts +115 -0
  145. package/src/rbac/resource-validator.ts +119 -0
  146. package/src/rbac/role-service.ts +165 -0
  147. package/src/rbac/server.ts +16 -0
  148. package/src/rbac/types.ts +38 -0
  149. package/src/schemas/action.schema.ts +66 -0
  150. package/src/schemas/branch.schema.ts +52 -0
  151. package/src/schemas/coming-soon-schema.ts +9 -0
  152. package/src/schemas/company.schema.ts +44 -0
  153. package/src/schemas/forgot-passward-schema.ts +9 -0
  154. package/src/schemas/index.ts +30 -0
  155. package/src/schemas/material-category.schema.ts +43 -0
  156. package/src/schemas/material-pricing.schema.ts +74 -0
  157. package/src/schemas/material.schema.ts +76 -0
  158. package/src/schemas/materials.ts +52 -0
  159. package/src/schemas/new-passward-schema.ts +15 -0
  160. package/src/schemas/partner-company.schema.ts +149 -0
  161. package/src/schemas/register-schema.ts +36 -0
  162. package/src/schemas/resource.schema.ts +133 -0
  163. package/src/schemas/role.schema.ts +11 -0
  164. package/src/schemas/sign-in-schema.ts +24 -0
  165. package/src/schemas/supplier-pricing.schema.ts +15 -0
  166. package/src/schemas/supplier.schema.ts +120 -0
  167. package/src/schemas/system-category-group.schema.ts +67 -0
  168. package/src/schemas/system-category.schema.ts +77 -0
  169. package/src/schemas/system-config.schema.ts +118 -0
  170. package/src/schemas/uom.schema.ts +75 -0
  171. package/src/schemas/user-supplier.schema.ts +179 -0
  172. package/src/schemas/user.schema.ts +18 -0
  173. package/src/schemas/verify-email-schema.ts +9 -0
  174. package/src/schemas/warehouse.schema.ts +49 -0
  175. package/src/system/components/categories/category-list.tsx +529 -0
  176. package/src/system/components/categories/category-manager.tsx +89 -0
  177. package/src/system/components/categories/group-sidebar.tsx +308 -0
  178. package/src/system/components/settings/setting-dialogs.tsx +197 -0
  179. package/src/system/components/settings/setting-field.tsx +291 -0
  180. package/src/system/components/settings/setting-form-dialog.tsx +308 -0
  181. package/src/system/components/settings/settings-groups.ts +80 -0
  182. package/src/system/components/settings/settings-search.tsx +71 -0
  183. package/src/system/components/settings/settings-section.tsx +74 -0
  184. package/src/system/components/settings/settings-sidebar.tsx +81 -0
  185. package/src/system/constants.ts +3 -0
  186. package/src/system/index.ts +150 -0
  187. package/src/system/job-manager.ts +176 -0
  188. package/src/system/pages/components/categories/category-list.tsx +537 -0
  189. package/src/system/pages/components/categories/category-manager.tsx +90 -0
  190. package/src/system/pages/components/categories/group-sidebar.tsx +311 -0
  191. package/src/system/pages/components/settings/sales-rules-settings.tsx +222 -0
  192. package/src/system/pages/components/settings/setting-dialogs.tsx +197 -0
  193. package/src/system/pages/components/settings/setting-field.tsx +292 -0
  194. package/src/system/pages/components/settings/setting-form-dialog.tsx +308 -0
  195. package/src/system/pages/components/settings/settings-groups.ts +87 -0
  196. package/src/system/pages/components/settings/settings-page.tsx +372 -0
  197. package/src/system/pages/components/settings/settings-search.tsx +71 -0
  198. package/src/system/pages/components/settings/settings-section.tsx +74 -0
  199. package/src/system/pages/components/settings/settings-sidebar.tsx +81 -0
  200. package/src/system/pages/components/settings/system-settings.tsx +244 -0
  201. package/src/system/pages/system-category-page.tsx +15 -0
  202. package/src/system/pages/system-settings-page.tsx +380 -0
  203. package/src/system/schemas/system-category-group.schema.ts +46 -0
  204. package/src/system/schemas/system-category.schema.ts +56 -0
  205. package/src/system/services/settings-service.ts +127 -0
  206. package/src/system/services/system-category-service.ts +63 -0
  207. package/src/system/types.ts +45 -0
  208. package/src/types/index.ts +703 -0
  209. package/src/ui/auth/auth-layout.tsx +135 -0
  210. package/src/ui/auth/forgot-password-form.tsx +98 -0
  211. package/src/ui/auth/index.tsx +7 -0
  212. package/src/ui/auth/new-password-form.tsx +107 -0
  213. package/src/ui/auth/oauth-links.tsx +30 -0
  214. package/src/ui/auth/register-form.tsx +202 -0
  215. package/src/ui/auth/sign-in-form.tsx +238 -0
  216. package/src/ui/auth/verify-email-form.tsx +104 -0
  217. package/src/ui/crud/index.tsx +10 -0
  218. package/src/ui/data-display/accordion.tsx +65 -0
  219. package/src/ui/data-display/aspect-ratio.tsx +11 -0
  220. package/src/ui/data-display/avatar.tsx +163 -0
  221. package/src/ui/data-display/bento-grid.tsx +77 -0
  222. package/src/ui/data-display/carousel.tsx +249 -0
  223. package/src/ui/data-display/chart.tsx +363 -0
  224. package/src/ui/data-display/code-block-highlight.tsx +54 -0
  225. package/src/ui/data-display/collapsible.tsx +42 -0
  226. package/src/ui/data-display/compact-stat-bar.tsx +149 -0
  227. package/src/ui/data-display/data-table/data-table-context.tsx +255 -0
  228. package/src/ui/data-display/data-table/data-table-empty-state.tsx +133 -0
  229. package/src/ui/data-display/data-table/data-table-skeleton.tsx +145 -0
  230. package/src/ui/data-display/data-table/data-table-toolbar.tsx +353 -0
  231. package/src/ui/data-display/data-table/data-table.tsx +597 -0
  232. package/src/ui/data-display/data-table/index.ts +44 -0
  233. package/src/ui/data-display/data-table-column-header.tsx +75 -0
  234. package/src/ui/data-display/data-table-pagination.tsx +130 -0
  235. package/src/ui/data-display/data-table-view-options.tsx +59 -0
  236. package/src/ui/data-display/formatted-number-input.tsx +210 -0
  237. package/src/ui/data-display/highlight.tsx +20 -0
  238. package/src/ui/data-display/hover-card.tsx +48 -0
  239. package/src/ui/data-display/index.tsx +50 -0
  240. package/src/ui/data-display/iphone-15-pro.tsx +114 -0
  241. package/src/ui/data-display/kanban/index.ts +4 -0
  242. package/src/ui/data-display/kanban/kanban-board.tsx +192 -0
  243. package/src/ui/data-display/kanban/kanban-column.tsx +74 -0
  244. package/src/ui/data-display/kanban/kanban-item.tsx +50 -0
  245. package/src/ui/data-display/kanban/kanban-types.ts +21 -0
  246. package/src/ui/data-display/kpi-card.tsx +68 -0
  247. package/src/ui/data-display/media-grid.tsx +110 -0
  248. package/src/ui/data-display/safari.tsx +175 -0
  249. package/src/ui/data-display/show-more-text.tsx +55 -0
  250. package/src/ui/data-display/tabs.tsx +68 -0
  251. package/src/ui/data-display/timeline.tsx +256 -0
  252. package/src/ui/feedback/alert.tsx +60 -0
  253. package/src/ui/feedback/context-menu.tsx +245 -0
  254. package/src/ui/feedback/drawer.tsx +132 -0
  255. package/src/ui/feedback/error-dialog.tsx +273 -0
  256. package/src/ui/feedback/index.tsx +183 -0
  257. package/src/ui/feedback/progress.tsx +32 -0
  258. package/src/ui/feedback/sheet.tsx +148 -0
  259. package/src/ui/feedback/sonner.tsx +36 -0
  260. package/src/ui/forms/command.tsx +157 -0
  261. package/src/ui/forms/date-picker.tsx +73 -0
  262. package/src/ui/forms/date-range-picker.tsx +76 -0
  263. package/src/ui/forms/date-time-picker.tsx +109 -0
  264. package/src/ui/forms/editor/editor-menu-bar.tsx +394 -0
  265. package/src/ui/forms/editor/index.tsx +130 -0
  266. package/src/ui/forms/editor/multi-select-example.tsx +1234 -0
  267. package/src/ui/forms/emoji-picker.tsx +109 -0
  268. package/src/ui/forms/file-dropzone.tsx +169 -0
  269. package/src/ui/forms/file-thumbnail.tsx +29 -0
  270. package/src/ui/forms/index.tsx +201 -0
  271. package/src/ui/forms/input-file.tsx +99 -0
  272. package/src/ui/forms/input-group.tsx +46 -0
  273. package/src/ui/forms/input-otp.tsx +81 -0
  274. package/src/ui/forms/input-phone.tsx +172 -0
  275. package/src/ui/forms/input-spin.tsx +116 -0
  276. package/src/ui/forms/input-tags.tsx +219 -0
  277. package/src/ui/forms/input-time.tsx +42 -0
  278. package/src/ui/forms/multi-select.tsx +629 -0
  279. package/src/ui/forms/multiple-date-picker.tsx +74 -0
  280. package/src/ui/forms/radio-group.tsx +42 -0
  281. package/src/ui/forms/rating.tsx +158 -0
  282. package/src/ui/forms/time-picker.tsx +57 -0
  283. package/src/ui/index.tsx +17 -0
  284. package/src/ui/layout/animated-list.tsx +77 -0
  285. package/src/ui/layout/animated-sidebar.tsx +294 -0
  286. package/src/ui/layout/command-menu.tsx +355 -0
  287. package/src/ui/layout/customizer.tsx +324 -0
  288. package/src/ui/layout/footer.tsx +43 -0
  289. package/src/ui/layout/full-screen-toggle.tsx +52 -0
  290. package/src/ui/layout/header-breadcrumb.tsx +77 -0
  291. package/src/ui/layout/horizontal-layout-header.tsx +83 -0
  292. package/src/ui/layout/horizontal-layout.tsx +50 -0
  293. package/src/ui/layout/index.tsx +25 -0
  294. package/src/ui/layout/language-dropdown.tsx +103 -0
  295. package/src/ui/layout/logo.tsx +63 -0
  296. package/src/ui/layout/main-layout.tsx +57 -0
  297. package/src/ui/layout/mode-dropdown.tsx +58 -0
  298. package/src/ui/layout/notification-dropdown.tsx +127 -0
  299. package/src/ui/layout/page-tabs.tsx +306 -0
  300. package/src/ui/layout/route-cache.tsx +214 -0
  301. package/src/ui/layout/sidebar-group-icon-menu.tsx +195 -0
  302. package/src/ui/layout/sidebar.tsx +279 -0
  303. package/src/ui/layout/tab-content-cache.tsx +201 -0
  304. package/src/ui/layout/tab-navigation-provider.tsx +536 -0
  305. package/src/ui/layout/toggle-mobile-sidebar.tsx +33 -0
  306. package/src/ui/layout/top-bar-header-menubar.tsx +412 -0
  307. package/src/ui/layout/user-dropdown.tsx +188 -0
  308. package/src/ui/layout/vertical-layout-header.tsx +65 -0
  309. package/src/ui/layout/vertical-layout.tsx +47 -0
  310. package/src/ui/management/audit-log-page.tsx +209 -0
  311. package/src/ui/management/cache-management.tsx +349 -0
  312. package/src/ui/management/index.ts +3 -0
  313. package/src/ui/management/job-management.tsx +308 -0
  314. package/src/ui/pages/not-found.tsx +30 -0
  315. package/src/ui/primitives/badge.tsx +66 -0
  316. package/src/ui/primitives/breadcrumb.tsx +103 -0
  317. package/src/ui/primitives/button.tsx +129 -0
  318. package/src/ui/primitives/calendar.tsx +74 -0
  319. package/src/ui/primitives/card.tsx +86 -0
  320. package/src/ui/primitives/checkbox.tsx +31 -0
  321. package/src/ui/primitives/client.ts +30 -0
  322. package/src/ui/primitives/combobox.tsx +290 -0
  323. package/src/ui/primitives/dialog.tsx +121 -0
  324. package/src/ui/primitives/dropdown-menu.tsx +239 -0
  325. package/src/ui/primitives/dynamic-icon.tsx +24 -0
  326. package/src/ui/primitives/index.tsx +134 -0
  327. package/src/ui/primitives/input-number.tsx +131 -0
  328. package/src/ui/primitives/input.tsx +22 -0
  329. package/src/ui/primitives/keyboard.tsx +23 -0
  330. package/src/ui/primitives/label.tsx +24 -0
  331. package/src/ui/primitives/menubar.tsx +262 -0
  332. package/src/ui/primitives/navigation-menu.tsx +157 -0
  333. package/src/ui/primitives/pagination.tsx +118 -0
  334. package/src/ui/primitives/popover.tsx +56 -0
  335. package/src/ui/primitives/prefetch-link.tsx +60 -0
  336. package/src/ui/primitives/resizable.tsx +59 -0
  337. package/src/ui/primitives/scroll-area.tsx +63 -0
  338. package/src/ui/primitives/select.tsx +172 -0
  339. package/src/ui/primitives/separator.tsx +51 -0
  340. package/src/ui/primitives/sidebar.tsx +844 -0
  341. package/src/ui/primitives/slider.tsx +27 -0
  342. package/src/ui/primitives/status-badge.tsx +47 -0
  343. package/src/ui/primitives/sticky-layout.tsx +50 -0
  344. package/src/ui/primitives/switch.tsx +29 -0
  345. package/src/ui/primitives/table.tsx +116 -0
  346. package/src/ui/primitives/tabs.tsx +55 -0
  347. package/src/ui/primitives/toggle-group.tsx +70 -0
  348. package/src/ui/primitives/toggle.tsx +47 -0
  349. package/src/ui/primitives/tooltip.tsx +59 -0
  350. package/src/user/components/dangerous-zone.tsx +34 -0
  351. package/src/user/components/delete-account-form.tsx +40 -0
  352. package/src/user/components/index.ts +4 -0
  353. package/src/user/components/profile-info-form.tsx +390 -0
  354. package/src/user/components/profile-info.tsx +32 -0
  355. package/src/user/components/unified-profile-dialog.tsx +1019 -0
  356. package/src/user/components/user-stats.tsx +27 -0
  357. package/src/user/components/user-toolbar.tsx +137 -0
  358. package/src/user/components/users-card-view.tsx +253 -0
  359. package/src/user/index.ts +11 -0
  360. package/src/user/pages/user-list-page.tsx +234 -0
  361. package/src/user/pages/users-client-page.tsx +385 -0
  362. package/src/user/profile-page.tsx +19 -0
  363. package/src/user/schemas.ts +68 -0
  364. package/src/user/types.ts +34 -0
  365. package/src/user/user-service.ts +538 -0
  366. package/src/utils/index.ts +906 -0
  367. package/src/workflow/activity-timeline.tsx +412 -0
  368. package/src/workflow/approval-workflow.tsx +31 -0
  369. package/src/workflow/index.ts +2 -0
@@ -0,0 +1,10 @@
1
+ import { Facebook, Github, Chrome, Twitter } from "lucide-react";
2
+
3
+ import type { OAuthLinkType } from "../../types";
4
+
5
+ export const oauthLinksData: OAuthLinkType[] = [
6
+ { href: "/", label: "Facebook", icon: Facebook },
7
+ { href: "/", label: "GitHub", icon: Github },
8
+ { href: "/", label: "Google", icon: Chrome },
9
+ { href: "/", label: "X", icon: Twitter },
10
+ ];
@@ -0,0 +1,125 @@
1
+ import { FolderTree } from "lucide-react";
2
+
3
+ import type { EntityConfig } from "../../types";
4
+
5
+ import { STATUS_OPTIONS } from "../status";
6
+
7
+ export const materialCategoriesConfig: EntityConfig = {
8
+ name: "material-category",
9
+ label: "Danh mục nguyên vật liệu",
10
+ pluralLabel: "Danh mục nguyên vật liệu",
11
+ icon: FolderTree,
12
+ description: "Quản lý danh mục nguyên vật liệu",
13
+ apiEndpoint: "/api/material-categories",
14
+ idField: "id",
15
+ displayField: "name",
16
+
17
+ // Custom row actions
18
+ rowActions: [
19
+ {
20
+ label: "Copy",
21
+ action: "copy",
22
+ icon: "Copy",
23
+ excludeFields: ["id", "createdAt", "createdBy", "updatedAt", "updatedBy"],
24
+ transformData: (rowData) => ({
25
+ ...rowData,
26
+ code: `${rowData.code}-COPY`,
27
+ name: `${rowData.name} (Copy)`,
28
+ }),
29
+ },
30
+ ],
31
+
32
+ fields: [
33
+ {
34
+ name: "id",
35
+ label: "ID",
36
+ type: "text",
37
+ hideInForm: true,
38
+ hideInTable: true,
39
+ },
40
+ {
41
+ name: "code",
42
+ label: "Mã danh mục",
43
+ type: "text",
44
+ required: true,
45
+ placeholder: "Nhập mã danh mục",
46
+
47
+ filterable: true,
48
+ disableOnEdit: true,
49
+ },
50
+ {
51
+ name: "name",
52
+ label: "Tên danh mục",
53
+ type: "text",
54
+ required: true,
55
+ placeholder: "Nhập tên danh mục",
56
+
57
+ filterable: true,
58
+ },
59
+ {
60
+ name: "description",
61
+ label: "Mô tả",
62
+ type: "textarea",
63
+ placeholder: "Nhập mô tả",
64
+ rows: 3,
65
+ hideInTable: true,
66
+ },
67
+ {
68
+ name: "status",
69
+ label: "Trạng thái",
70
+ type: "switch",
71
+ required: true,
72
+ defaultValue: "active",
73
+
74
+ filterable: true,
75
+ options: STATUS_OPTIONS,
76
+ },
77
+ {
78
+ name: "createdAt",
79
+ label: "Ngày tạo",
80
+ type: "datetime",
81
+ hideInForm: true,
82
+
83
+ renderCell: (value) => {
84
+ return new Date(value as string).toLocaleDateString("vi-VN");
85
+ },
86
+ },
87
+ ],
88
+
89
+ filters: [
90
+ {
91
+ name: "search",
92
+ label: "Tìm kiếm",
93
+ type: "text",
94
+ field: "name",
95
+ operator: "contains",
96
+ },
97
+ {
98
+ name: "status",
99
+ label: "Trạng thái",
100
+ type: "checkbox",
101
+ field: "status",
102
+ operator: "in",
103
+ options: [
104
+ { label: "Hoạt động", value: "active" },
105
+ { label: "Không hoạt động", value: "inactive" },
106
+ ],
107
+ },
108
+ ],
109
+
110
+ permissions: {
111
+ create: true,
112
+ read: true,
113
+ update: true,
114
+ delete: true,
115
+ export: true,
116
+ import: true,
117
+ },
118
+
119
+ features: {
120
+ search: true,
121
+ bulkActions: true,
122
+ export: true,
123
+ import: true,
124
+ },
125
+ };
@@ -0,0 +1,12 @@
1
+ export const i18n = {
2
+ defaultLocale: "vi",
3
+ locales: ["vi", "en"],
4
+ localeDirection: {
5
+ vi: "ltr",
6
+ en: "ltr",
7
+ },
8
+ localeNames: {
9
+ vi: "vietnamese",
10
+ en: "english",
11
+ },
12
+ } as const;
@@ -0,0 +1,26 @@
1
+ // @goerp/core/configs
2
+ // Core configuration for GoERP platform
3
+ // Consolidated from packages/shared/configs
4
+
5
+ // Local data configs
6
+ export * from "./data/oauth-links";
7
+
8
+ // Inline configs
9
+ export * from "./i18n";
10
+ export * from "./themes";
11
+ export * from "./auth-routes";
12
+ export * from "./status";
13
+ export * from "./crud";
14
+
15
+ // Create locales export for backward compatibility
16
+ import { i18n as _i18n } from "./i18n";
17
+ export const locales = _i18n.locales;
18
+
19
+ // Re-exports with aliases for backward compatibility
20
+ export {
21
+ STATUS_COLORS as CONFIG_STATUS_COLORS,
22
+ STATUS_ACTIVE as CONFIG_STATUS_ACTIVE,
23
+ STATUS_INACTIVE as CONFIG_STATUS_INACTIVE,
24
+ STATUS_OPTIONS as CONFIG_STATUS_OPTIONS,
25
+ STATUS_VALUES as CONFIG_STATUS_VALUES,
26
+ } from "./status";
@@ -0,0 +1,25 @@
1
+ export const STATUS_ACTIVE = "active";
2
+ export const STATUS_INACTIVE = "inactive";
3
+
4
+ export const STATUS_VALUES = [STATUS_ACTIVE, STATUS_INACTIVE] as const;
5
+
6
+ export const STATUS_OPTIONS = [
7
+ { label: "crud.common.options.active", value: STATUS_ACTIVE },
8
+ { label: "crud.common.options.inactive", value: STATUS_INACTIVE },
9
+ ];
10
+
11
+ export const STATUS_COLORS: Record<
12
+ string,
13
+ "success" | "warning" | "default" | "destructive" | "secondary" | "outline"
14
+ > = {
15
+ [STATUS_ACTIVE]: "success",
16
+ [STATUS_INACTIVE]: "warning",
17
+ };
18
+
19
+ export function booleanToStatus(value: boolean): string {
20
+ return value ? STATUS_ACTIVE : STATUS_INACTIVE;
21
+ }
22
+
23
+ export function statusToBoolean(value: string): boolean {
24
+ return value === STATUS_ACTIVE;
25
+ }
@@ -0,0 +1,100 @@
1
+ export const radii = [0, 0.3, 0.5, 0.75, 1];
2
+
3
+ export const themes = {
4
+ zinc: {
5
+ label: "Zinc",
6
+ activeColor: {
7
+ light: "240 5.9% 10%",
8
+ dark: "240 5.2% 33.9%",
9
+ foreground: "0 0% 98%",
10
+ },
11
+ },
12
+ slate: {
13
+ label: "Slate",
14
+ activeColor: {
15
+ light: "215.4 16.3% 46.9%",
16
+ dark: "215.3 19.3% 34.5%",
17
+ foreground: "210 40% 98%",
18
+ },
19
+ },
20
+ stone: {
21
+ label: "Stone",
22
+ activeColor: {
23
+ light: "25 5.3% 44.7%",
24
+ dark: "33.3 5.5% 32.4%",
25
+ foreground: "60 9.1% 97.8%",
26
+ },
27
+ },
28
+ gray: {
29
+ label: "Gray",
30
+ activeColor: {
31
+ light: "220 8.9% 46.1%",
32
+ dark: "215 13.8% 34.1%",
33
+ foreground: "210 20% 98%",
34
+ },
35
+ },
36
+ neutral: {
37
+ label: "Neutral",
38
+ activeColor: {
39
+ light: "0 0% 45.1%",
40
+ dark: "0 0% 32.2%",
41
+ foreground: "0 0% 98%",
42
+ },
43
+ },
44
+ red: {
45
+ label: "Red",
46
+ activeColor: {
47
+ light: "0 72.2% 50.6%",
48
+ dark: "0 72.2% 50.6%",
49
+ foreground: "0 85.7% 97.3%",
50
+ },
51
+ },
52
+ rose: {
53
+ label: "Rose",
54
+ activeColor: {
55
+ light: "346.8 77.2% 49.8%",
56
+ dark: "346.8 77.2% 49.8%",
57
+ foreground: "355.7 100% 97.3%",
58
+ },
59
+ },
60
+ orange: {
61
+ label: "Orange",
62
+ activeColor: {
63
+ light: "24.6 95% 53.1%",
64
+ dark: "20.5 90.2% 48.2%",
65
+ foreground: "60 9.1% 97.8%",
66
+ },
67
+ },
68
+ green: {
69
+ label: "Green",
70
+ activeColor: {
71
+ light: "142.1 76.2% 36.3%",
72
+ dark: "142.1 70.6% 45.3%",
73
+ foreground: "355.7 100% 97.3%",
74
+ },
75
+ },
76
+ blue: {
77
+ label: "Blue",
78
+ activeColor: {
79
+ light: "221.2 83.2% 53.3%",
80
+ dark: "217.2 91.2% 59.8%",
81
+ foreground: "210 40% 98%",
82
+ },
83
+ },
84
+ yellow: {
85
+ label: "Yellow",
86
+ activeColor: {
87
+ light: "47.9 95.8% 53.1%",
88
+ dark: "47.9 95.8% 53.1%",
89
+ foreground: "26 83.3% 14.1%",
90
+ },
91
+ },
92
+ violet: {
93
+ label: "Violet",
94
+ activeColor: {
95
+ light: "262.1 83.3% 57.8%",
96
+ dark: "263.4 70% 50.4%",
97
+ foreground: "210 20% 98%",
98
+ },
99
+ },
100
+ };
@@ -0,0 +1,91 @@
1
+ "use client";
2
+
3
+ import { MoreHorizontal, Trash2 } from "lucide-react";
4
+
5
+ import type { CrudPermissions, EntityConfig } from "../../types";
6
+
7
+ import { Button } from "../../ui";
8
+ import {
9
+ DropdownMenu,
10
+ DropdownMenuContent,
11
+ DropdownMenuItem,
12
+ DropdownMenuSeparator,
13
+ DropdownMenuTrigger,
14
+ } from "../../ui/primitives/client";
15
+ import { useCrudContext } from "./crud-provider";
16
+
17
+ interface CrudBulkActionsProps {
18
+ config: EntityConfig;
19
+ permissions: CrudPermissions;
20
+ onDelete?: (rowIds: string[]) => void;
21
+ onExport?: (rowIds: string[]) => void;
22
+ }
23
+
24
+ export function CrudBulkActions({
25
+ config,
26
+ permissions,
27
+ onDelete,
28
+ onExport,
29
+ }: CrudBulkActionsProps) {
30
+ const { selectedRows, clearSelection, translations } = useCrudContext();
31
+
32
+ // Chỉ hiển thị bulk actions nếu selection column được bật
33
+ const showRowSelection = config.features?.showRowSelection !== false; // Default: true
34
+ if (!showRowSelection) {
35
+ return null;
36
+ }
37
+
38
+ const selectedCount = selectedRows.size;
39
+
40
+ if (selectedCount === 0) {
41
+ return null;
42
+ }
43
+
44
+ const selectedIds = Array.from(selectedRows);
45
+
46
+ // Translation fallbacks
47
+ const t = {
48
+ selected: "selected",
49
+ actions: translations.actions || "Actions",
50
+ exportSelected: "Export selected",
51
+ deleteSelected: translations.deleteSelected || "Delete selected",
52
+ };
53
+
54
+ return (
55
+ <div className="flex items-center gap-2">
56
+ <span className="text-sm text-muted-foreground">
57
+ {selectedCount} {t.selected}
58
+ </span>
59
+ <DropdownMenu>
60
+ <DropdownMenuTrigger asChild>
61
+ <Button variant="outline" size="sm">
62
+ <MoreHorizontal className="mr-2 h-4 w-4" />
63
+ {t.actions}
64
+ </Button>
65
+ </DropdownMenuTrigger>
66
+ <DropdownMenuContent>
67
+ {permissions.export && onExport && (
68
+ <DropdownMenuItem onClick={() => onExport(selectedIds)}>
69
+ {t.exportSelected}
70
+ </DropdownMenuItem>
71
+ )}
72
+ {permissions.delete && onDelete && (
73
+ <>
74
+ {permissions.export && <DropdownMenuSeparator />}
75
+ <DropdownMenuItem
76
+ onClick={() => {
77
+ onDelete(selectedIds);
78
+ clearSelection();
79
+ }}
80
+ className="text-destructive"
81
+ >
82
+ <Trash2 className="mr-2 h-4 w-4" />
83
+ {t.deleteSelected}
84
+ </DropdownMenuItem>
85
+ </>
86
+ )}
87
+ </DropdownMenuContent>
88
+ </DropdownMenu>
89
+ </div>
90
+ );
91
+ }
@@ -0,0 +1,241 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import {
5
+ getCoreRowModel,
6
+ getPaginationRowModel,
7
+ useReactTable,
8
+ } from "@tanstack/react-table";
9
+
10
+ import type { CrudPermissions, CrudResponse, EntityConfig } from "../../types";
11
+
12
+ import { isFieldVisibleInTable, sortFieldsByOrder } from "../lib/crud-utils";
13
+ import { formatFieldValue } from "../lib/field-formatter";
14
+
15
+ import { Badge } from "../../ui";
16
+ import { Card, CardContent, CardHeader } from "../../ui";
17
+ import { Checkbox } from "../../ui/primitives/client";
18
+ import { DataTablePagination } from "../../ui";
19
+ import { CrudEmptyState } from "./crud-empty-state";
20
+ import { useCrudConfig, useCrudSelection, useCrudState } from "./crud-context";
21
+ import { CrudRowActions } from "./crud-row-actions";
22
+ import { CrudTableSkeleton } from "./crud-table-skeleton";
23
+
24
+ interface CrudCardViewProps<TData = Record<string, unknown>> {
25
+ // ... existing props ...
26
+ config: EntityConfig; // Config is passed as prop here, but we should use context if possible or keep it consistent
27
+ data: CrudResponse<TData>;
28
+ permissions: CrudPermissions; // Permissions passed as prop
29
+ loading?: boolean;
30
+ onEdit?: (rowId: string, rowData?: Record<string, unknown>) => void;
31
+ onDelete?: (rowId: string) => void;
32
+ onCustomAction?: (
33
+ action: string,
34
+ rowId: string,
35
+ rowData: Record<string, unknown>,
36
+ ) => void | Promise<void>;
37
+ onEmptyStateAction?: {
38
+ onCreate?: () => void;
39
+ onClearSearch?: () => void;
40
+ onClearFilters?: () => void;
41
+ };
42
+ }
43
+
44
+ export function CrudCardView<TData extends Record<string, unknown>>({
45
+ config: propConfig, // Rename to avoid conflict if we use context, but here we might just use props as it was designed
46
+ data,
47
+ permissions: propPermissions,
48
+ loading = false,
49
+ onEdit,
50
+ onDelete,
51
+ onCustomAction,
52
+ onEmptyStateAction,
53
+ }: CrudCardViewProps<TData>) {
54
+ // ✅ All hooks must be called before any early returns
55
+ // Note: CrudCardView receives config and permissions as props, so we might not need useCrudConfig
56
+ // But to be consistent with Context Splitting, we should use what we need.
57
+ // However, the original code used props for config/permissions.
58
+ // Let's stick to using the hooks for state and selection.
59
+
60
+ const { selectedRows, toggleRowSelection } = useCrudSelection();
61
+ const { search, filters, clearFilters, setSearch, pagination } =
62
+ useCrudState();
63
+
64
+ // Use props for config/permissions as they are passed down
65
+ const config = propConfig;
66
+ const permissions = propPermissions;
67
+
68
+ // Create a minimal table instance for pagination
69
+ // Always call this hook, even when loading or empty data
70
+ const table = useReactTable({
71
+ data: data.data || [],
72
+ columns: [],
73
+ getCoreRowModel: getCoreRowModel(),
74
+ getPaginationRowModel: getPaginationRowModel(),
75
+ pageCount: Math.ceil((data.total || 0) / (data.pageSize || 10)),
76
+ state: {
77
+ pagination: {
78
+ pageIndex: (data.page || 1) - 1,
79
+ pageSize: data.pageSize || 10,
80
+ },
81
+ },
82
+ manualPagination: true,
83
+ });
84
+
85
+ // Get visible fields (not hidden in table) - sort by order first
86
+ const visibleFields = sortFieldsByOrder(config.fields).filter(
87
+ (field) => !field.hideInTable && field.name !== config.idField,
88
+ );
89
+
90
+ // Get primary field (displayField) and secondary fields
91
+ const primaryField = config.fields.find(
92
+ (f) => f.name === config.displayField,
93
+ );
94
+ const secondaryFields = visibleFields
95
+ .filter((f) => f.name !== config.displayField)
96
+ .slice(0, 3); // Show max 3 secondary fields
97
+
98
+ if (loading) {
99
+ return (
100
+ <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
101
+ {Array.from({ length: 6 }).map((_, index) => (
102
+ <Card key={`skeleton-card-${index}`} className="animate-pulse">
103
+ <CardHeader className="pb-3">
104
+ <div className="flex items-start gap-2">
105
+ {config.features?.showRowSelection !== false && (
106
+ <div className="h-4 w-4 bg-muted rounded shrink-0 mt-0.5" />
107
+ )}
108
+ <div className="flex-1 space-y-2">
109
+ <div className="h-4 w-3/4 bg-muted rounded" />
110
+ <div className="h-3 w-1/2 bg-muted rounded" />
111
+ </div>
112
+ </div>
113
+ </CardHeader>
114
+ <CardContent className="pt-0">
115
+ <div className="space-y-2">
116
+ <div className="h-4 w-full bg-muted rounded" />
117
+ <div className="h-4 w-2/3 bg-muted rounded" />
118
+ </div>
119
+ </CardContent>
120
+ </Card>
121
+ ))}
122
+ </div>
123
+ );
124
+ }
125
+
126
+ if (!data.data || data.data.length === 0) {
127
+ return (
128
+ <div className="min-h-[400px]">
129
+ <CrudEmptyState
130
+ config={config}
131
+ hasSearch={!!search && search.trim().length > 0}
132
+ hasFilters={filters.length > 0}
133
+ onClearSearch={() => setSearch("")}
134
+ onClearFilters={clearFilters}
135
+ onCreate={onEmptyStateAction?.onCreate}
136
+ canCreate={permissions.create}
137
+ />
138
+ </div>
139
+ );
140
+ }
141
+
142
+ return (
143
+ <div className="space-y-4">
144
+ <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
145
+ {data.data.map((row) => {
146
+ const rowId = String(row[config.idField]);
147
+ const isSelected = selectedRows.has(rowId);
148
+ const primaryValue = row[config.displayField];
149
+ const primaryLabel = primaryField?.label || config.displayField;
150
+
151
+ return (
152
+ <Card
153
+ key={rowId}
154
+ className={`transition-all duration-150 hover:shadow-md ${
155
+ isSelected ? "ring-2 ring-primary" : ""
156
+ }`}
157
+ >
158
+ <CardHeader className="pb-3">
159
+ <div className="flex items-start justify-between gap-2">
160
+ <div className="flex items-start gap-2 flex-1 min-w-0">
161
+ {config.features?.showRowSelection !== false && (
162
+ <Checkbox
163
+ checked={isSelected}
164
+ onCheckedChange={() => toggleRowSelection(rowId)}
165
+ className="mt-0.5 shrink-0"
166
+ aria-label={`Select ${primaryValue}`}
167
+ />
168
+ )}
169
+ <div className="flex-1 min-w-0">
170
+ <h3 className="font-semibold text-sm truncate">
171
+ {primaryField?.renderCell
172
+ ? (primaryField.renderCell(primaryValue, row) as any)
173
+ : primaryField
174
+ ? formatFieldValue(primaryValue, primaryField)
175
+ : String(primaryValue ?? "")}
176
+ </h3>
177
+ {primaryField?.description && (
178
+ <p className="text-xs text-muted-foreground mt-0.5">
179
+ {primaryField.description}
180
+ </p>
181
+ )}
182
+ </div>
183
+ </div>
184
+ {(permissions.update ||
185
+ permissions.delete ||
186
+ (config.rowActions && config.rowActions.length > 0)) && (
187
+ <CrudRowActions
188
+ rowId={rowId}
189
+ rowData={row as Record<string, unknown>}
190
+ config={config}
191
+ permissions={permissions}
192
+ onEdit={onEdit}
193
+ onDelete={onDelete}
194
+ onCustomAction={onCustomAction}
195
+ />
196
+ )}
197
+ </div>
198
+ </CardHeader>
199
+ <CardContent className="pt-0">
200
+ <div className="space-y-2">
201
+ {secondaryFields.map((field) => {
202
+ const value = row[field.name];
203
+ if (value === null || value === undefined || value === "") {
204
+ return null;
205
+ }
206
+
207
+ return (
208
+ <div
209
+ key={field.name}
210
+ className="flex items-start gap-2 text-sm"
211
+ >
212
+ <span className="text-muted-foreground font-medium shrink-0 min-w-[80px]">
213
+ {field.label}:
214
+ </span>
215
+ <span className="text-foreground flex-1 break-words">
216
+ {field.renderCell
217
+ ? (field.renderCell(value, row) as any)
218
+ : formatFieldValue(value, field)}
219
+ </span>
220
+ </div>
221
+ );
222
+ })}
223
+ </div>
224
+ </CardContent>
225
+ </Card>
226
+ );
227
+ })}
228
+ </div>
229
+
230
+ {/* Pagination Section */}
231
+ <div className="border-t bg-muted/30 px-4 sm:px-6 py-3">
232
+ <DataTablePagination
233
+ table={table}
234
+ totalItems={data.total}
235
+ currentPage={pagination.page}
236
+ pageSize={pagination.pageSize}
237
+ />
238
+ </div>
239
+ </div>
240
+ );
241
+ }