added create user
This commit is contained in:
parent
dc4a119a7a
commit
8f69af24ba
@ -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) {
|
||||
|
||||
@ -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 ---
|
||||
|
||||
24
src/components/rv/UsersView.tsx
Normal file
24
src/components/rv/UsersView.tsx
Normal file
@ -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 (
|
||||
<RecordView
|
||||
client={userClient}
|
||||
rvUid={USER.recordViews.SALES_OFFICERS}
|
||||
title="Sales Officers"
|
||||
onRowClick={onRowClick}
|
||||
pageSize={pageSize}
|
||||
headerActions={headerActions}
|
||||
rowActions={rowActions}
|
||||
refreshKey={refreshKey}
|
||||
sortBy="instance_id"
|
||||
sortDir="desc"
|
||||
initialFilters={initialFilters}
|
||||
presetAlias={presetAlias}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -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';
|
||||
|
||||
@ -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: <DatasetsPage />,
|
||||
adminOnly: true,
|
||||
},
|
||||
{
|
||||
path: "/admin/users",
|
||||
element: <UsersPage />,
|
||||
adminOnly: true,
|
||||
},
|
||||
];
|
||||
|
||||
@ -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() {
|
||||
<Database size={16} />
|
||||
Manage Datasets
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to="/admin/users"
|
||||
className={({ isActive }) => 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")}
|
||||
>
|
||||
<Users size={16} />
|
||||
Manage Users
|
||||
</NavLink>
|
||||
</div>
|
||||
)}
|
||||
<div className="px-2">
|
||||
|
||||
64
src/screens/admin/UsersPage.tsx
Normal file
64
src/screens/admin/UsersPage.tsx
Normal file
@ -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 (
|
||||
<>
|
||||
<UsersView
|
||||
refreshKey={refreshKey}
|
||||
headerActions={
|
||||
<Button size="sm" iconLeft={<Plus size={14} />} onClick={() => setIsCreating(true)}>
|
||||
Add Sales Officer
|
||||
</Button>
|
||||
}
|
||||
rowActions={(row) => (
|
||||
<Button size="sm" variant="outline" iconLeft={<Edit size={14} />} onClick={() => handleEditRow(row)}>
|
||||
Edit
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
open={isCreating || activeActivity !== null}
|
||||
onClose={() => {
|
||||
setIsCreating(false);
|
||||
setActiveActivity(null);
|
||||
}}
|
||||
title={activeActivity?.name || "Add User"}
|
||||
>
|
||||
<DynamicForm
|
||||
client={userClient}
|
||||
activityId={activeActivity?.id || USER.activities.ADD_USER.uid}
|
||||
instanceId={activeActivity?.instanceId}
|
||||
onSuccess={() => {
|
||||
setIsCreating(false);
|
||||
setActiveActivity(null);
|
||||
setRefreshKey(k => k + 1);
|
||||
}}
|
||||
onCancel={() => {
|
||||
setIsCreating(false);
|
||||
setActiveActivity(null);
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user