import React, { useCallback, useEffect, useState } from 'react'; import type { StoreContextResponse } from '../../service/visibility/visibility.interface'; import { getStoreContext, editStoreContext, regenerateStoreContext, } from '../../service/visibility/visibility.service'; interface StoreContextPanelProps { /** Merchant client id. */ clientId: string; /** Merchant JWT. */ token: string; /** Brand whose context is shown. */ brandId: string; } interface ContextDraft { identity: string; proposes: string; does: string; topics: string; tone: string; } const draftFromContext = (context: StoreContextResponse): ContextDraft => ({ identity: context.identity, proposes: context.proposes, does: context.does, topics: context.topics.join(', '), tone: context.tone, }); const FIELD_CLASS = 'w-full rounded-md border border-gray-300 px-3 py-1.5 text-sm'; /** * "Your Knowledge Base" (Beta): the store's living, article-derived identity * that Reco keeps and uses. Self-contained - fetches on mount, lets the * merchant edit each field, and re-synthesizes from articles on demand. */ const StoreContextPanel: React.FC = ({ clientId, token, brandId, }) => { const [context, setContext] = useState(null); const [draft, setDraft] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [regenerating, setRegenerating] = useState(false); const [error, setError] = useState(null); const [status, setStatus] = useState(null); const apply = useCallback((fresh: StoreContextResponse) => { setContext(fresh); setDraft(draftFromContext(fresh)); }, []); useEffect(() => { let cancelled = false; setLoading(true); setError(null); getStoreContext(clientId, token, brandId) .then(fresh => { if (!cancelled) apply(fresh); }) .catch(() => { if (!cancelled) setError("Couldn't load your knowledge base."); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [clientId, token, brandId, apply]); const patch = (key: keyof ContextDraft, value: string) => { setDraft(prev => (prev ? { ...prev, [key]: value } : prev)); setStatus(null); }; const handleSave = async () => { if (!draft) return; setSaving(true); setError(null); setStatus(null); try { const fresh = await editStoreContext(clientId, token, brandId, { identity: draft.identity.trim(), proposes: draft.proposes.trim(), does: draft.does.trim(), tone: draft.tone.trim(), topics: draft.topics .split(',') .map(topic => topic.trim()) .filter(Boolean), }); apply(fresh); setStatus('Saved. Recomaze Co-pilot will use this.'); } catch { setError("Couldn't save your changes."); } finally { setSaving(false); } }; const handleRegenerate = async () => { setRegenerating(true); setError(null); setStatus(null); try { const fresh = await regenerateStoreContext(clientId, token, brandId); apply(fresh); setStatus( fresh.exists ? 'Rebuilt from your articles.' : 'No finished articles yet - publish a few, then regenerate.' ); } catch { setError("Couldn't regenerate from your articles."); } finally { setRegenerating(false); } }; return (
Your Knowledge Base Beta

What Recomaze Co-pilot has learned about your store from the content you have published. Recomaze Co-pilot uses this across chat and new articles. Edit anything; your words win.

{loading ? (
Loading...
) : (
{context && !context.exists && (

Nothing learned yet. Once you have published articles, use the Regenerate from articles button to build this.

)}