179 lines
4.9 KiB
TypeScript
179 lines
4.9 KiB
TypeScript
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);
|
|
}; |