Spaces:
Sleeping
Sleeping
| <script lang="ts"> | |
| import { rfpData, prevStep, resetApp } from '../stores/appStore' | |
| import { generateWordDocument, generateDocumentPreview } from '../utils/documentGenerator' | |
| $: answers = $rfpData.answers | |
| $: totalQuestions = answers.length | |
| $: finalizedAnswers = answers.filter(a => a.isFinalized) | |
| let isGenerating = false | |
| let downloadUrl: string | null = null | |
| let showPreview = false | |
| let previewContent = '' | |
| function openPreview() { | |
| previewContent = generateDocumentPreview(answers, { | |
| title: 'RFP Response Document', | |
| company: 'SEDNA Consulting Group', | |
| date: new Date().toLocaleDateString(), | |
| generatedBy: 'RFP Management System', | |
| rfpName: $rfpData.currentRFP?.rfpName, | |
| bidNumber: $rfpData.currentRFP?.bidNumber | |
| }) | |
| showPreview = true | |
| } | |
| function closePreview() { | |
| showPreview = false | |
| previewContent = '' | |
| } | |
| async function downloadWordDocument() { | |
| isGenerating = true | |
| try { | |
| const blob = await generateWordDocument(answers, { | |
| title: 'RFP Response Document', | |
| company: 'SEDNA Consulting Group', | |
| date: new Date().toLocaleDateString(), | |
| generatedBy: 'RFP Management System', | |
| rfpName: $rfpData.currentRFP?.rfpName, | |
| bidNumber: $rfpData.currentRFP?.bidNumber | |
| }) | |
| downloadUrl = URL.createObjectURL(blob) | |
| // Generate filename with RFP details | |
| const currentRfp = $rfpData.currentRFP | |
| let filename = 'RFP_Response' | |
| if (currentRfp?.bidNumber) { | |
| filename += `_${currentRfp.bidNumber.replace(/[^a-zA-Z0-9]/g, '_')}` | |
| } else if (currentRfp?.rfpName) { | |
| filename += `_${currentRfp.rfpName.substring(0, 30).replace(/[^a-zA-Z0-9]/g, '_')}` | |
| } | |
| filename += `_${new Date().toISOString().split('T')[0]}.docx` | |
| // Trigger download | |
| const link = document.createElement('a') | |
| link.href = downloadUrl | |
| link.download = filename | |
| document.body.appendChild(link) | |
| link.click() | |
| document.body.removeChild(link) | |
| } catch (error) { | |
| console.error('Error generating document:', error) | |
| alert('Error generating document. Please try again.') | |
| } finally { | |
| isGenerating = false | |
| } | |
| } | |
| function startNew() { | |
| if (downloadUrl) { | |
| URL.revokeObjectURL(downloadUrl) | |
| } | |
| resetApp() | |
| } | |
| function getCompletionPercentage(): number { | |
| return Math.round((finalizedAnswers.length / totalQuestions) * 100) | |
| } | |
| </script> | |
| <div class="max-w-5xl mx-auto"> | |
| <div class="bg-gray-800 border border-gray-600 rounded-lg shadow-lg p-8"> | |
| <!-- Success Header --> | |
| <div class="text-center mb-8"> | |
| <div class="mx-auto flex items-center justify-center h-16 w-16 rounded-full bg-green-900/20 mb-4"> | |
| <svg class="h-8 w-8 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" /> | |
| </svg> | |
| </div> | |
| <h2 class="text-3xl font-bold text-white mb-2"> | |
| RFP Response Complete! | |
| </h2> | |
| <p class="text-gray-300"> | |
| Your AI-enhanced RFP responses are ready for download | |
| </p> | |
| </div> | |
| <!-- RFP Information --> | |
| {#if $rfpData.currentRFP?.rfpName || $rfpData.currentRFP?.bidNumber} | |
| <div class="bg-blue-900/10 border border-blue-800/30 rounded-lg p-6 mb-8"> | |
| <h3 class="text-lg font-semibold text-blue-300 mb-3">RFP Details</h3> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| {#if $rfpData.currentRFP?.rfpName} | |
| <div> | |
| <div class="text-sm text-blue-200 mb-1">RFP Name</div> | |
| <div class="text-white font-medium">{$rfpData.currentRFP.rfpName}</div> | |
| </div> | |
| {/if} | |
| {#if $rfpData.currentRFP?.bidNumber} | |
| <div> | |
| <div class="text-sm text-blue-200 mb-1">Bid Number</div> | |
| <div class="text-white font-medium">{$rfpData.currentRFP.bidNumber}</div> | |
| </div> | |
| {/if} | |
| </div> | |
| <p class="text-blue-300/80 text-sm mt-3">This information will be included in the cover letter of your final document.</p> | |
| </div> | |
| {/if} | |
| <!-- Summary Stats --> | |
| <div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8"> | |
| <div class="bg-blue-900/20 p-6 rounded-lg border border-blue-800"> | |
| <div class="text-3xl font-bold text-blue-400 mb-2">{totalQuestions}</div> | |
| <div class="text-blue-200 font-medium">Total Questions</div> | |
| <div class="text-blue-400 text-sm">Answered</div> | |
| </div> | |
| <div class="bg-green-900/20 p-6 rounded-lg border border-green-800"> | |
| <div class="text-3xl font-bold text-green-400 mb-2">{finalizedAnswers.length}</div> | |
| <div class="text-green-200 font-medium">Finalized</div> | |
| <div class="text-green-400 text-sm">Ready for submission</div> | |
| </div> | |
| <div class="bg-purple-900/20 p-6 rounded-lg border border-purple-800"> | |
| <div class="text-3xl font-bold text-purple-400 mb-2"> | |
| {finalizedAnswers.reduce((sum, answer) => sum + (answer.citations?.length || 0), 0)} | |
| </div> | |
| <div class="text-purple-200 font-medium">Citations</div> | |
| <div class="text-purple-400 text-sm">From previous RFPs</div> | |
| </div> | |
| <div class="bg-orange-900/20 p-6 rounded-lg border border-orange-800"> | |
| <div class="text-3xl font-bold text-orange-400 mb-2">{getCompletionPercentage()}%</div> | |
| <div class="text-orange-200 font-medium">Complete</div> | |
| <div class="text-orange-400 text-sm">Ready to download</div> | |
| </div> | |
| </div> | |
| <!-- Document Preview --> | |
| <div class="mb-8"> | |
| <h3 class="text-xl font-semibold text-white mb-4">Document Preview</h3> | |
| <div class="bg-gray-700 rounded-lg p-6 border border-gray-600"> | |
| <div class="flex items-center mb-4"> | |
| <svg class="w-8 h-8 text-blue-400 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /> | |
| </svg> | |
| <div> | |
| <div class="font-semibold text-white">RFP Response Document</div> | |
| <div class="text-sm text-gray-400"> | |
| Generated on {new Date().toLocaleDateString()} • Microsoft Word Format (.docx) | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Answer Summary --> | |
| <div class="mb-8"> | |
| <h3 class="text-xl font-semibold text-white mb-4">Answer Summary</h3> | |
| <div class="space-y-3 max-h-64 overflow-y-auto"> | |
| {#each answers as answer, index} | |
| <div class="flex items-center justify-between p-3 bg-gray-700 rounded-lg border border-gray-600"> | |
| <div class="flex-1"> | |
| <div class="font-medium text-white text-sm"> | |
| Question {index + 1} | |
| </div> | |
| <div class="text-gray-400 text-sm truncate"> | |
| {answer.question} | |
| </div> | |
| </div> | |
| <div class="flex items-center space-x-3"> | |
| {#if answer.citations && answer.citations.length > 0} | |
| <div class="flex items-center text-xs text-blue-400"> | |
| <svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.746 0 3.332.477 4.5 1.253v13C19.832 18.477 18.246 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" /> | |
| </svg> | |
| {answer.citations.length} | |
| </div> | |
| {/if} | |
| <div class="w-6 h-6 rounded-full flex items-center justify-center { | |
| answer.isFinalized | |
| ? 'bg-green-900/20' | |
| : 'bg-gray-600' | |
| }"> | |
| {#if answer.isFinalized} | |
| <svg class="w-3 h-3 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" /> | |
| </svg> | |
| {/if} | |
| </div> | |
| </div> | |
| </div> | |
| {/each} | |
| </div> | |
| </div> | |
| <!-- Download Section --> | |
| <div class="bg-blue-900/20 rounded-lg p-6 border border-blue-800 mb-8"> | |
| <h3 class="text-lg font-semibold text-blue-100 mb-4"> | |
| Ready to Download | |
| </h3> | |
| <p class="text-blue-200 mb-6"> | |
| Your professionally formatted RFP response document is ready. | |
| </p> | |
| <div class="flex flex-col sm:flex-row gap-4"> | |
| <button | |
| class="flex-1 px-6 py-4 bg-purple-600 text-white rounded-lg font-medium hover:bg-purple-700 transition-colors flex items-center justify-center" | |
| on:click={openPreview} | |
| > | |
| <svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /> | |
| </svg> | |
| Preview Document | |
| </button> | |
| <button | |
| class="flex-1 px-6 py-4 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center" | |
| disabled={isGenerating || finalizedAnswers.length === 0} | |
| on:click={downloadWordDocument} | |
| > | |
| {#if isGenerating} | |
| <div class="animate-spin rounded-full h-5 w-5 border-b-2 border-white mr-3"></div> | |
| Generating Document... | |
| {:else} | |
| <svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /> | |
| </svg> | |
| Download Word Document | |
| {/if} | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Navigation Buttons --> | |
| <div class="flex justify-between"> | |
| <button | |
| class="px-6 py-3 bg-gray-700 text-gray-300 rounded-lg font-medium hover:bg-gray-600 transition-colors" | |
| on:click={prevStep} | |
| disabled={isGenerating} | |
| > | |
| <svg class="w-5 h-5 mr-2 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" /> | |
| </svg> | |
| Back to Review | |
| </button> | |
| <button | |
| class="px-6 py-3 bg-green-600 text-white rounded-lg font-medium hover:bg-green-700 transition-colors" | |
| on:click={startNew} | |
| disabled={isGenerating} | |
| > | |
| Start New RFP | |
| <svg class="w-5 h-5 ml-2 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" /> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Preview Modal --> | |
| {#if showPreview} | |
| <div class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black bg-opacity-75"> | |
| <div class="bg-gray-800 rounded-lg shadow-2xl w-full max-w-6xl h-5/6 flex flex-col"> | |
| <!-- Modal Header --> | |
| <div class="flex items-center justify-between p-6 border-b border-gray-600"> | |
| <div> | |
| <h3 class="text-xl font-semibold text-white">Document Preview</h3> | |
| <p class="text-gray-400 text-sm">Review your RFP response before downloading</p> | |
| </div> | |
| <div class="flex items-center space-x-3"> | |
| <button | |
| class="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors flex items-center" | |
| on:click={downloadWordDocument} | |
| > | |
| <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /> | |
| </svg> | |
| Download | |
| </button> | |
| <button | |
| class="p-2 text-gray-400 hover:text-white transition-colors" | |
| on:click={closePreview} | |
| > | |
| <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Modal Content --> | |
| <div class="flex-1 overflow-hidden"> | |
| <div class="h-full overflow-y-auto p-6"> | |
| <div class="bg-white rounded-lg p-8 text-gray-900 font-mono text-sm leading-relaxed shadow-inner"> | |
| {@html previewContent} | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Modal Footer --> | |
| <div class="flex items-center justify-between p-6 border-t border-gray-600"> | |
| <div class="text-sm text-gray-400"> | |
| This preview shows how your document will appear when downloaded. | |
| </div> | |
| <div class="flex space-x-3"> | |
| <button | |
| class="px-4 py-2 bg-gray-700 text-gray-300 rounded-lg font-medium hover:bg-gray-600 transition-colors" | |
| on:click={closePreview} | |
| > | |
| Close Preview | |
| </button> | |
| <button | |
| class="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors flex items-center" | |
| disabled={isGenerating} | |
| on:click={downloadWordDocument} | |
| > | |
| {#if isGenerating} | |
| <div class="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div> | |
| Generating... | |
| {:else} | |
| <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /> | |
| </svg> | |
| Download Word Document | |
| {/if} | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {/if} | |