create-lego-one 2.0.10 → 2.0.12

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 (171) hide show
  1. package/dist/index.cjs +145 -0
  2. package/dist/index.cjs.map +1 -1
  3. package/package.json +5 -3
  4. package/template/host/e2e/auth.spec.ts +38 -0
  5. package/template/host/e2e/layout.spec.ts +38 -0
  6. package/template/host/modern.config.ts +19 -0
  7. package/template/host/package.json +71 -0
  8. package/template/host/playwright.config.ts +34 -0
  9. package/template/host/postcss.config.mjs +6 -0
  10. package/template/host/src/App.tsx +6 -0
  11. package/template/host/src/bootstrap.tsx +74 -0
  12. package/template/host/src/global.css +59 -0
  13. package/template/host/src/index.ts +2 -0
  14. package/template/host/src/kernel/__tests__/lib-utils.test.ts +32 -0
  15. package/template/host/src/kernel/__tests__/rbac-hooks.test.tsx +114 -0
  16. package/template/host/src/kernel/__tests__/rbac-utils.test.ts +108 -0
  17. package/template/host/src/kernel/auth/ProtectedRoute.tsx +41 -0
  18. package/template/host/src/kernel/auth/components/LoginForm.tsx +97 -0
  19. package/template/host/src/kernel/auth/components/LogoutButton.tsx +79 -0
  20. package/template/host/src/kernel/auth/hooks.ts +174 -0
  21. package/template/host/src/kernel/auth/index.ts +5 -0
  22. package/template/host/src/kernel/auth/schemas.ts +27 -0
  23. package/template/host/src/kernel/auth/service.ts +197 -0
  24. package/template/host/src/kernel/auth/types.ts +36 -0
  25. package/template/host/src/kernel/channels/ChannelBus.ts +181 -0
  26. package/template/host/src/kernel/channels/ChannelProvider.tsx +57 -0
  27. package/template/host/src/kernel/channels/events.ts +27 -0
  28. package/template/host/src/kernel/channels/hooks.ts +168 -0
  29. package/template/host/src/kernel/channels/index.ts +6 -0
  30. package/template/host/src/kernel/channels/integrations/ToastIntegration.tsx +60 -0
  31. package/template/host/src/kernel/channels/plugin-hooks.ts +72 -0
  32. package/template/host/src/kernel/channels/types.ts +112 -0
  33. package/template/host/src/kernel/components/__tests__/Badge.test.tsx +35 -0
  34. package/template/host/src/kernel/components/__tests__/Button.test.tsx +63 -0
  35. package/template/host/src/kernel/components/__tests__/Input.test.tsx +64 -0
  36. package/template/host/src/kernel/components/index.ts +32 -0
  37. package/template/host/src/kernel/components/ui/alert.tsx +58 -0
  38. package/template/host/src/kernel/components/ui/avatar.tsx +47 -0
  39. package/template/host/src/kernel/components/ui/badge.tsx +35 -0
  40. package/template/host/src/kernel/components/ui/button.tsx +50 -0
  41. package/template/host/src/kernel/components/ui/card.tsx +78 -0
  42. package/template/host/src/kernel/components/ui/dialog.tsx +116 -0
  43. package/template/host/src/kernel/components/ui/dropdown-menu.tsx +192 -0
  44. package/template/host/src/kernel/components/ui/index.ts +7 -0
  45. package/template/host/src/kernel/components/ui/input.tsx +24 -0
  46. package/template/host/src/kernel/components/ui/label.tsx +21 -0
  47. package/template/host/src/kernel/components/ui/popover.tsx +28 -0
  48. package/template/host/src/kernel/components/ui/progress.tsx +25 -0
  49. package/template/host/src/kernel/components/ui/scroll-area.tsx +45 -0
  50. package/template/host/src/kernel/components/ui/select.tsx +155 -0
  51. package/template/host/src/kernel/components/ui/separator.tsx +28 -0
  52. package/template/host/src/kernel/components/ui/skeleton.tsx +15 -0
  53. package/template/host/src/kernel/components/ui/switch.tsx +26 -0
  54. package/template/host/src/kernel/components/ui/table.tsx +116 -0
  55. package/template/host/src/kernel/components/ui/tabs.tsx +52 -0
  56. package/template/host/src/kernel/components/ui/toast.tsx +126 -0
  57. package/template/host/src/kernel/components/ui/toaster.tsx +34 -0
  58. package/template/host/src/kernel/components/ui/tooltip.tsx +27 -0
  59. package/template/host/src/kernel/components/ui/use-toast.ts +183 -0
  60. package/template/host/src/kernel/index.ts +48 -0
  61. package/template/host/src/kernel/lib/cn.ts +1 -0
  62. package/template/host/src/kernel/lib/utils.ts +36 -0
  63. package/template/host/src/kernel/plugins/Slot.tsx +41 -0
  64. package/template/host/src/kernel/plugins/SlotProvider.tsx +88 -0
  65. package/template/host/src/kernel/plugins/index.ts +23 -0
  66. package/template/host/src/kernel/plugins/loader.ts +122 -0
  67. package/template/host/src/kernel/plugins/schemas.ts +54 -0
  68. package/template/host/src/kernel/plugins/store.ts +185 -0
  69. package/template/host/src/kernel/plugins/types.ts +103 -0
  70. package/template/host/src/kernel/providers/PocketBaseProvider.tsx +70 -0
  71. package/template/host/src/kernel/providers/QueryProvider.tsx +28 -0
  72. package/template/host/src/kernel/providers/ThemeProvider.tsx +25 -0
  73. package/template/host/src/kernel/providers/index.ts +3 -0
  74. package/template/host/src/kernel/rbac/components/OrganizationSelector.tsx +69 -0
  75. package/template/host/src/kernel/rbac/components/PermissionGate.tsx +43 -0
  76. package/template/host/src/kernel/rbac/hooks.ts +379 -0
  77. package/template/host/src/kernel/rbac/index.ts +6 -0
  78. package/template/host/src/kernel/rbac/service.ts +504 -0
  79. package/template/host/src/kernel/rbac/types.ts +164 -0
  80. package/template/host/src/kernel/rbac/utils.ts +34 -0
  81. package/template/host/src/kernel/shared-state/bridge.ts +31 -0
  82. package/template/host/src/kernel/shared-state/index.ts +3 -0
  83. package/template/host/src/kernel/shared-state/store.ts +62 -0
  84. package/template/host/src/kernel/shared-state/types.ts +60 -0
  85. package/template/host/src/kernel/use-migrations.ts +72 -0
  86. package/template/host/src/layout/MobileMenu.tsx +61 -0
  87. package/template/host/src/layout/Shell.tsx +42 -0
  88. package/template/host/src/layout/Sidebar.tsx +178 -0
  89. package/template/host/src/layout/Topbar.tsx +50 -0
  90. package/template/host/src/layout/index.ts +4 -0
  91. package/template/host/src/lib/pocketbase/client.ts +38 -0
  92. package/template/host/src/lib/pocketbase/collections/audit_logs.ts +87 -0
  93. package/template/host/src/lib/pocketbase/collections/index.ts +19 -0
  94. package/template/host/src/lib/pocketbase/collections/organizations.ts +63 -0
  95. package/template/host/src/lib/pocketbase/collections/permissions.ts +57 -0
  96. package/template/host/src/lib/pocketbase/collections/roles.ts +55 -0
  97. package/template/host/src/lib/pocketbase/collections/todos.ts +74 -0
  98. package/template/host/src/lib/pocketbase/collections/user_roles.ts +57 -0
  99. package/template/host/src/lib/pocketbase/collections/users.ts +43 -0
  100. package/template/host/src/lib/pocketbase/index.ts +5 -0
  101. package/template/host/src/lib/pocketbase/migrations.ts +44 -0
  102. package/template/host/src/lib/pocketbase/seed/permissions.ts +8 -0
  103. package/template/host/src/lib/pocketbase/seed/roles.ts +22 -0
  104. package/template/host/src/lib/pocketbase/seed.ts +113 -0
  105. package/template/host/src/lib/pocketbase/types.ts +102 -0
  106. package/template/host/src/modern.runtime.ts +26 -0
  107. package/template/host/src/plugins.d.ts +9 -0
  108. package/template/host/src/providers/PocketBaseProvider.tsx +30 -0
  109. package/template/host/src/routes/_.tsx +6 -0
  110. package/template/host/src/routes/dashboard._.tsx +41 -0
  111. package/template/host/src/routes/index.tsx +93 -0
  112. package/template/host/src/routes/login.tsx +36 -0
  113. package/template/host/src/saas.config.ts +52 -0
  114. package/template/host/src/test/setup.ts +65 -0
  115. package/template/host/src/test/utils.tsx +69 -0
  116. package/template/host/src/test/vitest-globals.d.ts +19 -0
  117. package/template/host/src/vite-env.d.ts +16 -0
  118. package/template/host/tailwind.config.ts +77 -0
  119. package/template/host/tsconfig.json +19 -0
  120. package/template/host/vitest.config.ts +30 -0
  121. package/template/package.json +44 -0
  122. package/template/packages/plugins/@lego/plugin-dashboard/modern.config.ts +19 -0
  123. package/template/packages/plugins/@lego/plugin-dashboard/package.json +35 -0
  124. package/template/packages/plugins/@lego/plugin-dashboard/postcss.config.mjs +6 -0
  125. package/template/packages/plugins/@lego/plugin-dashboard/src/App.tsx +27 -0
  126. package/template/packages/plugins/@lego/plugin-dashboard/src/components/ActivityFeed.tsx +63 -0
  127. package/template/packages/plugins/@lego/plugin-dashboard/src/components/QuickActionSlot.tsx +11 -0
  128. package/template/packages/plugins/@lego/plugin-dashboard/src/components/QuickActions.tsx +68 -0
  129. package/template/packages/plugins/@lego/plugin-dashboard/src/components/SidebarWidget.tsx +35 -0
  130. package/template/packages/plugins/@lego/plugin-dashboard/src/components/StatCard.tsx +47 -0
  131. package/template/packages/plugins/@lego/plugin-dashboard/src/global.css +24 -0
  132. package/template/packages/plugins/@lego/plugin-dashboard/src/hooks/useChannelIntegration.ts +43 -0
  133. package/template/packages/plugins/@lego/plugin-dashboard/src/hooks/useDashboardStats.ts +65 -0
  134. package/template/packages/plugins/@lego/plugin-dashboard/src/hooks/usePocketBase.ts +47 -0
  135. package/template/packages/plugins/@lego/plugin-dashboard/src/hooks/useRecentActivity.ts +55 -0
  136. package/template/packages/plugins/@lego/plugin-dashboard/src/lib/utils.ts +6 -0
  137. package/template/packages/plugins/@lego/plugin-dashboard/src/pages/DashboardPage.tsx +105 -0
  138. package/template/packages/plugins/@lego/plugin-dashboard/src/plugin.config.ts +121 -0
  139. package/template/packages/plugins/@lego/plugin-dashboard/src/plugin.ts +18 -0
  140. package/template/packages/plugins/@lego/plugin-dashboard/src/vite-env.d.ts +32 -0
  141. package/template/packages/plugins/@lego/plugin-dashboard/tailwind.config.ts +35 -0
  142. package/template/packages/plugins/@lego/plugin-dashboard/tsconfig.json +18 -0
  143. package/template/packages/plugins/@lego/plugin-todo/modern.config.ts +18 -0
  144. package/template/packages/plugins/@lego/plugin-todo/package.json +41 -0
  145. package/template/packages/plugins/@lego/plugin-todo/postcss.config.mjs +6 -0
  146. package/template/packages/plugins/@lego/plugin-todo/src/App.tsx +12 -0
  147. package/template/packages/plugins/@lego/plugin-todo/src/components/SidebarWidget.tsx +16 -0
  148. package/template/packages/plugins/@lego/plugin-todo/src/components/TodoDialog.tsx +55 -0
  149. package/template/packages/plugins/@lego/plugin-todo/src/components/TodoFilters.tsx +79 -0
  150. package/template/packages/plugins/@lego/plugin-todo/src/components/TodoForm.tsx +94 -0
  151. package/template/packages/plugins/@lego/plugin-todo/src/components/TodoItem.tsx +121 -0
  152. package/template/packages/plugins/@lego/plugin-todo/src/components/TodoList.tsx +41 -0
  153. package/template/packages/plugins/@lego/plugin-todo/src/components/index.ts +6 -0
  154. package/template/packages/plugins/@lego/plugin-todo/src/global.css +59 -0
  155. package/template/packages/plugins/@lego/plugin-todo/src/hooks/useCreateTodo.ts +62 -0
  156. package/template/packages/plugins/@lego/plugin-todo/src/hooks/useDeleteTodo.ts +46 -0
  157. package/template/packages/plugins/@lego/plugin-todo/src/hooks/usePocketBase.ts +38 -0
  158. package/template/packages/plugins/@lego/plugin-todo/src/hooks/useTodos.ts +64 -0
  159. package/template/packages/plugins/@lego/plugin-todo/src/hooks/useUpdateTodo.ts +35 -0
  160. package/template/packages/plugins/@lego/plugin-todo/src/index.tsx +5 -0
  161. package/template/packages/plugins/@lego/plugin-todo/src/lib/utils.ts +20 -0
  162. package/template/packages/plugins/@lego/plugin-todo/src/pages/TodoPage.tsx +89 -0
  163. package/template/packages/plugins/@lego/plugin-todo/src/plugin.config.ts +104 -0
  164. package/template/packages/plugins/@lego/plugin-todo/src/plugin.ts +13 -0
  165. package/template/packages/plugins/@lego/plugin-todo/src/schemas.ts +37 -0
  166. package/template/packages/plugins/@lego/plugin-todo/src/types.ts +42 -0
  167. package/template/packages/plugins/@lego/plugin-todo/src/vite-env.d.ts +31 -0
  168. package/template/packages/plugins/@lego/plugin-todo/tailwind.config.ts +51 -0
  169. package/template/packages/plugins/@lego/plugin-todo/tsconfig.json +18 -0
  170. package/template/pnpm-workspace.yaml +4 -0
  171. package/template/tsconfig.json +8 -0
