update onboarding colors and add image upload

This commit is contained in:
Ra
2025-08-20 11:20:28 -07:00
parent 875280cdac
commit 9332a48542
12 changed files with 2078 additions and 426 deletions

View File

@@ -0,0 +1,179 @@
import { doc, setDoc, getDoc, updateDoc, deleteDoc } from 'firebase/firestore';
import { db } from './firebase';
import { processImage, validateImageFile, generateUniqueFileName, ProcessedImage } from '../utils/imageUtils';
export interface StoredImage {
id: string;
dataUrl: string;
filename: string;
originalSize: number;
compressedSize: number;
uploadedAt: number;
width: number;
height: number;
}
/**
* Upload and store an image in Firestore
* @param file - The image file to upload
* @param collectionName - Firestore collection name (e.g., 'company-logos')
* @param documentId - Document ID (e.g., orgId)
* @param maxWidth - Maximum width for resizing (default: 128)
* @param maxHeight - Maximum height for resizing (default: 128)
* @returns Promise with stored image data
*/
export const uploadImage = async (
file: File,
collectionName: string,
documentId: string,
maxWidth: number = 128,
maxHeight: number = 128
): Promise<StoredImage> => {
if (!db) {
throw new Error('Firebase not initialized');
}
// Validate the image file
const validation = validateImageFile(file);
if (!validation.valid) {
throw new Error(validation.error);
}
// Process the image
const processedImage: ProcessedImage = await processImage(file, maxWidth, maxHeight);
// Generate unique filename
const filename = generateUniqueFileName(file.name, 'logo');
// Create image data to store
const imageData: StoredImage = {
id: filename,
dataUrl: processedImage.dataUrl,
filename,
originalSize: processedImage.originalSize,
compressedSize: processedImage.compressedSize,
uploadedAt: Date.now(),
width: processedImage.width,
height: processedImage.height,
};
// Store in Firestore
const docRef = doc(db, collectionName, documentId);
try {
// Get existing document to preserve other data
const existingDoc = await getDoc(docRef);
if (existingDoc.exists()) {
// Update existing document
await updateDoc(docRef, {
logo: imageData,
updatedAt: Date.now(),
});
} else {
// Create new document
await setDoc(docRef, {
logo: imageData,
createdAt: Date.now(),
updatedAt: Date.now(),
});
}
return imageData;
} catch (error) {
console.error('Failed to store image in Firestore:', error);
throw new Error('Failed to upload image');
}
};
/**
* Retrieve an image from Firestore
* @param collectionName - Firestore collection name
* @param documentId - Document ID
* @returns Promise with stored image data or null if not found
*/
export const getImage = async (
collectionName: string,
documentId: string
): Promise<StoredImage | null> => {
if (!db) {
throw new Error('Firebase not initialized');
}
try {
const docRef = doc(db, collectionName, documentId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const data = docSnap.data();
return data.logo || null;
}
return null;
} catch (error) {
console.error('Failed to retrieve image from Firestore:', error);
return null;
}
};
/**
* Delete an image from Firestore
* @param collectionName - Firestore collection name
* @param documentId - Document ID
* @returns Promise indicating success
*/
export const deleteImage = async (
collectionName: string,
documentId: string
): Promise<boolean> => {
if (!db) {
throw new Error('Firebase not initialized');
}
try {
const docRef = doc(db, collectionName, documentId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const data = docSnap.data();
if (data.logo) {
// Remove only the logo field, keep other data
const updatedData = { ...data };
delete updatedData.logo;
updatedData.updatedAt = Date.now();
await updateDoc(docRef, updatedData);
return true;
}
}
return false;
} catch (error) {
console.error('Failed to delete image from Firestore:', error);
return false;
}
};
/**
* Company-specific image upload (convenience function)
*/
export const uploadCompanyLogo = async (
file: File,
orgId: string
): Promise<StoredImage> => {
return uploadImage(file, 'company-logos', orgId, 128, 128);
};
/**
* Get company logo (convenience function)
*/
export const getCompanyLogo = async (orgId: string): Promise<StoredImage | null> => {
return getImage('company-logos', orgId);
};
/**
* Delete company logo (convenience function)
*/
export const deleteCompanyLogo = async (orgId: string): Promise<boolean> => {
return deleteImage('company-logos', orgId);
};