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 => {
const navigate = useNavigate();
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 dropdownRef = useRef<HTMLDivElement>(null);
@ -35,7 +35,7 @@ export const Header = ({ breadcrumbs, currentPage, onMenuClick }: HeaderProps):
// Get user display name
const getUserDisplayName = (): string => {
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';
};

View File

@ -48,7 +48,7 @@ const tenantAdminPlatformMenu: MenuItem[] = [
{ icon: LayoutDashboard, label: 'Dashboard', path: '/tenant' },
{ icon: Shield, label: 'Roles', path: '/tenant/roles', requiredPermission: { resource: 'roles' } },
{ 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[] = [

View File

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

View File

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

View File

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

View File

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

View File

@ -245,11 +245,11 @@ const TenantLogin = (): ReactElement => {
<div className="w-full max-w-[507px] flex flex-col gap-5">
{/* Header */}
<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">
<span className="text-[11px] font-medium text-[#0f1724]">Tenant Admin Portal</span>
</div>
</div>
</div> */}
<h1 className="text-[22px] font-semibold text-[#0f1724]">Sign in to your tenant</h1>
<p className="text-sm font-normal text-[#6b7280]">
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 type { ModulesResponse, GetModuleResponse, CreateModuleRequest, CreateModuleResponse, LaunchModuleResponse } from '@/types/module';
import type { ModulesResponse, GetModuleResponse, CreateModuleRequest, CreateModuleResponse, LaunchModuleResponse, MyModulesResponse } from '@/types/module';
export const moduleService = {
getAll: async (
@ -75,4 +75,8 @@ export const moduleService = {
const response = await apiClient.post<LaunchModuleResponse>(url);
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;
};
}