Accueil

import { useState, useRef, useEffect } from « react »;

const SYSTEM_PROMPT = `Tu es un formateur expert et pédagogue en Pôle 2 – Négociation à distance et digitalisation du BTS NDRC (Brevet de Technicien Supérieur en Négociation à Distance et Relation client). Tu connais parfaitement le référentiel du BTS NDRC ainsi que la progression pédagogique du Pôle 2. Tu es aussi un expert en WordPress avec le thème Astra et les extensions Spectra et Yoast SEO ainsi qu’en Prestashop.

MISSION : Tu accompagnes les étudiants en BTS NDRC dans leurs révisions de la matière Pôle 2 tout au long des deux années d’études pour les préparer aux examens. Tu réponds à leurs questions, proposes des quiz et des exercices. Quand tu ne sais pas, tu les rediriges vers leurs formateurs.

TONALITÉ : Pédagogique, bienveillant, encourageant. Tu utilises le vouvoiement. Tu expliques toujours les notions utilisées. Tu cherches à accroître la motivation de l’apprenant.

FORMAT DES RÉPONSES :
– Résumé avec notions importantes en gras
– Listes à puces
– Propositions de quiz et exercices pour vérifier l’ancrage des savoirs
– Tableaux si utile

PROCESSUS :
1. Comprendre la question (théorie, pratique, exercice ?)
2. Adapter au niveau de l’étudiant (1ère ou 2ème année)
3. Structurer : introduction courte → développement → exemple concret → résumé
4. Toujours vérifier la compréhension avec une question ou un mini-exercice
5. Feedback bienveillant et adaptatif

CONTRAINTES ABSOLUES :
– Respecter strictement le référentiel BTS NDRC Pôle 2
– Ne jamais faire le travail à la place de l’étudiant pour un devoir évalué
– Ne jamais inventer des sources, référentiels ou fonctionnalités
– Ne jamais juger l’apprenant
– Toujours contextualiser dans des situations professionnelles réelles (prospection, négociation à distance, CRM, e-commerce, relation client digitale)
– Favoriser l’apprentissage actif : toujours inclure une question, un exercice ou une mise en situation
– Si incertain → demander clarification. Si hors compétence → rediriger vers le formateur

AMORCE : À la première prise de contact, saluer l’apprenant, lui demander où il se situe dans le programme, et lui proposer un quiz récapitulatif ou des exercices.`;

const STORAGE_KEY = « bts_ndrc_sessions »;

function loadSessions() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
return raw ? JSON.parse(raw) : [];
} catch { return []; }
}

function saveSessions(sessions) {
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(sessions)); } catch {}
}

function formatDate(iso) {
const d = new Date(iso);
return d.toLocaleDateString(« fr-FR », { day: « 2-digit », month: « short », hour: « 2-digit », minute: « 2-digit » });
}

function getPreview(messages) {
const first = messages.find(m => m.role === « user »);
return first ? first.content.slice(0, 48) + (first.content.length > 48 ? « … » : «  ») : « Session vide »;
}

export default function App() {
const [sessions, setSessions] = useState(loadSessions);
const [activeId, setActiveId] = useState(null);
const [messages, setMessages] = useState([]);
const [input, setInput] = useState(«  »);
const [loading, setLoading] = useState(false);
const [sidebarOpen, setSidebarOpen] = useState(true);
const bottomRef = useRef(null);
const fileRef = useRef(null);

useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: « smooth » }); }, [messages, loading]);

const persistSession = (id, msgs) => {
setSessions(prev => {
const existing = prev.find(s => s.id === id);
let updated;
if (existing) {
updated = prev.map(s => s.id === id ? { …s, messages: msgs, updatedAt: new Date().toISOString() } : s);
} else {
updated = [{ id, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), messages: msgs }, …prev];
}
saveSessions(updated);
return updated;
});
};

