added create user

This commit is contained in:
suryacp23 2026-07-30 12:32:09 +05:30
parent dc4a119a7a
commit 8f69af24ba
7 changed files with 132 additions and 2 deletions

View File

@ -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) {

View File

@ -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 ---

View 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}
/>
);
}

View File

@ -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';

View File

@ -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,
},
];

View File

@ -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">

View 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>
</>
);
}