update onboarding colors and add image upload
This commit is contained in:
179
services/imageStorageService.ts
Normal file
179
services/imageStorageService.ts
Normal 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);
|
||||
};
|
||||
Reference in New Issue
Block a user