commcoach iteration 1 completed

This commit is contained in:
ValueOn AG 2026-03-03 22:04:54 +01:00
parent 275164e7cb
commit cd14e8a6fb
4 changed files with 32 additions and 10 deletions

View file

@ -99,7 +99,8 @@ export interface DashboardData {
recentScores: CoachingScore[];
openTasks: number;
completedTasks: number;
contexts: Array<{ id: string; title: string; category: string; sessionCount: number; lastSessionAt?: string }>;
goalProgress?: number;
contexts: Array<{ id: string; title: string; category: string; sessionCount: number; lastSessionAt?: string; goalProgress?: number }>;
}
export interface SSEEvent {

View file

@ -26,6 +26,7 @@ export interface CommcoachHookReturn {
messages: CoachingMessage[];
isStreaming: boolean;
streamingStatus: string | null;
streamingMessage: string | null;
tasks: CoachingTask[];
scores: CoachingScore[];
@ -70,6 +71,7 @@ export function useCommcoach(): CommcoachHookReturn {
const [messages, setMessages] = useState<CoachingMessage[]>([]);
const [isStreaming, setIsStreaming] = useState(false);
const [streamingStatus, setStreamingStatus] = useState<string | null>(null);
const [streamingMessage, setStreamingMessage] = useState<string | null>(null);
const [tasks, setTasks] = useState<CoachingTask[]>([]);
const [scores, setScores] = useState<CoachingScore[]>([]);
@ -237,7 +239,10 @@ export function useCommcoach(): CommcoachHookReturn {
if (eventData.resumed && Array.isArray(eventData.messages)) {
setMessages(eventData.messages);
}
} else if (eventType === 'messageChunk' && eventData) {
setStreamingMessage(eventData.accumulated || '');
} else if (eventType === 'message' && eventData) {
setStreamingMessage(null);
const msg: CoachingMessage = {
id: eventData.id || `msg-${Date.now()}`,
sessionId: eventData.sessionId || '',
@ -263,12 +268,14 @@ export function useCommcoach(): CommcoachHookReturn {
if (isMountedRef.current) {
setError(err.message);
setIsStreaming(false);
setStreamingMessage(null);
}
},
() => {
if (isMountedRef.current) {
setIsStreaming(false);
setStreamingStatus(null);
setStreamingMessage(null);
}
},
);
@ -309,7 +316,10 @@ export function useCommcoach(): CommcoachHookReturn {
const eventType = event.type;
const eventData = event.data;
if (eventType === 'message' && eventData) {
if (eventType === 'messageChunk' && eventData) {
setStreamingMessage(eventData.accumulated || '');
} else if (eventType === 'message' && eventData) {
setStreamingMessage(null);
const msg: CoachingMessage = {
id: eventData.id || `msg-${Date.now()}`,
sessionId: session.id,
@ -343,12 +353,14 @@ export function useCommcoach(): CommcoachHookReturn {
if (isMountedRef.current) {
setError(err.message);
setIsStreaming(false);
setStreamingMessage(null);
}
},
() => {
if (isMountedRef.current) {
setIsStreaming(false);
setStreamingStatus(null);
setStreamingMessage(null);
}
},
);
@ -485,7 +497,7 @@ export function useCommcoach(): CommcoachHookReturn {
return {
contexts, selectedContextId, selectedContext, loadingContexts,
session, messages, isStreaming, streamingStatus,
session, messages, isStreaming, streamingStatus, streamingMessage,
tasks, scores, sessions,
error, inputValue, setInputValue,
selectContext, createContext, archiveContext,

View file

@ -341,10 +341,16 @@ export const CommcoachCoachingView: React.FC = () => {
{coach.isStreaming && (
<div className={`${styles.message} ${styles.messageAssistant}`}>
<div className={styles.messageBubble}>
<div className={styles.typing}>
{coach.streamingStatus || 'Coach denkt nach'}
<span className={styles.typingDots}>...</span>
</div>
{coach.streamingMessage ? (
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{coach.streamingMessage}
</ReactMarkdown>
) : (
<div className={styles.typing}>
{coach.streamingStatus || 'Coach denkt nach'}
<span className={styles.typingDots}>...</span>
</div>
)}
</div>
</div>
)}

View file

@ -55,9 +55,11 @@ export const CommcoachDashboardView: React.FC = () => {
<div className={styles.kpiSub}>Durchschnitt</div>
</div>
<div className={styles.kpiCard}>
<div className={styles.kpiValue}>{dashboard.openTasks}</div>
<div className={styles.kpiLabel}>Offene Aufgaben</div>
<div className={styles.kpiSub}>{dashboard.completedTasks} erledigt</div>
<div className={styles.kpiValue}>
{dashboard.goalProgress != null ? `${dashboard.goalProgress}%` : '--'}
</div>
<div className={styles.kpiLabel}>Zielfortschritt</div>
<div className={styles.kpiSub}>{dashboard.openTasks} offene Aufgaben</div>
</div>
</div>
@ -84,6 +86,7 @@ export const CommcoachDashboardView: React.FC = () => {
<div className={styles.contextMeta}>
<span className={styles.contextCategory}>{_categoryLabel(ctx.category)}</span>
<span>{ctx.sessionCount} Sessions</span>
{ctx.goalProgress != null && <span>Ziele: {ctx.goalProgress}%</span>}
</div>
{ctx.lastSessionAt && (
<div className={styles.contextLast}>