diff --git a/src/api/clients.ts b/src/api/clients.ts index bbe0f12..b426984 100644 --- a/src/api/clients.ts +++ b/src/api/clients.ts @@ -21,10 +21,11 @@ export function clientFor(slug: WorkflowSlug): ZinoClient { export const orderBookingClient = clientFor('orderBooking'); export const storeClient = clientFor('store'); export const dailyReportsClient = clientFor('dailyReports'); +export const userClient = clientFor('user'); // The user JWT (from /usr/login) is valid across every workflow, but each // client holds its own copy — so auth helpers fan out to all of them. -const ALL = [orderBookingClient, storeClient, dailyReportsClient]; +const ALL = [orderBookingClient, storeClient, dailyReportsClient, userClient]; /** Log in once and share the JWT with every workflow client. */ export async function loginAll(email: string, password: string, orgId?: string) { diff --git a/src/api/config.ts b/src/api/config.ts index 8a40343..d9aed87 100644 --- a/src/api/config.ts +++ b/src/api/config.ts @@ -177,11 +177,38 @@ export const DAILY_REPORTS = { }, } as const; +// --- User Management (src/docs/api/user.md) --- +export const USER = { + workflowUuid: '9874af12-78b7-4730-834a-19a32221f3aa', + versionUuid: '', // No version UUID provided, server will use latest + activities: { + ADD_USER: { + uid: '3a8f132e-8c63-4d4d-b466-67595d345a99', // init + fields: { + name: 'name', // text + email: 'email', // email + password: 'password', // password + }, + }, + EDIT_USER: { + uid: '3091530c-4315-42b9-b53b-a148f2c54a81', + fields: { + name: 'name_3', // text + email: 'email_3', // email + }, + }, + }, + recordViews: { + SALES_OFFICERS: '406f89d7-09f6-42ba-ba35-84334ccb6204', + }, +} as const; + // All workflows keyed by slug, for generic lookup. export const WORKFLOWS = { orderBooking: ORDER_BOOKING, store: STORE, dailyReports: DAILY_REPORTS, + user: USER, } as const; // --- Daily Sales Report Constants --- diff --git a/src/components/rv/UsersView.tsx b/src/components/rv/UsersView.tsx new file mode 100644 index 0000000..1564cc1 --- /dev/null +++ b/src/components/rv/UsersView.tsx @@ -0,0 +1,24 @@ +import { userClient } from '../../api/clients'; +import { USER } from '../../api/config'; +import { RecordView } from './RecordView'; +import type { WiredRecordViewProps } from './OrdersView'; + +/** Users / Sales Officers record view (User workflow). */ +export function UsersView({ onRowClick, pageSize, headerActions, rowActions, refreshKey, initialFilters, presetAlias }: WiredRecordViewProps) { + return ( + + ); +} diff --git a/src/components/rv/index.ts b/src/components/rv/index.ts index 00fca48..ed3df33 100644 --- a/src/components/rv/index.ts +++ b/src/components/rv/index.ts @@ -5,3 +5,4 @@ export type { WiredRecordViewProps } from './OrdersView'; export { CallsView } from './CallsView'; export { StoresView } from './StoresView'; export { DailyLogsView } from './DailyLogsView'; +export { UsersView } from './UsersView'; diff --git a/src/routesConfig.tsx b/src/routesConfig.tsx index 0a7b129..cee2142 100644 --- a/src/routesConfig.tsx +++ b/src/routesConfig.tsx @@ -8,6 +8,7 @@ import { MyDailyLogsPage } from './screens/MyDailyLogsPage' import { DailySalesReportPage } from './screens/DailySalesReportPage' import { ReportPage } from './screens/ReportPage' import { DatasetsPage } from './screens/admin/DatasetsPage' +import { UsersPage } from './screens/admin/UsersPage' export const routeConfig = [ // Sales Officer @@ -104,4 +105,9 @@ export const routeConfig = [ element: , adminOnly: true, }, + { + path: "/admin/users", + element: , + adminOnly: true, + }, ]; diff --git a/src/screens/ConsoleLayout.tsx b/src/screens/ConsoleLayout.tsx index c826cae..81b24c5 100644 --- a/src/screens/ConsoleLayout.tsx +++ b/src/screens/ConsoleLayout.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react'; import { NavLink, Navigate, Outlet, useNavigate, useLocation } from 'react-router-dom'; -import { LogOut, ChevronDown, Database } from 'lucide-react'; +import { LogOut, ChevronDown, Database, Users } from 'lucide-react'; import { cn } from '../lib/cn'; import { useAuth } from '../auth/context'; import { onAuthErrorAll, orderBookingClient } from '../api/clients'; @@ -132,6 +132,13 @@ export function ConsoleLayout() { Manage Datasets + cn("w-full text-left px-3 py-2 text-sm font-medium hover:bg-indigo-50 hover:text-indigo-700 rounded-md transition-colors flex items-center gap-2 cursor-pointer mt-1", isActive ? "text-indigo-700 bg-indigo-50" : "text-gray-700")} + > + + Manage Users + )}
diff --git a/src/screens/admin/UsersPage.tsx b/src/screens/admin/UsersPage.tsx new file mode 100644 index 0000000..c23a49d --- /dev/null +++ b/src/screens/admin/UsersPage.tsx @@ -0,0 +1,64 @@ +import { useState } from 'react'; +import { Modal } from '../../components/reusable'; +import { UsersView } from '../../components/rv'; +import { DynamicForm } from '../../components/forms/DynamicForm'; +import { USER } from '../../api/config'; +import { userClient } from '../../api/clients'; +import { Button } from '../../components/buttons/Button'; +import { Plus, Edit } from 'lucide-react'; + +export function UsersPage() { + const [isCreating, setIsCreating] = useState(false); + const [refreshKey, setRefreshKey] = useState(0); + const [activeActivity, setActiveActivity] = useState<{ id: string; name: string, instanceId?: number } | null>(null); + + const handleEditRow = (row: any) => { + setActiveActivity({ + id: USER.activities.EDIT_USER.uid, + name: "Edit User", + instanceId: row.instance_id + }); + }; + + return ( + <> + } onClick={() => setIsCreating(true)}> + Add Sales Officer + + } + rowActions={(row) => ( + + )} + /> + + { + setIsCreating(false); + setActiveActivity(null); + }} + title={activeActivity?.name || "Add User"} + > + { + setIsCreating(false); + setActiveActivity(null); + setRefreshKey(k => k + 1); + }} + onCancel={() => { + setIsCreating(false); + setActiveActivity(null); + }} + /> + + + ); +}