@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,299 @@
1
+ import { branchSchema, branchUpdateSchema } from "../schemas";
2
+
3
+ export interface BranchRecord {
4
+ id: string;
5
+ companyId?: string;
6
+ code: string;
7
+ name: string;
8
+ address?: string | null;
9
+ phone?: string | null;
10
+ email?: string | null;
11
+ status?: string;
12
+ company?: { id: string; name: string };
13
+ }
14
+
15
+ export interface BranchDbClient {
16
+ branch: {
17
+ count: (args: { where?: Record<string, unknown> }) => Promise<number>;
18
+ findMany: (args: {
19
+ where?: Record<string, unknown>;
20
+ orderBy?: Record<string, unknown>;
21
+ skip?: number;
22
+ take?: number;
23
+ include?: Record<string, unknown>;
24
+ }) => Promise<BranchRecord[]>;
25
+ findUnique: (args: {
26
+ where: { id?: string; code?: string };
27
+ include?: Record<string, unknown>;
28
+ }) => Promise<BranchRecord | null>;
29
+ create: (args: {
30
+ data: Record<string, unknown>;
31
+ include?: Record<string, unknown>;
32
+ }) => Promise<BranchRecord>;
33
+ update: (args: {
34
+ where: { id: string };
35
+ data: Record<string, unknown>;
36
+ include?: Record<string, unknown>;
37
+ }) => Promise<BranchRecord>;
38
+ delete: (args: { where: { id: string } }) => Promise<BranchRecord>;
39
+ };
40
+ company: {
41
+ findUnique: (args: {
42
+ where: { id: string };
43
+ }) => Promise<{ id: string } | null>;
44
+ };
45
+ }
46
+
47
+ export interface BranchListParams {
48
+ page?: number;
49
+ pageSize?: number;
50
+ search?: string | null;
51
+ companyId?: string | null;
52
+ status?: string | null;
53
+ }
54
+
55
+ export interface BranchListResponse {
56
+ data: BranchRecord[];
57
+ pagination: {
58
+ page: number;
59
+ pageSize: number;
60
+ total: number;
61
+ totalPages: number;
62
+ };
63
+ }
64
+
65
+ export class BranchServiceError extends Error {
66
+ status: number;
67
+ field?: string;
68
+ details?: unknown;
69
+
70
+ constructor(
71
+ message: string,
72
+ status: number,
73
+ options?: { field?: string; details?: unknown },
74
+ ) {
75
+ super(message);
76
+ this.name = "BranchServiceError";
77
+ this.status = status;
78
+ this.field = options?.field;
79
+ this.details = options?.details;
80
+ }
81
+ }
82
+
83
+ const BRANCH_INCLUDE = {
84
+ company: {
85
+ select: { id: true, name: true },
86
+ },
87
+ };
88
+
89
+ const ensureUserId = (userId?: string) => {
90
+ if (!userId) {
91
+ throw new BranchServiceError("Unauthorized", 401);
92
+ }
93
+ };
94
+
95
+ export async function listBranches(
96
+ db: BranchDbClient,
97
+ params: BranchListParams,
98
+ ): Promise<BranchListResponse> {
99
+ const page = Number(params.page || 1);
100
+ const pageSize = Math.min(Number(params.pageSize || 10), 100);
101
+ const skip = (page - 1) * pageSize;
102
+
103
+ const search = params.search?.trim() || undefined;
104
+ const companyId = params.companyId?.trim() || undefined;
105
+ const status = params.status?.trim() || undefined;
106
+
107
+ const where: Record<string, unknown> = {};
108
+
109
+ if (search) {
110
+ where.OR = [
111
+ { name: { contains: search, mode: "insensitive" } },
112
+ { code: { contains: search, mode: "insensitive" } },
113
+ { email: { contains: search, mode: "insensitive" } },
114
+ ];
115
+ }
116
+
117
+ if (companyId) {
118
+ where.companyId = companyId;
119
+ }
120
+
121
+ if (status) {
122
+ where.status = status;
123
+ }
124
+
125
+ // ⚡ Bolt: Run count and findMany concurrently to reduce latency
126
+ const [total, data] = await Promise.all([
127
+ db.branch.count({ where }),
128
+ db.branch.findMany({
129
+ where,
130
+ orderBy: { name: "asc" },
131
+ skip,
132
+ take: pageSize,
133
+ include: BRANCH_INCLUDE,
134
+ }),
135
+ ]);
136
+
137
+ return {
138
+ data,
139
+ pagination: {
140
+ page,
141
+ pageSize,
142
+ total,
143
+ totalPages: Math.ceil(total / pageSize),
144
+ },
145
+ };
146
+ }
147
+
148
+ export async function getBranchById(
149
+ db: BranchDbClient,
150
+ id: string,
151
+ ): Promise<BranchRecord> {
152
+ const branch = await db.branch.findUnique({
153
+ where: { id },
154
+ include: BRANCH_INCLUDE,
155
+ });
156
+
157
+ if (!branch) {
158
+ throw new BranchServiceError("Chi nhánh không tồn tại", 404);
159
+ }
160
+
161
+ return branch;
162
+ }
163
+
164
+ export async function createBranch(
165
+ db: BranchDbClient,
166
+ input: unknown,
167
+ userId?: string,
168
+ ): Promise<BranchRecord> {
169
+ ensureUserId(userId);
170
+
171
+ const result = branchSchema.safeParse(input);
172
+ if (!result.success) {
173
+ const errors = result.error.issues || [];
174
+ const firstError = errors[0];
175
+ throw new BranchServiceError(
176
+ firstError?.message || "Validation error",
177
+ 400,
178
+ {
179
+ field: firstError?.path?.join("."),
180
+ details: errors,
181
+ },
182
+ );
183
+ }
184
+
185
+ const validData = result.data;
186
+
187
+ const existing = await db.branch.findUnique({
188
+ where: { code: validData.code },
189
+ });
190
+
191
+ if (existing) {
192
+ throw new BranchServiceError("Mã chi nhánh đã tồn tại", 400, {
193
+ field: "code",
194
+ });
195
+ }
196
+
197
+ const company = await db.company.findUnique({
198
+ where: { id: validData.companyId },
199
+ });
200
+
201
+ if (!company) {
202
+ throw new BranchServiceError("Công ty không tồn tại", 400, {
203
+ field: "companyId",
204
+ });
205
+ }
206
+
207
+ return db.branch.create({
208
+ data: {
209
+ id: crypto.randomUUID(),
210
+ companyId: validData.companyId,
211
+ code: validData.code,
212
+ name: validData.name,
213
+ address: validData.address,
214
+ phone: validData.phone,
215
+ email: validData.email,
216
+ status: validData.status,
217
+ createdBy: userId,
218
+ updatedAt: new Date(),
219
+ updatedBy: userId,
220
+ },
221
+ include: BRANCH_INCLUDE,
222
+ });
223
+ }
224
+
225
+ export async function updateBranch(
226
+ db: BranchDbClient,
227
+ id: string,
228
+ input: unknown,
229
+ userId?: string,
230
+ ): Promise<BranchRecord> {
231
+ ensureUserId(userId);
232
+
233
+ const result = branchUpdateSchema.safeParse(input);
234
+ if (!result.success) {
235
+ const errors = result.error.issues || [];
236
+ const firstError = errors[0];
237
+ throw new BranchServiceError(
238
+ firstError?.message || "Validation error",
239
+ 400,
240
+ {
241
+ field: firstError?.path?.join("."),
242
+ details: errors,
243
+ },
244
+ );
245
+ }
246
+
247
+ const validData = result.data;
248
+ const existingBranch = await db.branch.findUnique({
249
+ where: { id },
250
+ });
251
+
252
+ if (!existingBranch) {
253
+ throw new BranchServiceError("Chi nhánh không tồn tại", 404);
254
+ }
255
+
256
+ if (validData.code && validData.code !== existingBranch.code) {
257
+ const duplicate = await db.branch.findUnique({
258
+ where: { code: validData.code },
259
+ });
260
+ if (duplicate) {
261
+ throw new BranchServiceError("Mã chi nhánh đã tồn tại", 400, {
262
+ field: "code",
263
+ });
264
+ }
265
+ }
266
+
267
+ if (validData.companyId) {
268
+ const company = await db.company.findUnique({
269
+ where: { id: validData.companyId },
270
+ });
271
+ if (!company) {
272
+ throw new BranchServiceError("Công ty không tồn tại", 400, {
273
+ field: "companyId",
274
+ });
275
+ }
276
+ }
277
+
278
+ return db.branch.update({
279
+ where: { id },
280
+ data: {
281
+ ...validData,
282
+ updatedAt: new Date(),
283
+ updatedBy: userId,
284
+ },
285
+ include: BRANCH_INCLUDE,
286
+ });
287
+ }
288
+
289
+ export async function deleteBranch(
290
+ db: BranchDbClient,
291
+ id: string,
292
+ ): Promise<BranchRecord> {
293
+ const branch = await db.branch.findUnique({ where: { id } });
294
+ if (!branch) {
295
+ throw new BranchServiceError("Chi nhánh không tồn tại", 404);
296
+ }
297
+
298
+ return db.branch.delete({ where: { id } });
299
+ }
@@ -0,0 +1,154 @@
1
+ import { GitBranch } from "lucide-react";
2
+
3
+ import type { EntityConfig } from "../types";
4
+
5
+ import { STATUS_OPTIONS } from "../configs/status";
6
+
7
+ export const branchesConfig: EntityConfig = {
8
+ name: "branch",
9
+ permissionResource: "branch",
10
+ label: "Chi nhánh",
11
+ pluralLabel: "Danh sách chi nhánh",
12
+ icon: GitBranch,
13
+ description: "Quản lý danh sách chi nhánh",
14
+ apiEndpoint: "/api/branches",
15
+ idField: "id",
16
+ displayField: "name",
17
+
18
+ fields: [
19
+ {
20
+ name: "id",
21
+ label: "ID",
22
+ type: "text",
23
+ hideInForm: true,
24
+ hideInTable: true,
25
+ },
26
+ {
27
+ name: "companyId",
28
+ label: "Công ty",
29
+ type: "select",
30
+ required: true,
31
+ placeholder: "Chọn công ty",
32
+ filterable: true,
33
+ dataSource: {
34
+ type: "api",
35
+ endpoint: "/api/companies",
36
+ labelField: "name",
37
+ valueField: "id",
38
+ },
39
+ },
40
+ {
41
+ name: "code",
42
+ label: "Mã chi nhánh",
43
+ type: "text",
44
+ required: true,
45
+ placeholder: "Nhập mã chi nhánh",
46
+ filterable: true,
47
+ },
48
+ {
49
+ name: "name",
50
+ label: "Tên chi nhánh",
51
+ type: "text",
52
+ required: true,
53
+ placeholder: "Nhập tên chi nhánh",
54
+ filterable: true,
55
+ },
56
+ {
57
+ name: "address",
58
+ label: "Địa chỉ",
59
+ type: "textarea",
60
+ required: false,
61
+ placeholder: "Nhập địa chỉ",
62
+ rows: 2,
63
+ },
64
+ {
65
+ name: "phone",
66
+ label: "Số điện thoại",
67
+ type: "text",
68
+ required: false,
69
+ placeholder: "Nhập số điện thoại",
70
+ },
71
+ {
72
+ name: "email",
73
+ label: "Email",
74
+ type: "email",
75
+ required: false,
76
+ placeholder: "Nhập email",
77
+ },
78
+ {
79
+ name: "status",
80
+ label: "Trạng thái",
81
+ type: "switch",
82
+ required: true,
83
+ defaultValue: "active",
84
+ filterable: true,
85
+ options: STATUS_OPTIONS,
86
+ },
87
+ {
88
+ name: "createdAt",
89
+ label: "Ngày tạo",
90
+ type: "datetime",
91
+ hideInForm: true,
92
+ renderCell: (value) => {
93
+ return new Date(value as string).toLocaleDateString("vi-VN");
94
+ },
95
+ },
96
+ {
97
+ name: "updatedAt",
98
+ label: "Ngày cập nhật",
99
+ type: "datetime",
100
+ hideInForm: true,
101
+ hideInTable: true,
102
+ },
103
+ ],
104
+
105
+ filters: [
106
+ {
107
+ name: "search",
108
+ label: "Tìm kiếm",
109
+ type: "text",
110
+ field: "name",
111
+ operator: "contains",
112
+ },
113
+ {
114
+ name: "companyId",
115
+ label: "Công ty",
116
+ type: "select",
117
+ field: "companyId",
118
+ operator: "eq",
119
+ dataSource: {
120
+ type: "api",
121
+ endpoint: "/api/companies",
122
+ labelField: "name",
123
+ valueField: "id",
124
+ },
125
+ },
126
+ {
127
+ name: "status",
128
+ label: "Trạng thái",
129
+ type: "checkbox",
130
+ field: "status",
131
+ operator: "in",
132
+ options: [
133
+ { label: "Hoạt động", value: "active" },
134
+ { label: "Ngừng hoạt động", value: "inactive" },
135
+ ],
136
+ },
137
+ ],
138
+
139
+ permissions: {
140
+ create: true,
141
+ read: true,
142
+ update: true,
143
+ delete: true,
144
+ export: true,
145
+ import: false,
146
+ },
147
+
148
+ features: {
149
+ search: true,
150
+ bulkActions: true,
151
+ export: true,
152
+ import: false,
153
+ },
154
+ };
@@ -0,0 +1,5 @@
1
+ // @goerp/core/organization
2
+ // Organization shared module
3
+
4
+ export * from "./branches.config";
5
+ export * from "./branch-service";
@@ -0,0 +1,97 @@
1
+ // @goerp/core/plugin
2
+ // AppsRegistry - Central registry for GoerpApp instances
3
+
4
+ import type { EntityConfig, NavigationType } from "../types"
5
+
6
+ import type { GoerpApp } from "./types"
7
+
8
+ /**
9
+ * AppsRegistry - Manages registration and lookup of GoerpApp
10
+ * Host app registers installed apps; registry merges navigation and entity configs
11
+ */
12
+ export class AppsRegistry {
13
+ private apps: GoerpApp[] = []
14
+ private appsById = new Map<string, GoerpApp>()
15
+
16
+ /**
17
+ * Register an app. Later registrations override earlier entity configs for same entity.
18
+ */
19
+ register(app: GoerpApp): void {
20
+ if (this.appsById.has(app.appId)) {
21
+ console.warn(`[AppsRegistry] App "${app.appId}" already registered. Replacing.`)
22
+ }
23
+ this.appsById.set(app.appId, app)
24
+ this.apps = Array.from(this.appsById.values())
25
+ }
26
+
27
+ /**
28
+ * Register multiple apps in order
29
+ */
30
+ registerAll(apps: GoerpApp[]): void {
31
+ for (const app of apps) {
32
+ this.register(app)
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Get app by appId
38
+ */
39
+ getApp(appId: string): GoerpApp | undefined {
40
+ return this.appsById.get(appId)
41
+ }
42
+
43
+ /**
44
+ * Get all registered apps
45
+ */
46
+ getAllApps(): GoerpApp[] {
47
+ return [...this.apps]
48
+ }
49
+
50
+ /**
51
+ * Get merged navigation from all apps (order: registration order)
52
+ * Groups with same title have their items merged
53
+ */
54
+ getNavigation(): NavigationType[] {
55
+ const byTitle = new Map<string, NavigationType>()
56
+
57
+ for (const app of this.apps) {
58
+ for (const group of app.navigation) {
59
+ const existing = byTitle.get(group.title)
60
+ const items = group.items ?? []
61
+ if (existing) {
62
+ existing.items = [...(existing.items ?? []), ...items]
63
+ } else {
64
+ byTitle.set(group.title, { ...group, items: [...items] })
65
+ }
66
+ }
67
+ }
68
+ return Array.from(byTitle.values())
69
+ }
70
+
71
+ /**
72
+ * Get entity config for entity key.
73
+ * Later-registered apps override earlier for same entity.
74
+ */
75
+ getEntityConfig(entity: string): EntityConfig | undefined {
76
+ for (let i = this.apps.length - 1; i >= 0; i--) {
77
+ const config = this.apps[i].entityConfigs[entity]
78
+ if (config) return config
79
+ }
80
+ return undefined
81
+ }
82
+
83
+ /**
84
+ * Check if entity exists in any app
85
+ */
86
+ hasEntity(entity: string): boolean {
87
+ return this.getEntityConfig(entity) !== undefined
88
+ }
89
+
90
+ /**
91
+ * Clear all registrations (for testing)
92
+ */
93
+ clear(): void {
94
+ this.apps = []
95
+ this.appsById.clear()
96
+ }
97
+ }
@@ -0,0 +1,5 @@
1
+ // @goerp/core/plugin
2
+ // GoerpApp API - Plugin/App types and registry
3
+
4
+ export { AppsRegistry } from "./apps-registry"
5
+ export type { GoerpApp, RouteDefinition } from "./types"
@@ -0,0 +1,41 @@
1
+ // @goerp/core/plugin
2
+ // GoerpApp types - maps to AppDefinition in core-db
3
+
4
+ import type { ComponentType } from "react"
5
+
6
+ import type { EntityConfig, NavigationType } from "../types"
7
+
8
+ /**
9
+ * Route definition for /app/[appId]/[pageId]
10
+ * Used when an app has custom pages beyond CRUD
11
+ */
12
+ export interface RouteDefinition {
13
+ pageId: string
14
+ label: string
15
+ path: string
16
+ component: ComponentType<Record<string, unknown>>
17
+ permission?: string
18
+ }
19
+
20
+ /**
21
+ * GoerpApp - Plugin/App descriptor
22
+ * Maps to AppDefinition.appId in core-db
23
+ */
24
+ export interface GoerpApp {
25
+ /** Unique app identifier - maps to AppDefinition.appId */
26
+ appId: string
27
+ /** Display name */
28
+ name: string
29
+ /** Semantic version */
30
+ version: string
31
+ /** Human-readable description */
32
+ description?: string
33
+ /** Core system app (always enabled) */
34
+ isCore?: boolean
35
+ /** Navigation items for sidebar */
36
+ navigation: NavigationType[]
37
+ /** Entity configs for CRUD (/crud/[entity]) */
38
+ entityConfigs: Record<string, EntityConfig>
39
+ /** Custom routes for /app/[appId]/[pageId] */
40
+ routes?: RouteDefinition[]
41
+ }
@@ -0,0 +1,109 @@
1
+ // @goerp/core/providers
2
+ // Core React context providers for GoERP platform
3
+ // Consolidated from packages/shared/providers
4
+
5
+ "use client";
6
+
7
+ import * as React from "react";
8
+ import { createContext, useCallback, useEffect, useState } from "react";
9
+ import { useCookie } from "react-use";
10
+ import { DirectionProvider as RadixDirectionProvider } from "@radix-ui/react-direction";
11
+
12
+ import type { LocaleType, SettingsType, DirectionType } from "../types";
13
+ import type { ReactNode } from "react";
14
+
15
+ // ============================================================================
16
+ // Settings Provider
17
+ // ============================================================================
18
+
19
+ export const defaultSettings: SettingsType = {
20
+ theme: "blue",
21
+ mode: "system",
22
+ radius: 0.5,
23
+ layout: "vertical",
24
+ locale: "vi",
25
+ sidebarVariant: "sidebar",
26
+ sidebarCollapsible: "icon",
27
+ density: "comfortable",
28
+ };
29
+
30
+ export const SettingsContext = createContext<
31
+ | {
32
+ settings: SettingsType;
33
+ updateSettings: (newSettings: SettingsType) => void;
34
+ resetSettings: () => void;
35
+ }
36
+ | undefined
37
+ >(undefined);
38
+
39
+ export function SettingsProvider({
40
+ locale,
41
+ children,
42
+ }: {
43
+ locale: LocaleType;
44
+ children: ReactNode;
45
+ }) {
46
+ const [storedSettings, setStoredSettings, deleteStoredSettings] =
47
+ useCookie("settings");
48
+ const [settings, setSettings] = useState<SettingsType>(() => ({
49
+ ...defaultSettings,
50
+ locale,
51
+ }));
52
+
53
+ useEffect(() => {
54
+ if (storedSettings) {
55
+ try {
56
+ const parsedSettings = JSON.parse(storedSettings);
57
+ setSettings({ ...defaultSettings, ...parsedSettings });
58
+ } catch {
59
+ setSettings({ ...defaultSettings, locale });
60
+ }
61
+ } else {
62
+ setSettings({ ...defaultSettings, locale });
63
+ }
64
+ }, [storedSettings, locale]);
65
+
66
+ const updateSettings = useCallback(
67
+ (newSettings: SettingsType) => {
68
+ setStoredSettings(JSON.stringify(newSettings));
69
+ setSettings(newSettings);
70
+ },
71
+ [setStoredSettings],
72
+ );
73
+
74
+ const resetSettings = useCallback(() => {
75
+ deleteStoredSettings();
76
+ setSettings(defaultSettings);
77
+ }, [deleteStoredSettings]);
78
+
79
+ return (
80
+ <SettingsContext.Provider
81
+ value={{ settings, updateSettings, resetSettings }}
82
+ >
83
+ {children}
84
+ </SettingsContext.Provider>
85
+ );
86
+ }
87
+
88
+ // ============================================================================
89
+ // Direction Provider
90
+ // ============================================================================
91
+
92
+ interface DirectionProviderProps {
93
+ direction: DirectionType;
94
+ children: React.ReactNode;
95
+ }
96
+
97
+ export function DirectionProvider({
98
+ direction,
99
+ children,
100
+ }: DirectionProviderProps) {
101
+ return (
102
+ <RadixDirectionProvider dir={direction}>{children}</RadixDirectionProvider>
103
+ );
104
+ }
105
+ // ============================================================================
106
+ // Tenant Provider
107
+ // ============================================================================
108
+
109
+ export * from "./tenant-provider";