// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential. import { useState, useMemo } from 'react'; import { useModuleRegistry } from '../context/ModuleRegistryContext'; import { useCommercial } from '../context/CommercialContext'; export default function TenantModuleMatrix({ allowedModules = [] }) { const { registry, allModules } = useModuleRegistry(); const { tiers, modulePrices } = useCommercial(); const [searchQuery, setSearchQuery] = useState(''); const [viewMode, setViewMode] = useState('grid'); // grid | list // Supreme mode: all modules granted const isSupreme = allowedModules === 'supreme'; const effectiveAllowed = isSupreme ? allModules.map(m => m.id) : allowedModules; // Build module status map const moduleStatusMap = useMemo(() => { const map = {}; allModules.forEach(mod => { const isGranted = effectiveAllowed.includes(mod.id); map[mod.id] = { ...mod, granted: isGranted, price: modulePrices?.[mod.id] || null }; }); return map; }, [allModules, allowedModules, modulePrices]); const grantedCount = effectiveAllowed.length; const totalCount = allModules.length; const lockedCount = totalCount - grantedCount; // Find matching tier const matchedTier = useMemo(() => { return tiers.find(t => t.modules.length === effectiveAllowed.length && t.modules.every(m => effectiveAllowed.includes(m)) ); }, [tiers, allowedModules]); // Filter modules const filteredModules = useMemo(() => { if (!searchQuery.trim()) return allModules; const q = searchQuery.toLowerCase(); return allModules.filter(m => m.id.toLowerCase().includes(q) || m.name.toLowerCase().includes(q) ); }, [allModules, searchQuery]); // Group by registry category const groupedModules = useMemo(() => { const groups = {}; for (const [groupKey, groupData] of Object.entries(registry)) { const mods = groupData.modules.filter(m => filteredModules.some(fm => fm.id === m.id) ); if (mods.length > 0) { groups[groupKey] = { ...groupData, modules: mods }; } } return groups; }, [registry, filteredModules]); return (
{/* Header Stats */}

MODULE ACCESS MATRIX

{isSupreme && SUPREME ADMIN — ALL ACCESS}{!isSupreme && <>Tier: {matchedTier ? matchedTier.name : 'CUSTOM A LA CARTE'}}

{grantedCount}
GRANTED
{lockedCount}
LOCKED
{totalCount}
TOTAL
{/* Search + View Toggle */}
setSearchQuery(e.target.value)} style={{ flex: 1, padding: '10px 15px', background: 'var(--panel-bg)', color: 'var(--text-main)', border: '1px solid var(--table-border)', borderRadius: '8px', fontFamily: 'monospace', fontSize: '0.85rem' }} />
{/* Progress Bar */}
COVERAGE {totalCount > 0 ? Math.round(grantedCount / totalCount * 100) : 0}%
0 ? `${grantedCount / totalCount * 100}%` : '0%', height: '100%', background: 'linear-gradient(90deg, var(--accent-green), var(--accent-cyan))', borderRadius: '3px', transition: 'width 0.5s ease' }} />
{/* Module Grid/List by Group */} {Object.entries(groupedModules).map(([groupKey, groupData]) => (

{groupKey.replace(/_/g, ' ')} ({groupData.modules.length})

{viewMode === 'grid' ? (
{groupData.modules.map(mod => { const status = moduleStatusMap[mod.id]; const isGranted = status?.granted; return (
{mod.id.toUpperCase()} {isGranted ? '✓ GRANTED' : '✗ LOCKED'}
{mod.name}
{status?.price && (
${status.price}/mo
)}
); })}
) : ( {groupData.modules.map(mod => { const status = moduleStatusMap[mod.id]; const isGranted = status?.granted; return ( ); })}
{mod.id} {mod.name} {isGranted ? '✓ GRANTED' : '✗ LOCKED'}
)}
))} {filteredModules.length === 0 && (
Tidak ada modul yang cocok dengan pencarian.
)}
); }