@@ -0,0 +1,379 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
3
+ import { usePocketBase } from '../providers';
4
+ import { RBACService } from './service';
5
+ import type {
6
+ Organization,
7
+ CreateOrganizationData,
8
+ UpdateOrganizationData,
9
+ Role,
10
+ CreateRoleData,
11
+ UpdateRoleData,
12
+ Permission,
13
+ UserRole,
14
+ AssignRoleData,
15
+ UserWithRoles,
16
+ CreateUserRequest,
17
+ UpdateUserRequest,
18
+ ResourceType,
19
+ ActionType,
20
+ } from './types';
21
+ import { useGlobalKernelState } from '../shared-state';
22
+
23
+ /**
24
+ * Get RBAC service instance
25
+ */
26
+ function useRBACService(): RBACService | null {
27
+ const pb = usePocketBase();
28
+ if (!pb) return null;
29
+ return new RBACService(pb);
30
+ }
31
+
32
+ /**
33
+ * Manage current organization
34
+ */
35
+ export function useCurrentOrganization() {
36
+ const { organization, setOrganization } = useGlobalKernelState();
37
+ const queryClient = useQueryClient();
38
+
39
+ const setCurrentOrganization = useCallback((org: Organization | null) => {
40
+ setOrganization(org);
41
+ // Clear related queries when switching organizations
42
+ queryClient.clear();
43
+ }, [setOrganization, queryClient]);
44
+
45
+ return {
46
+ organization,
47
+ setCurrentOrganization,
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Get user's organizations
53
+ */
54
+ export function useOrganizations() {
55
+ const service = useRBACService();
56
+
57
+ return useQuery({
58
+ queryKey: ['organizations'],
59
+ queryFn: () => service?.getUserOrganizations() || [],
60
+ enabled: !!service,
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Get single organization
66
+ */
67
+ export function useOrganization(id: string) {
68
+ const service = useRBACService();
69
+
70
+ return useQuery({
71
+ queryKey: ['organization', id],
72
+ queryFn: () => service?.getOrganization(id),
73
+ enabled: !!service && !!id,
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Create organization
79
+ */
80
+ export function useCreateOrganization() {
81
+ const service = useRBACService();
82
+ const queryClient = useQueryClient();
83
+ const { setCurrentOrganization } = useCurrentOrganization();
84
+
85
+ return useMutation({
86
+ mutationFn: (data: CreateOrganizationData) => {
87
+ if (!service) throw new Error('Service not available');
88
+ return service.createOrganization(data);
89
+ },
90
+ onSuccess: (org) => {
91
+ queryClient.invalidateQueries({ queryKey: ['organizations'] });
92
+ setCurrentOrganization(org);
93
+ },
94
+ });
95
+ }
96
+
97
+ /**
98
+ * Update organization
99
+ */
100
+ export function useUpdateOrganization() {
101
+ const service = useRBACService();
102
+ const queryClient = useQueryClient();
103
+
104
+ return useMutation({
105
+ mutationFn: ({ id, data }: { id: string; data: UpdateOrganizationData }) => {
106
+ if (!service) throw new Error('Service not available');
107
+ return service.updateOrganization(id, data);
108
+ },
109
+ onSuccess: (_, { id }) => {
110
+ queryClient.invalidateQueries({ queryKey: ['organization', id] });
111
+ queryClient.invalidateQueries({ queryKey: ['organizations'] });
112
+ },
113
+ });
114
+ }
115
+
116
+ /**
117
+ * Get organization roles
118
+ */
119
+ export function useOrganizationRoles(organizationId: string | null) {
120
+ const service = useRBACService();
121
+
122
+ return useQuery({
123
+ queryKey: ['roles', organizationId],
124
+ queryFn: () => {
125
+ if (!organizationId || !service) return [];
126
+ return service.getOrganizationRoles(organizationId);
127
+ },
128
+ enabled: !!service && !!organizationId,
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Create custom role
134
+ */
135
+ export function useCreateRole() {
136
+ const service = useRBACService();
137
+ const queryClient = useQueryClient();
138
+
139
+ return useMutation({
140
+ mutationFn: (data: CreateRoleData) => {
141
+ if (!service) throw new Error('Service not available');
142
+ return service.createRole(data);
143
+ },
144
+ onSuccess: (_, { organizationId }) => {
145
+ queryClient.invalidateQueries({ queryKey: ['roles', organizationId] });
146
+ },
147
+ });
148
+ }
149
+
150
+ /**
151
+ * Update role
152
+ */
153
+ export function useUpdateRole() {
154
+ const service = useRBACService();
155
+ const queryClient = useQueryClient();
156
+
157
+ return useMutation({
158
+ mutationFn: ({ id, data }: { id: string; data: UpdateRoleData }) => {
159
+ if (!service) throw new Error('Service not available');
160
+ return service.updateRole(id, data);
161
+ },
162
+ onSuccess: () => {
163
+ queryClient.invalidateQueries({ queryKey: ['roles'] });
164
+ },
165
+ });
166
+ }
167
+
168
+ /**
169
+ * Delete role
170
+ */
171
+ export function useDeleteRole() {
172
+ const service = useRBACService();
173
+ const queryClient = useQueryClient();
174
+
175
+ return useMutation({
176
+ mutationFn: (id: string) => {
177
+ if (!service) throw new Error('Service not available');
178
+ return service.deleteRole(id);
179
+ },
180
+ onSuccess: () => {
181
+ queryClient.invalidateQueries({ queryKey: ['roles'] });
182
+ },
183
+ });
184
+ }
185
+
186
+ /**
187
+ * Get all permissions
188
+ */
189
+ export function usePermissions() {
190
+ const service = useRBACService();
191
+
192
+ return useQuery({
193
+ queryKey: ['permissions'],
194
+ queryFn: () => service?.getAllPermissions() || [],
195
+ enabled: !!service,
196
+ });
197
+ }
198
+
199
+ /**
200
+ * Get organization users
201
+ */
202
+ export function useOrganizationUsers(organizationId: string | null) {
203
+ const service = useRBACService();
204
+
205
+ return useQuery({
206
+ queryKey: ['users', organizationId],
207
+ queryFn: () => {
208
+ if (!organizationId || !service) return [];
209
+ return service.getOrganizationUsers(organizationId);
210
+ },
211
+ enabled: !!service && !!organizationId,
212
+ });
213
+ }
214
+
215
+ /**
216
+ * Assign role to user
217
+ */
218
+ export function useAssignRole() {
219
+ const service = useRBACService();
220
+ const queryClient = useQueryClient();
221
+
222
+ return useMutation({
223
+ mutationFn: (data: AssignRoleData) => {
224
+ if (!service) throw new Error('Service not available');
225
+ return service.assignRole(data);
226
+ },
227
+ onSuccess: (_, { organizationId }) => {
228
+ queryClient.invalidateQueries({ queryKey: ['users', organizationId] });
229
+ },
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Remove role from user
235
+ */
236
+ export function useRemoveRole() {
237
+ const service = useRBACService();
238
+ const queryClient = useQueryClient();
239
+
240
+ return useMutation({
241
+ mutationFn: ({ userRoleId, organizationId }: { userRoleId: string; organizationId: string }) => {
242
+ if (!service) throw new Error('Service not available');
243
+ return service.removeRole(userRoleId);
244
+ },
245
+ onSuccess: (_, { organizationId }) => {
246
+ queryClient.invalidateQueries({ queryKey: ['users', organizationId] });
247
+ },
248
+ });
249
+ }
250
+
251
+ /**
252
+ * Create user
253
+ */
254
+ export function useCreateUser() {
255
+ const service = useRBACService();
256
+ const queryClient = useQueryClient();
257
+
258
+ return useMutation({
259
+ mutationFn: (data: CreateUserRequest) => {
260
+ if (!service) throw new Error('Service not available');
261
+ return service.createUser(data);
262
+ },
263
+ onSuccess: (_, { organizationId }) => {
264
+ queryClient.invalidateQueries({ queryKey: ['users', organizationId] });
265
+ },
266
+ });
267
+ }
268
+
269
+ /**
270
+ * Update user
271
+ */
272
+ export function useUpdateUser() {
273
+ const service = useRBACService();
274
+ const queryClient = useQueryClient();
275
+
276
+ return useMutation({
277
+ mutationFn: ({ userId, data }: { userId: string; data: UpdateUserRequest }) => {
278
+ if (!service) throw new Error('Service not available');
279
+ return service.updateUser(userId, data);
280
+ },
281
+ onSuccess: (_, { userId }) => {
282
+ queryClient.invalidateQueries({ queryKey: ['users'] });
283
+ queryClient.invalidateQueries({ queryKey: ['auth', 'user'] });
284
+ },
285
+ });
286
+ }
287
+
288
+ /**
289
+ * Delete user
290
+ */
291
+ export function useDeleteUser() {
292
+ const service = useRBACService();
293
+ const queryClient = useQueryClient();
294
+
295
+ return useMutation({
296
+ mutationFn: ({ userId, organizationId }: { userId: string; organizationId: string }) => {
297
+ if (!service) throw new Error('Service not available');
298
+ return service.deleteUser(userId);
299
+ },
300
+ onSuccess: (_, { organizationId }) => {
301
+ queryClient.invalidateQueries({ queryKey: ['users', organizationId] });
302
+ },
303
+ });
304
+ }
305
+
306
+ /**
307
+ * Check permissions
308
+ */
309
+ export function useHasPermission() {
310
+ const service = useRBACService();
311
+ const { user, organization } = useGlobalKernelState();
312
+
313
+ return useCallback(
314
+ async (resource: ResourceType, action: ActionType): Promise<boolean> => {
315
+ if (!service || !user?.id || !organization?.id) return false;
316
+ const result = await service.hasPermission(user.id, organization.id, resource, action);
317
+ return result.allowed;
318
+ },
319
+ [service, user, organization]
320
+ );
321
+ }
322
+
323
+ /**
324
+ * Get user permissions for current organization
325
+ */
326
+ export function useUserPermissions() {
327
+ const service = useRBACService();
328
+ const { user, organization } = useGlobalKernelState();
329
+
330
+ return useQuery({
331
+ queryKey: ['permissions', 'user', user?.id, organization?.id],
332
+ queryFn: () => {
333
+ if (!service || !user?.id || !organization?.id) return [];
334
+ return service.getUserPermissions(user.id, organization.id);
335
+ },
336
+ enabled: !!service && !!user?.id && !!organization?.id,
337
+ });
338
+ }
339
+
340
+ /**
341
+ * Require permission - returns whether user has permission
342
+ */
343
+ export function useRequirePermission(resource: ResourceType, action: ActionType) {
344
+ const permissions = useUserPermissions();
345
+ const [hasPermission, setHasPermission] = useState(false);
346
+
347
+ useEffect(() => {
348
+ const perms = permissions.data || [];
349
+
350
+ const allowed =
351
+ perms.some(p => p.resource === 'all' && p.action === 'all') ||
352
+ perms.some(p => p.resource === resource && p.action === 'all') ||
353
+ perms.some(p => p.resource === 'all' && p.action === action) ||
354
+ perms.some(p => p.resource === resource && p.action === action);
355
+
356
+ setHasPermission(allowed);
357
+ }, [permissions.data, resource, action]);
358
+
359
+ return {
360
+ hasPermission,
361
+ isLoading: permissions.isLoading,
362
+ };
363
+ }
364
+
365
+ /**
366
+ * Get audit logs
367
+ */
368
+ export function useAuditLogs(organizationId: string | null, page = 1) {
369
+ const service = useRBACService();
370
+
371
+ return useQuery({
372
+ queryKey: ['audit-logs', organizationId, page],
373
+ queryFn: () => {
374
+ if (!organizationId || !service) return null;
375
+ return service.getAuditLogs(organizationId, page);
376
+ },
377
+ enabled: !!service && !!organizationId,
378
+ });
379
+ }
@@ -0,0 +1,6 @@
1
+ export * from './types';
2
+ export * from './service';
3
+ export * from './hooks';
4
+ export * from './components/PermissionGate';
5
+ export * from './components/OrganizationSelector';
6
+ export * from './utils';