spb/vquant Public MIT
VibeQuant — AI-powered institutional-grade financial intelligence platform.
TypeScript 84.3%
Python 11.7%
JavaScript 1.6%
CSS 1.5%
HTML 0.7%
1/*2 * =============================================================================3 * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform4 * -----------------------------------------------------------------------------5 * File: client/src/components/chat/download-buttons.tsx6 *7 * Author: Simon-Pierre Boucher8 * Contact: contact@spboucher.ai9 * Website: https://www.spboucher.ai10 * Demo: https://www.vquant.ai11 * License: MIT (see LICENSE)12 *13 * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.14 * =============================================================================15 */1617import { FileText, FileDown, FileType, Loader2, Presentation } from "lucide-react";18import { Button } from "@/components/ui/button";19import { useState } from "react";20import { useToast } from "@/hooks/use-toast";21import { useLocation } from "wouter";2223interface DownloadButtonsProps {24 question: string;25 answer: string;26 contentRef?: React.RefObject<HTMLElement>;27 figureUrls?: string[];28}2930export function DownloadButtons({ question, answer, contentRef, figureUrls = [] }: DownloadButtonsProps) {31 const [isGeneratingPDF, setIsGeneratingPDF] = useState(false);32 const [isGeneratingDOCX, setIsGeneratingDOCX] = useState(false);33 const { toast } = useToast();34 const [, setLocation] = useLocation();3536 const handleDownloadMarkdown = () => {37 const content = answer;38 const blob = new Blob([content], { type: 'text/markdown' });39 const url = URL.createObjectURL(blob);40 const a = document.createElement('a');41 a.href = url;42 a.download = `vibequant-${Date.now()}.md`;43 document.body.appendChild(a);44 a.click();45 document.body.removeChild(a);46 URL.revokeObjectURL(url);4748 toast({49 title: "Téléchargement réussi",50 description: "Le fichier Markdown a été téléchargé avec succès.",51 });52 };5354 const handleDownloadPDF = async () => {55 setIsGeneratingPDF(true);5657 try {58 const response = await fetch('/api/generate-pdf', {59 method: 'POST',60 headers: {61 'Content-Type': 'application/json',62 },63 body: JSON.stringify({64 question,65 answer66 }),67 });6869 if (!response.ok) {70 throw new Error('Failed to generate PDF');71 }7273 const blob = await response.blob();74 const url = URL.createObjectURL(blob);75 const a = document.createElement('a');76 a.href = url;77 a.download = `vibequant-${Date.now()}.pdf`;78 document.body.appendChild(a);79 a.click();80 document.body.removeChild(a);81 URL.revokeObjectURL(url);8283 toast({84 title: "PDF généré avec succès",85 description: "Le rapport PDF a été téléchargé.",86 });87 } catch (error) {88 console.error('Error generating PDF:', error);89 toast({90 title: "Erreur de génération",91 description: "Une erreur s'est produite lors de la génération du PDF. Veuillez réessayer.",92 variant: "destructive",93 });94 } finally {95 setIsGeneratingPDF(false);96 }97 };9899 const handleDownloadDOCX = async () => {100 setIsGeneratingDOCX(true);101102 try {103 const response = await fetch('/api/generate-docx', {104 method: 'POST',105 headers: {106 'Content-Type': 'application/json',107 },108 body: JSON.stringify({109 question,110 answer111 }),112 });113114 if (!response.ok) {115 throw new Error('Failed to generate Word document');116 }117118 const blob = await response.blob();119 const url = URL.createObjectURL(blob);120 const a = document.createElement('a');121 a.href = url;122 a.download = `vibequant-${Date.now()}.docx`;123 document.body.appendChild(a);124 a.click();125 document.body.removeChild(a);126 URL.revokeObjectURL(url);127128 toast({129 title: "Word généré avec succès",130 description: "Le document Word a été téléchargé.",131 });132 } catch (error) {133 console.error('Error generating DOCX:', error);134 toast({135 title: "Erreur de génération",136 description: "Une erreur s'est produite lors de la génération du Word. Veuillez réessayer.",137 variant: "destructive",138 });139 } finally {140 setIsGeneratingDOCX(false);141 }142 };143144 const handleConvertToSlides = () => {145 // Store content in sessionStorage to pass to slides generator page146 sessionStorage.setItem('slidesContent', JSON.stringify({ question, answer, figureUrls }));147 setLocation('/slides-generator');148149 toast({150 title: "Redirection...",151 description: "Ouverture du générateur de slides",152 });153 };154155 return (156 <>157 <Button158 variant="outline"159 size="sm"160 onClick={handleDownloadMarkdown}161 className="gap-2 hover:bg-muted transition-colors"162 disabled={isGeneratingPDF}163 >164 <FileText className="w-4 h-4" />165 <span className="hidden sm:inline">Télécharger MD</span>166 </Button>167 <Button168 variant="outline"169 size="sm"170 onClick={handleDownloadPDF}171 className="gap-2 hover:bg-muted transition-colors"172 disabled={isGeneratingPDF}173 >174 {isGeneratingPDF ? (175 <>176 <Loader2 className="w-4 h-4 animate-spin" />177 <span className="hidden sm:inline">Génération...</span>178 </>179 ) : (180 <>181 <FileDown className="w-4 h-4" />182 <span className="hidden sm:inline">Télécharger PDF</span>183 </>184 )}185 </Button>186 <Button187 variant="outline"188 size="sm"189 onClick={handleDownloadDOCX}190 className="gap-2 hover:bg-muted transition-colors"191 disabled={isGeneratingDOCX}192 >193 {isGeneratingDOCX ? (194 <>195 <Loader2 className="w-4 h-4 animate-spin" />196 <span className="hidden sm:inline">Génération...</span>197 </>198 ) : (199 <>200 <FileType className="w-4 h-4" />201 <span className="hidden sm:inline">Télécharger Word</span>202 </>203 )}204 </Button>205 <Button206 variant="outline"207 size="sm"208 onClick={handleConvertToSlides}209 className="gap-2 hover:bg-muted transition-colors"210 disabled={isGeneratingPDF || isGeneratingDOCX || !question || !answer}211 >212 <Presentation className="w-4 h-4" />213 <span className="hidden sm:inline">Convertir en Slides</span>214 </Button>215 </>216 );217}218