fix(chat): buttons always visible on last msg + preview panel outside scroll zone
Some checks failed
Deploy to Production / Build and Deploy (push) Has been cancelled

This commit is contained in:
2026-05-03 01:28:54 +02:00
parent af6e7a2cdf
commit 0f48df114a
2 changed files with 110 additions and 4 deletions

View File

@@ -0,0 +1,54 @@
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, '..', 'components', 'contextual-ai-chat.tsx');
let src = fs.readFileSync(filePath, 'utf8');
// ─── FIX 1: make inject buttons always visible on last assistant msg ──────────
// Replace the hover-gated condition with always-visible for last msg
const OLD_BUTTONS_CONDITION = ` {/* Hover-actions \u2014 visible only on assistant messages */}\r\n {isAssistant && onApplyToNote && (\r\n <div className={cn(\r\n 'flex gap-1 transition-all duration-150',\r\n isHovered ? 'opacity-100 translate-y-0' : 'opacity-0 -translate-y-1 pointer-events-none',\r\n )}>`;
const NEW_BUTTONS_CONDITION = ` {/* Inject buttons \u2014 always visible on last assistant msg */}\r\n {isAssistant && onApplyToNote && (() => {\r\n const lastAssistantId = messages.filter(m => m.role === 'assistant').at(-1)?.id\r\n const alwaysShow = msg.id === lastAssistantId\r\n return (\r\n <div className={cn(\r\n 'flex gap-1 transition-all duration-150',\r\n (alwaysShow || isHovered) ? 'opacity-100' : 'opacity-0 pointer-events-none',\r\n )}>`;
// Also need to close the IIFE
const OLD_BUTTONS_CLOSE = ` </div>\r\n )}\r\n </div>`;
const NEW_BUTTONS_CLOSE = ` </div>\r\n )\r\n })()}\r\n </div>`;
if (src.includes(OLD_BUTTONS_CONDITION)) {
src = src.replace(OLD_BUTTONS_CONDITION, NEW_BUTTONS_CONDITION);
console.log('Fix 1a: buttons condition updated');
} else {
console.error('Fix 1a: OLD_BUTTONS_CONDITION not found!');
process.exit(1);
}
if (src.includes(OLD_BUTTONS_CLOSE)) {
src = src.replace(OLD_BUTTONS_CLOSE, NEW_BUTTONS_CLOSE);
console.log('Fix 1b: buttons IIFE close updated');
} else {
console.error('Fix 1b: OLD_BUTTONS_CLOSE not found!');
process.exit(1);
}
// ─── FIX 2: Move preview panel OUTSIDE the scrollable div ────────────────────
// The scrollable div ends with: messagesEndRef then </div>
// We need to:
// A) Remove the preview block from inside the scrollable area (already was removed in previous sessions since it was added after messagesEndRef)
// B) Add preview as shrink-0 panel between the scroll div and controls
// Find the closing of the scrollable area + start of controls
const OLD_SCROLL_END = ` <div ref={messagesEndRef} />\r\n </div>\r\n\r\n {/* Scope & Tone Control Area */}`;
const NEW_SCROLL_END = ` <div ref={messagesEndRef} />\r\n </div>\r\n\r\n {/* \u2550\u2550 Inject Preview Panel \u2014 fixed, always visible, NO scroll needed \u2550\u2550 */}\r\n {resourceEnriching && (\r\n <div className="shrink-0 mx-3 mb-2 flex items-center gap-2 rounded-xl border border-emerald-500/30 bg-emerald-50/50 dark:bg-emerald-950/20 p-3">\r\n <Loader2 className="h-3.5 w-3.5 animate-spin text-emerald-600 shrink-0" />\r\n <span className="text-xs text-emerald-700 dark:text-emerald-400">Traitement IA en cours...</span>\r\n </div>\r\n )}\r\n {resourcePreview && !resourceEnriching && (\r\n <div className="shrink-0 mx-3 mb-2 rounded-xl border border-primary/30 bg-primary/5 overflow-hidden">\r\n <div className="flex items-center justify-between px-3 py-2 border-b border-primary/20">\r\n <span className="text-[10px] font-semibold uppercase tracking-wider text-primary">\r\n {resourcePreview.source === 'complete' ? 'Compl\u00e9t\u00e9 par IA'\r\n : resourcePreview.source === 'merge' ? 'Fusionn\u00e9 par IA'\r\n : 'Aper\u00e7u'}\r\n </span>\r\n <button onClick={() => setResourcePreview(null)} className="text-muted-foreground hover:text-foreground">\r\n <X className="h-3 w-3" />\r\n </button>\r\n </div>\r\n <div className="px-3 py-2 max-h-36 overflow-y-auto text-sm">\r\n <MarkdownContent content={resourcePreview.text} />\r\n </div>\r\n <div className="flex gap-2 px-3 py-2 border-t border-primary/20">\r\n <button\r\n onClick={() => setResourcePreview(null)}\r\n className="flex-1 text-[11px] py-1.5 rounded-lg border border-border/60 text-muted-foreground hover:bg-muted transition-colors"\r\n >\r\n Annuler\r\n </button>\r\n <button\r\n onClick={() => {\r\n if (onApplyToNote && resourcePreview) {\r\n onApplyToNote(resourcePreview.text)\r\n setResourcePreview(null)\r\n setResourceText('')\r\n toast.success('Appliqu\u00e9 \u00e0 la note')\r\n }\r\n }}\r\n disabled={!onApplyToNote}\r\n className="flex-1 text-[11px] py-1.5 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors disabled:opacity-50 flex items-center justify-center gap-1"\r\n >\r\n <Check className="h-3 w-3" />\r\n Appliquer \u00e0 la note\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Scope & Tone Control Area */}`;
if (src.includes(OLD_SCROLL_END)) {
src = src.replace(OLD_SCROLL_END, NEW_SCROLL_END);
console.log('Fix 2: preview panel moved outside scroll');
} else {
console.error('Fix 2: OLD_SCROLL_END not found!');
// Show what we're looking for context
const idx = src.indexOf('messagesEndRef');
console.error('Context around messagesEndRef:', JSON.stringify(src.slice(idx-20, idx+200)));
process.exit(1);
}
fs.writeFileSync(filePath, src);
console.log('Done!');