87 lines
2.7 KiB
TypeScript

import { create } from 'zustand';
import { apiFetch } from '../lib/api';
let historyLoaded = false;
export type Message = {
id: string;
role: 'user' | 'assistant';
content: string;
isError?: boolean;
feedbackSaved?: boolean;
};
type CoachState = {
messages: Message[];
thinking: boolean;
historyLoaded: boolean;
/** True sobald der Welcome-Back-Call in dieser App-Session geantwortet hat
* — verhindert dass jede Tab-Rückkehr eine neue Lyra-Begrüßung anhängt. */
welcomeBackShownThisSession: boolean;
loadHistory: () => Promise<void>;
clearHistory: () => Promise<void>;
sendMessage: (content: string, locale: string) => Promise<{ message: string; feedbackSaved?: boolean }>;
prependMessage: (msg: Message) => void;
pushMessage: (msg: Message) => void;
markFeedbackSaved: (id: string) => void;
setThinking: (v: boolean) => void;
setWelcomeBackShown: (v: boolean) => void;
reset: () => void;
};
export const useCoachStore = create<CoachState>((set, get) => ({
messages: [],
thinking: false,
historyLoaded: false,
welcomeBackShownThisSession: false,
loadHistory: async () => {
if (historyLoaded) {
set({ historyLoaded: true });
return;
}
historyLoaded = true;
const res = await apiFetch<{ messages: Array<{ role: 'user' | 'assistant'; content: string }> }>(
'/api/coach/history'
);
set({
messages: res.messages?.length
? res.messages.map((m, i) => ({ id: i.toString(), role: m.role, content: m.content }))
: [],
historyLoaded: true,
});
},
clearHistory: async () => {
await apiFetch('/api/coach/history', { method: 'DELETE' }).catch(() => null);
historyLoaded = false;
set({ messages: [], historyLoaded: false, welcomeBackShownThisSession: false });
},
sendMessage: async (content, locale) => {
const { messages } = get();
const res = await apiFetch<{ message: string; feedbackSaved?: boolean }>('/api/coach/message', {
method: 'POST',
body: {
messages: messages.filter((m) => !m.isError).map((m) => ({ role: m.role, content: m.content })),
locale,
},
});
return res;
},
prependMessage: (msg) => set((s) => ({ messages: [msg, ...s.messages] })),
pushMessage: (msg) => set((s) => ({ messages: [...s.messages, msg] })),
markFeedbackSaved: (id) =>
set((s) => ({
messages: s.messages.map((m) => (m.id === id ? { ...m, feedbackSaved: true } : m)),
})),
setThinking: (v) => set({ thinking: v }),
setWelcomeBackShown: (v) => set({ welcomeBackShownThisSession: v }),
reset: () => {
historyLoaded = false;
set({ messages: [], thinking: false, historyLoaded: false, welcomeBackShownThisSession: false });
},
}));