Spaces:
Sleeping
Sleeping
| import { writable } from 'svelte/store' | |
| import { backendService, type StoredDocument } from '../utils/backendService' | |
| // Interface for reference documents stored in backend | |
| export interface ReferenceDocument extends StoredDocument { | |
| // Inherits: id, name, category, fileType, uploadDate, size | |
| } | |
| // Interface for current RFP (metadata only, not stored in backend) | |
| export interface CurrentRFPDocument { | |
| id: string | |
| name: string | |
| size: number | |
| uploadDate: string | |
| pageCount?: number | |
| quality?: string | |
| keyTopics?: string[] | |
| wordCount?: number | |
| fileType?: string | |
| // RFP specific metadata | |
| rfpName?: string | |
| bidNumber?: string | |
| // Note: No content field - this is metadata only | |
| } | |
| export interface Question { | |
| id: string | |
| text: string | |
| selected: boolean | |
| priority: 'high' | 'medium' | 'low' | |
| source?: string | |
| } | |
| export interface RFPAnswer { | |
| id: string | |
| question: string | |
| previousAnswer?: string | |
| aiGeneratedAnswer?: string | |
| finalAnswer?: string | |
| source?: string | |
| pageNumber?: number | |
| isFinalized: boolean | |
| isFormatted?: boolean | |
| hasAdditionalInfo?: boolean | |
| additionalInfo?: string | |
| citations: string[] | |
| } | |
| export interface RFPData { | |
| currentRFP: CurrentRFPDocument | null // Changed from previousRFPs array | |
| newQuestions: File | null | |
| questions: string[] | |
| answers: RFPAnswer[] | |
| extractedData: any[] | |
| } | |
| export interface AppState { | |
| currentStep: number | |
| isLoading: boolean | |
| error: string | null | |
| } | |
| // App state stores | |
| // LocalStorage keys | |
| const STORAGE_KEYS = { | |
| CURRENT_STEP: 'rfp_current_step', | |
| CURRENT_RFP: 'rfp_current_rfp', // Changed from PREVIOUS_RFPS | |
| QUESTIONS: 'rfp_questions', | |
| ANSWERS: 'rfp_answers', | |
| RFP_DATA: 'rfp_data' | |
| } | |
| // Load data from localStorage | |
| function loadFromStorage<T>(key: string, defaultValue: T): T { | |
| if (typeof window === 'undefined') return defaultValue | |
| try { | |
| const stored = localStorage.getItem(key) | |
| return stored ? JSON.parse(stored) : defaultValue | |
| } catch (error) { | |
| console.warn(`Failed to load ${key} from localStorage:`, error) | |
| return defaultValue | |
| } | |
| } | |
| // Save data to localStorage | |
| function saveToStorage<T>(key: string, value: T): void { | |
| if (typeof window === 'undefined') return | |
| try { | |
| localStorage.setItem(key, JSON.stringify(value)) | |
| } catch (error) { | |
| console.warn(`Failed to save ${key} to localStorage:`, error) | |
| } | |
| } | |
| export const currentStep = writable<number>(loadFromStorage(STORAGE_KEYS.CURRENT_STEP, 1)) | |
| export const isLoading = writable<boolean>(false) | |
| export const error = writable<string | null>(null) | |
| // Store for reference documents (managed by backend) | |
| export const referenceDocuments = writable<ReferenceDocument[]>([]) | |
| // Store for current RFP (metadata only, localStorage) | |
| export const currentRfp = writable<CurrentRFPDocument | null>(loadFromStorage(STORAGE_KEYS.CURRENT_RFP, null)) | |
| // Other stores with localStorage persistence | |
| export const questions = writable<Question[]>(loadFromStorage(STORAGE_KEYS.QUESTIONS, [])) | |
| export const answers = writable<RFPAnswer[]>(loadFromStorage(STORAGE_KEYS.ANSWERS, [])) | |
| // Legacy RFP data store (updated structure) | |
| export const rfpData = writable<RFPData>(loadFromStorage(STORAGE_KEYS.RFP_DATA, { | |
| currentRFP: null, | |
| newQuestions: null, | |
| questions: [], | |
| answers: [], | |
| extractedData: [] | |
| })) | |
| // Subscribe to store changes and save to localStorage | |
| currentStep.subscribe(value => saveToStorage(STORAGE_KEYS.CURRENT_STEP, value)) | |
| currentRfp.subscribe(value => saveToStorage(STORAGE_KEYS.CURRENT_RFP, value)) | |
| questions.subscribe(value => saveToStorage(STORAGE_KEYS.QUESTIONS, value)) | |
| answers.subscribe(value => saveToStorage(STORAGE_KEYS.ANSWERS, value)) | |
| rfpData.subscribe(value => saveToStorage(STORAGE_KEYS.RFP_DATA, value)) | |
| // Helper functions | |
| export function nextStep() { | |
| currentStep.update(step => Math.min(step + 1, 5)) | |
| } | |
| export function prevStep() { | |
| currentStep.update(step => Math.max(step - 1, 1)) | |
| } | |
| export function resetApp() { | |
| currentStep.set(1) | |
| isLoading.set(false) | |
| error.set(null) | |
| referenceDocuments.set([]) | |
| currentRfp.set(null) | |
| questions.set([]) | |
| answers.set([]) | |
| rfpData.set({ | |
| currentRFP: null, | |
| newQuestions: null, | |
| questions: [], | |
| answers: [], | |
| extractedData: [] | |
| }) | |
| // Clear localStorage | |
| if (typeof window !== 'undefined') { | |
| Object.values(STORAGE_KEYS).forEach(key => { | |
| localStorage.removeItem(key) | |
| }) | |
| } | |
| } | |
| // Function to clear current RFP (keeping reference documents in backend) | |
| export function clearCurrentRfp() { | |
| currentRfp.set(null) | |
| if (typeof window !== 'undefined') { | |
| localStorage.removeItem(STORAGE_KEYS.CURRENT_RFP) | |
| } | |
| } | |
| // Backend service functions | |
| export async function loadReferenceDocuments() { | |
| try { | |
| isLoading.set(true) | |
| error.set(null) | |
| // Check backend health first | |
| const isHealthy = await backendService.healthCheck() | |
| if (!isHealthy) { | |
| throw new Error('Backend server is not responding') | |
| } | |
| const documents = await backendService.getPreviousRFPs() | |
| referenceDocuments.set(documents) | |
| console.log(`✅ Loaded ${documents.length} reference documents from backend`) | |
| } catch (err) { | |
| const errorMessage = err instanceof Error ? err.message : 'Failed to load reference documents' | |
| error.set(errorMessage) | |
| console.warn('❌ Failed to load reference documents:', errorMessage) | |
| // Set empty array if backend fails | |
| referenceDocuments.set([]) | |
| } finally { | |
| isLoading.set(false) | |
| } | |
| } | |
| export async function uploadReferenceDocument(file: File, category: string) { | |
| try { | |
| isLoading.set(true) | |
| const document = await backendService.uploadPreviousRFP(file, category) | |
| // Add to current list | |
| referenceDocuments.update(docs => [...docs, document]) | |
| return document | |
| } catch (err) { | |
| error.set(err instanceof Error ? err.message : 'Failed to upload document') | |
| throw err | |
| } finally { | |
| isLoading.set(false) | |
| } | |
| } | |
| export async function deleteReferenceDocument(id: string) { | |
| try { | |
| isLoading.set(true) | |
| await backendService.deleteDocument(id) | |
| // Remove from current list | |
| referenceDocuments.update(docs => docs.filter(doc => doc.id !== id)) | |
| } catch (err) { | |
| error.set(err instanceof Error ? err.message : 'Failed to delete document') | |
| throw err | |
| } finally { | |
| isLoading.set(false) | |
| } | |
| } | |
| export async function getDocumentContent(id: string) { | |
| try { | |
| return await backendService.getDocumentContent(id) | |
| } catch (err) { | |
| error.set(err instanceof Error ? err.message : 'Failed to get document content') | |
| throw err | |
| } | |
| } | |