CA-Foundation / frontend /src /utils /conversationStorage.js
“vinit5112”
Add all code
deb090d
raw
history blame
6.61 kB
/**
* Conversation Storage Utility
* Handles conversation persistence with localStorage
*/
const STORAGE_KEY = 'ca_study_conversations';
const MAX_CONVERSATIONS = 50; // Limit to prevent localStorage overflow
export class ConversationStorage {
/**
* Load all conversations from localStorage
*/
static loadConversations() {
try {
const stored = localStorage.getItem(STORAGE_KEY);
if (!stored) return [];
const conversations = JSON.parse(stored);
// Convert date strings back to Date objects
return conversations.map(conv => ({
...conv,
createdAt: new Date(conv.createdAt),
messages: conv.messages.map(msg => ({
...msg,
timestamp: new Date(msg.timestamp)
}))
}));
} catch (error) {
console.error('Error loading conversations:', error);
return [];
}
}
/**
* Save conversations to localStorage
*/
static saveConversations(conversations) {
try {
// Limit the number of conversations to prevent localStorage overflow
const limitedConversations = conversations.slice(0, MAX_CONVERSATIONS);
localStorage.setItem(STORAGE_KEY, JSON.stringify(limitedConversations));
return true;
} catch (error) {
console.error('Error saving conversations:', error);
// Handle localStorage quota exceeded
if (error.name === 'QuotaExceededError') {
// Try to save with fewer conversations
const reducedConversations = conversations.slice(0, 25);
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(reducedConversations));
return true;
} catch (retryError) {
console.error('Error saving reduced conversations:', retryError);
}
}
return false;
}
}
/**
* Add a new conversation
*/
static addConversation(conversation) {
const conversations = this.loadConversations();
const newConversations = [conversation, ...conversations];
return this.saveConversations(newConversations);
}
/**
* Update an existing conversation
*/
static updateConversation(conversationId, updates) {
const conversations = this.loadConversations();
const updatedConversations = conversations.map(conv =>
conv.id === conversationId ? { ...conv, ...updates } : conv
);
return this.saveConversations(updatedConversations);
}
/**
* Delete a conversation
*/
static deleteConversation(conversationId) {
const conversations = this.loadConversations();
const filteredConversations = conversations.filter(conv => conv.id !== conversationId);
return this.saveConversations(filteredConversations);
}
/**
* Add a message to a conversation
*/
static addMessage(conversationId, message) {
const conversations = this.loadConversations();
const updatedConversations = conversations.map(conv => {
if (conv.id === conversationId) {
return {
...conv,
messages: [...conv.messages, message],
updatedAt: new Date()
};
}
return conv;
});
return this.saveConversations(updatedConversations);
}
/**
* Search conversations by title or content
*/
static searchConversations(query) {
const conversations = this.loadConversations();
const lowercaseQuery = query.toLowerCase();
return conversations.filter(conv =>
conv.title.toLowerCase().includes(lowercaseQuery) ||
conv.messages.some(msg =>
msg.content.toLowerCase().includes(lowercaseQuery)
)
);
}
/**
* Get conversation statistics
*/
static getStatistics() {
const conversations = this.loadConversations();
const totalMessages = conversations.reduce((sum, conv) => sum + conv.messages.length, 0);
return {
totalConversations: conversations.length,
totalMessages,
storageSize: this.getStorageSize(),
oldestConversation: conversations.length > 0 ?
conversations[conversations.length - 1].createdAt : null,
newestConversation: conversations.length > 0 ?
conversations[0].createdAt : null
};
}
/**
* Get storage size in KB
*/
static getStorageSize() {
try {
const stored = localStorage.getItem(STORAGE_KEY);
return stored ? Math.round(new Blob([stored]).size / 1024) : 0;
} catch (error) {
return 0;
}
}
/**
* Export conversations as JSON
*/
static exportConversations() {
const conversations = this.loadConversations();
const exportData = {
exportDate: new Date().toISOString(),
version: '1.0',
conversations
};
const blob = new Blob([JSON.stringify(exportData, null, 2)], {
type: 'application/json'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `ca_study_conversations_${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
/**
* Import conversations from JSON file
*/
static importConversations(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
try {
const importData = JSON.parse(e.target.result);
if (!importData.conversations || !Array.isArray(importData.conversations)) {
reject(new Error('Invalid conversation file format'));
return;
}
const existingConversations = this.loadConversations();
const mergedConversations = [...importData.conversations, ...existingConversations];
// Remove duplicates based on ID
const uniqueConversations = mergedConversations.filter((conv, index, self) =>
index === self.findIndex(c => c.id === conv.id)
);
const success = this.saveConversations(uniqueConversations);
resolve({ success, count: importData.conversations.length });
} catch (error) {
reject(error);
}
};
reader.onerror = () => reject(new Error('Error reading file'));
reader.readAsText(file);
});
}
/**
* Clear all conversations
*/
static clearAllConversations() {
try {
localStorage.removeItem(STORAGE_KEY);
return true;
} catch (error) {
console.error('Error clearing conversations:', error);
return false;
}
}
}
export default ConversationStorage;