const newSession = async () => {
const id = Date.now().toString();
setActiveId(id);
setMessages([]);
setLoading(true);
setSidebarOpen(false);
try {
const res = await fetch(« https://api.anthropic.com/v1/messages », {
method: « POST »,
headers: { « Content-Type »: « application/json » },
body: JSON.stringify({
model: « claude-sonnet-4-20250514 »,
max_tokens: 1000,
system: SYSTEM_PROMPT,
messages: [{ role: « user », content: « Bonjour, commence la session. » }]
})
});
const data = await res.json();
const text = data.content?.map(b => b.text || «  »).join(«  ») || « Bonjour ! »;
const initMsgs = [{ role: « assistant », content: text }];
setMessages(initMsgs);
persistSession(id, initMsgs);
} catch {
const errMsgs = [{ role: « assistant », content: « Une erreur est survenue. Veuillez réessayer. » }];
setMessages(errMsgs);
persistSession(id, errMsgs);
}
setLoading(false);
};

const openSession = (s) => {
setActiveId(s.id);
setMessages(s.messages);
setSidebarOpen(false);
};

const deleteSession = (e, id) => {
e.stopPropagation();
setSessions(prev => { const u = prev.filter(s => s.id !== id); saveSessions(u); return u; });
if (activeId === id) { setActiveId(null); setMessages([]); }
};

const sendMessage = async () => {
if (!input.trim() || loading || !activeId) return;
const userMsg = { role: « user », content: input.trim() };
const newMessages = […messages, userMsg];
setMessages(newMessages);
setInput(«  »);
setLoading(true);
try {
const res = await fetch(« https://api.anthropic.com/v1/messages », {
method: « POST »,
headers: { « Content-Type »: « application/json » },
body: JSON.stringify({
model: « claude-sonnet-4-20250514 »,
max_tokens: 1000,
system: SYSTEM_PROMPT,
messages: newMessages
})
});
const data = await res.json();
const text = data.content?.map(b => b.text || «  »).join(«  ») || « Je n’ai pas pu répondre. »;
const finalMsgs = […newMessages, { role: « assistant », content: text }];
setMessages(finalMsgs);
persistSession(activeId, finalMsgs);
} catch {
const errMsgs = […newMessages, { role: « assistant », content: « Une erreur est survenue. » }];
setMessages(errMsgs);
persistSession(activeId, errMsgs);
}
setLoading(false);
};

const handleKey = (e) => {
if (e.key === « Enter » && !e.shiftKey) { e.preventDefault(); sendMessage(); }
};

const formatText = (text) => {
return text.split(« \n »).map((line, i) => {
line = line.replace(/\*\*(.*?)\*\*/g, (_, m) => `${m}`);
if (/^[-•]\s/.test(line)) return

  • ;
    if (/^\d+\.\s/.test(line)) return

  • ;
    if (line.trim() === «  ») return
    ;
    return

    ;
    });
    };

    const blue = « #1a237e », lightBlue = « #1565c0 »;

    return (

    {/* Sidebar */}

    🎓 BTS NDRC – Pôle 2
    Assistant de révision

    {/* Sessions list */}

    {sessions.length === 0 ? (

    Aucune session

    ) : (
    sessions.map(s => (

    openSession(s)} style={{ background: activeId === s.id ? « rgba(255,255,255,0.2) » : « rgba(255,255,255,0.06) », borderRadius: 10, padding: « 9px 10px », marginBottom: 6, cursor: « pointer », display: « flex », justifyContent: « space-between », alignItems: « flex-start », border: activeId === s.id ? « 1px solid rgba(255,255,255,0.3) » : « 1px solid transparent » }}>

    {getPreview(s.messages)}
    {formatDate(s.updatedAt)}

    ))
    )}

    {/* Main */}

    {/* Topbar */}

    Pôle 2 – Négociation à distance & Digitalisation

    {activeId &&

    {messages.length} message{messages.length > 1 ? « s » : «  »}

    }

    {/* Chat */}

    {!activeId ? (

    📚
    Bienvenue dans votre assistant de révision
    Créez une nouvelle session ou reprenez une session précédente depuis l’historique.

    ) : (
    <>
    {messages.map((m, i) => (

    {m.role === « assistant » && (

    🎓

    )}

    {m.role === « assistant » ? formatText(m.content) : m.content}

    ))}
    {loading && (

    🎓

    {[0,1,2].map(j => )}

    )}


    )}

    {/* Input */}
    {activeId && (