Enhance Header component to display user roles alongside names. Update Sidebar menu item label for clarity. Refactor Modules component to utilize new MyModule type and fetch modules with updated service method. Comment out unused code in RolesTable and Dashboard components for cleaner codebase. Add MyModule and MyModulesResponse types for better type safety in module handling.

This commit is contained in:
Yashwin 2026-02-04 14:54:37 +05:30
parent cdd53a601c
commit dd71820ac9
9 changed files with 67 additions and 47 deletions

View File

@ -17,7 +17,7 @@ interface HeaderProps {
export const Header = ({ breadcrumbs, currentPage, onMenuClick }: HeaderProps): ReactElement => { export const Header = ({ breadcrumbs, currentPage, onMenuClick }: HeaderProps): ReactElement => {
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { user, isLoading } = useAppSelector((state) => state.auth); const { user, isLoading,roles } = useAppSelector((state) => state.auth);
const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false); const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false);
const dropdownRef = useRef<HTMLDivElement>(null); const dropdownRef = useRef<HTMLDivElement>(null);
@ -35,7 +35,7 @@ export const Header = ({ breadcrumbs, currentPage, onMenuClick }: HeaderProps):
// Get user display name // Get user display name
const getUserDisplayName = (): string => { const getUserDisplayName = (): string => {
if (user?.first_name && user?.last_name) { if (user?.first_name && user?.last_name) {
return `${user.first_name} ${user.last_name}`; return `${user.first_name} - ${roles[0] || 'N/A'}`;
} }
return user?.email?.split('@')[0] || 'Admin'; return user?.email?.split('@')[0] || 'Admin';
}; };

View File

@ -48,7 +48,7 @@ const tenantAdminPlatformMenu: MenuItem[] = [
{ icon: LayoutDashboard, label: 'Dashboard', path: '/tenant' }, { icon: LayoutDashboard, label: 'Dashboard', path: '/tenant' },
{ icon: Shield, label: 'Roles', path: '/tenant/roles', requiredPermission: { resource: 'roles' } }, { icon: Shield, label: 'Roles', path: '/tenant/roles', requiredPermission: { resource: 'roles' } },
{ icon: Users, label: 'Users', path: '/tenant/users', requiredPermission: { resource: 'users' } }, { icon: Users, label: 'Users', path: '/tenant/users', requiredPermission: { resource: 'users' } },
{ icon: Package, label: 'TenantModules', path: '/tenant/modules', requiredPermission: { resource: 'tenants' } }, { icon: Package, label: 'Modules', path: '/tenant/modules' },
]; ];
const tenantAdminSystemMenu: MenuItem[] = [ const tenantAdminSystemMenu: MenuItem[] = [

View File

@ -215,15 +215,15 @@ export const RolesTable = ({ tenantId, showHeader = true, compact = false }: Rol
</span> </span>
), ),
}, },
{ // {
key: 'is_system', // key: 'is_system',
label: 'System Role', // label: 'System Role',
render: (role) => ( // render: (role) => (
<span className="text-sm font-normal text-[#0f1724]"> // <span className="text-sm font-normal text-[#0f1724]">
{role.is_system ? 'Yes' : 'No'} // {role.is_system ? 'Yes' : 'No'}
</span> // </span>
), // ),
}, // },
{ {
key: 'created_at', key: 'created_at',
label: 'Created Date', label: 'Created Date',

View File

@ -65,13 +65,13 @@ const StatCard = ({ icon: Icon, value, label, status, statusLabel }: StatCardPro
const Dashboard = (): ReactElement => { const Dashboard = (): ReactElement => {
const statCards: StatCardProps[] = [ const statCards: StatCardProps[] = [
{ // {
icon: Info, // icon: Info,
value: '18', // value: '18',
label: 'Open CAPAs', // label: 'Open CAPAs',
status: 'success', // status: 'success',
statusLabel: 'Success', // statusLabel: 'Success',
}, // },
{ {
icon: FileCheck, icon: FileCheck,
value: '7', value: '7',

View File

@ -7,9 +7,8 @@ import {
type Column, type Column,
} from '@/components/shared'; } from '@/components/shared';
import { useAppSelector } from '@/hooks/redux-hooks'; import { useAppSelector } from '@/hooks/redux-hooks';
import { tenantService } from '@/services/tenant-service';
import type { AssignedModule } from '@/types/tenant';
import { moduleService } from '@/services/module-service'; import { moduleService } from '@/services/module-service';
import type { MyModule } from '@/types/module';
// Helper function to get status badge variant // Helper function to get status badge variant
const getStatusVariant = (status: string | null): 'success' | 'failure' | 'process' => { const getStatusVariant = (status: string | null): 'success' | 'failure' | 'process' => {
@ -28,24 +27,17 @@ const getStatusVariant = (status: string | null): 'success' | 'failure' | 'proce
const Modules = (): ReactElement => { const Modules = (): ReactElement => {
const { roles, tenantId } = useAppSelector((state) => state.auth); const { roles, tenantId } = useAppSelector((state) => state.auth);
// const tenantId = useAppSelector((state) => state.auth.tenantId); const [modules, setModules] = useState<MyModule[]>([]);
const [modules, setModules] = useState<AssignedModule[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true); const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const fetchTenantModules = async (): Promise<void> => { const fetchTenantModules = async (): Promise<void> => {
if (!tenantId) {
setError('Tenant ID not found');
setIsLoading(false);
return;
}
try { try {
setIsLoading(true); setIsLoading(true);
setError(null); setError(null);
const response = await tenantService.getById(tenantId); const response = await moduleService.getMyModules();
if (response.success && response.data.assignedModules) { if (response.success && response.data) {
setModules(response.data.assignedModules); setModules(response.data);
} else { } else {
setError('Failed to load modules'); setError('Failed to load modules');
} }
@ -58,7 +50,7 @@ const Modules = (): ReactElement => {
useEffect(() => { useEffect(() => {
fetchTenantModules(); fetchTenantModules();
}, [tenantId]); }, []);
// Launch module handler // Launch module handler
const handleLaunchModule = async (moduleId: string): Promise<void> => { const handleLaunchModule = async (moduleId: string): Promise<void> => {
@ -88,7 +80,7 @@ const Modules = (): ReactElement => {
}; };
// Define table columns // Define table columns
const columns: Column<AssignedModule>[] = [ const columns: Column<MyModule>[] = [
{ {
key: 'module_id', key: 'module_id',
label: 'Module ID', label: 'Module ID',
@ -149,7 +141,7 @@ const Modules = (): ReactElement => {
]; ];
// Mobile card renderer // Mobile card renderer
const mobileCardRenderer = (module: AssignedModule) => ( const mobileCardRenderer = (module: MyModule) => (
<div className="p-4"> <div className="p-4">
<div className="flex items-start justify-between gap-3 mb-3"> <div className="flex items-start justify-between gap-3 mb-3">
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">

View File

@ -218,15 +218,15 @@ const Roles = (): ReactElement => {
</span> </span>
), ),
}, },
{ // {
key: 'is_system', // key: 'is_system',
label: 'System Role', // label: 'System Role',
render: (role) => ( // render: (role) => (
<span className="text-sm font-normal text-[#0f1724]"> // <span className="text-sm font-normal text-[#0f1724]">
{role.is_system ? 'Yes' : 'No'} // {role.is_system ? 'Yes' : 'No'}
</span> // </span>
), // ),
}, // },
{ {
key: 'created_at', key: 'created_at',
label: 'Created Date', label: 'Created Date',

View File

@ -245,11 +245,11 @@ const TenantLogin = (): ReactElement => {
<div className="w-full max-w-[507px] flex flex-col gap-5"> <div className="w-full max-w-[507px] flex flex-col gap-5">
{/* Header */} {/* Header */}
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="flex items-center justify-between"> {/* <div className="flex items-center justify-between">
<div className="bg-[#edf3fe] px-2.5 py-1 rounded-full"> <div className="bg-[#edf3fe] px-2.5 py-1 rounded-full">
<span className="text-[11px] font-medium text-[#0f1724]">Tenant Admin Portal</span> <span className="text-[11px] font-medium text-[#0f1724]">Tenant Admin Portal</span>
</div> </div>
</div> </div> */}
<h1 className="text-[22px] font-semibold text-[#0f1724]">Sign in to your tenant</h1> <h1 className="text-[22px] font-semibold text-[#0f1724]">Sign in to your tenant</h1>
<p className="text-sm font-normal text-[#6b7280]"> <p className="text-sm font-normal text-[#6b7280]">
Use your work email or configured SSO provider to access the admin portal. Use your work email or configured SSO provider to access the admin portal.

View File

@ -1,5 +1,5 @@
import apiClient from './api-client'; import apiClient from './api-client';
import type { ModulesResponse, GetModuleResponse, CreateModuleRequest, CreateModuleResponse, LaunchModuleResponse } from '@/types/module'; import type { ModulesResponse, GetModuleResponse, CreateModuleRequest, CreateModuleResponse, LaunchModuleResponse, MyModulesResponse } from '@/types/module';
export const moduleService = { export const moduleService = {
getAll: async ( getAll: async (
@ -75,4 +75,8 @@ export const moduleService = {
const response = await apiClient.post<LaunchModuleResponse>(url); const response = await apiClient.post<LaunchModuleResponse>(url);
return response.data; return response.data;
}, },
getMyModules: async (): Promise<MyModulesResponse> => {
const response = await apiClient.get<MyModulesResponse>('/modules/my');
return response.data;
},
}; };

View File

@ -101,3 +101,27 @@ export interface LaunchModuleResponse {
}; };
}; };
} }
export interface MyModule {
id: string;
module_id: string;
name: string;
description: string | null;
version: string;
status: string;
base_url: string;
health_status: string | null;
assigned_at: string;
tenant_settings: Record<string, unknown> | null;
}
export interface MyModulesResponse {
success: boolean;
data: MyModule[];
meta: {
tenant_id: string;
is_super_admin: boolean;
is_tenant_admin: boolean;
total: number;
};
}