/** * Feature Store -- Users activate feature instances in their own mandates. * Uses the Own Instance Pattern -- each activation creates a dedicated FeatureInstance * in the selected mandate. Explicit mandate selection required. */ import React from 'react'; import { FaCogs, FaComments, FaHeadset, FaProjectDiagram } from 'react-icons/fa'; import { useLanguage } from '../providers/language/LanguageContext'; import { useStore } from '../hooks/useStore'; import type { StoreFeature, UserMandate } from '../api/storeApi'; import { formatBinaryDataSizeFromMebibytes } from '../utils/formatDataSize'; import styles from './Store.module.css'; const FEATURE_ICONS: Record = { automation: , automation2: , teamsbot: , workspace: , commcoach: , }; const FEATURE_DESCRIPTIONS: Record> = { automation: { de: 'Erstelle und verwalte Automatisierungen, um wiederkehrende Aufgaben effizient zu erledigen.', en: 'Create and manage automations to handle recurring tasks efficiently.', fr: 'Creer et gerer des automatisations pour traiter efficacement les taches recurrentes.', }, automation2: { de: 'n8n-style Flow-Automatisierung mit grafischem Editor, RAG und Tools.', en: 'n8n-style flow automation with visual editor, RAG and tools.', fr: 'Automatisation de flux style n8n avec editeur visuel, RAG et outils.', }, teamsbot: { de: 'Integriere einen AI-Bot in deine Microsoft Teams Meetings und Channels.', en: 'Integrate an AI bot into your Microsoft Teams meetings and channels.', fr: 'Integrez un bot IA dans vos reunions et canaux Microsoft Teams.', }, workspace: { de: 'Nutze den gemeinsamen AI Workspace: Chats, Tools und Kontext pro Instanz.', en: 'Use the shared AI workspace: chats, tools, and context per instance.', fr: 'Utilisez l\'espace de travail IA partage: chats, outils et contexte par instance.', }, commcoach: { de: 'CommCoach: Kommunikation trainieren mit KI-gestütztem Coaching und Feedback.', en: 'CommCoach: practice communication with AI-assisted coaching and feedback.', fr: 'CommCoach: entrainer la communication avec un coaching assiste par IA.', }, }; function _getLabel(labels: Record, lang: string): string { return labels[lang] || labels['en'] || labels['de'] || Object.values(labels)[0] || ''; } function _getDescription(featureCode: string, lang: string): string { const desc = FEATURE_DESCRIPTIONS[featureCode]; if (!desc) return ''; return desc[lang] || desc['en'] || desc['de'] || ''; } interface FeatureCardProps { feature: StoreFeature; language: string; mandates: UserMandate[]; actionLoading: string | null; onActivate: (code: string, mandateId?: string) => void; onDeactivate: (code: string, mandateId: string, instanceId: string) => void; } const FeatureCard: React.FC = ({ feature, language, mandates, actionLoading, onActivate, onDeactivate, }) => { const isProcessing = actionLoading === feature.featureCode; const icon = FEATURE_ICONS[feature.featureCode]; const activeInstances = feature.instances.filter(inst => inst.isActive); const hasActive = activeInstances.length > 0; return (
{icon && {icon}}

{_getLabel(feature.label, language)}

{_getDescription(feature.featureCode, language)}

{activeInstances.length > 0 && (
{activeInstances.map((inst) => (
{inst.mandateName || inst.label}
))}
)} {activeInstances.length === 0 && (
{language === 'de' ? 'Verfuegbar' : language === 'fr' ? 'Disponible' : 'Available'}
)}
{feature.canActivate && mandates.map((m) => ( ))}
); }; const StorePage: React.FC = () => { const { currentLanguage } = useLanguage(); const { features, mandates, subscriptionInfo, loading, actionLoading, error, activate, deactivate } = useStore(); return (

{currentLanguage === 'de' ? 'Feature Store' : currentLanguage === 'fr' ? 'Feature Store' : 'Feature Store'}

{currentLanguage === 'de' ? 'Aktiviere Features fuer dein Konto. Deine Daten sind isoliert und nur fuer dich sichtbar.' : currentLanguage === 'fr' ? 'Activez des fonctionnalites pour votre compte. Vos donnees sont isolees et visibles uniquement par vous.' : 'Activate features for your account. Your data is isolated and only visible to you.'}

{subscriptionInfo && subscriptionInfo.plan && (
Plan: {subscriptionInfo.plan} {subscriptionInfo.maxFeatureInstances != null && ( {currentLanguage === 'de' ? 'Instanzen' : 'Instances'}: {subscriptionInfo.currentFeatureInstances}/{subscriptionInfo.maxFeatureInstances} )} {subscriptionInfo.maxDataVolumeMB != null && ( {currentLanguage === 'de' ? 'Speicher' : 'Storage'}:{' '} {formatBinaryDataSizeFromMebibytes(subscriptionInfo.maxDataVolumeMB)} )} {subscriptionInfo.budgetAiCHF != null && subscriptionInfo.budgetAiCHF > 0 && ( {currentLanguage === 'de' ? 'AI-Budget' : 'AI budget'}: {subscriptionInfo.budgetAiCHF} CHF )} {subscriptionInfo.status === 'TRIALING' && subscriptionInfo.trialEndsAt && ( {currentLanguage === 'de' ? 'Trial endet' : 'Trial ends'}: {new Date(subscriptionInfo.trialEndsAt).toLocaleDateString()} )}
)} {error &&
{error}
} {loading ? (
{currentLanguage === 'de' ? 'Lade Features...' : 'Loading features...'}
) : features.length === 0 ? (
{currentLanguage === 'de' ? 'Keine Features im Store verfuegbar.' : 'No features available in the store.'}
) : (
{features.map((feature) => ( ))}
)}
); }; export default StorePage;