Update
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { doc, setDoc, getDoc, updateDoc, deleteDoc } from 'firebase/firestore';
|
||||
import { db } from './firebase';
|
||||
import { processImage, validateImageFile, generateUniqueFileName, ProcessedImage } from '../utils/imageUtils';
|
||||
import { secureApi } from './secureApi';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
|
||||
export interface StoredImage {
|
||||
id: string;
|
||||
@@ -14,10 +14,12 @@ export interface StoredImage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload and store an image in Firestore
|
||||
* Upload and store an image through secure API
|
||||
* @param file - The image file to upload
|
||||
* @param collectionName - Firestore collection name (e.g., 'company-logos')
|
||||
* @param collectionName - Collection name (e.g., 'company-logos')
|
||||
* @param documentId - Document ID (e.g., orgId)
|
||||
* @param orgId - Organization ID
|
||||
* @param userId - User ID for authentication
|
||||
* @param maxWidth - Maximum width for resizing (default: 128)
|
||||
* @param maxHeight - Maximum height for resizing (default: 128)
|
||||
* @returns Promise with stored image data
|
||||
@@ -26,13 +28,11 @@ export const uploadImage = async (
|
||||
file: File,
|
||||
collectionName: string,
|
||||
documentId: string,
|
||||
orgId: string,
|
||||
userId: 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) {
|
||||
@@ -45,135 +45,138 @@ export const uploadImage = async (
|
||||
// Generate unique filename
|
||||
const filename = generateUniqueFileName(file.name, 'logo');
|
||||
|
||||
// Create image data to store
|
||||
const imageData: StoredImage = {
|
||||
id: filename,
|
||||
// Create image data to upload
|
||||
const imageData = {
|
||||
collectionName,
|
||||
documentId,
|
||||
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);
|
||||
const result = await secureApi.uploadImage(orgId, userId, imageData);
|
||||
|
||||
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(),
|
||||
});
|
||||
if (!result.success) {
|
||||
throw new Error('Failed to upload image');
|
||||
}
|
||||
|
||||
return imageData;
|
||||
return {
|
||||
id: result.imageId,
|
||||
dataUrl: processedImage.dataUrl,
|
||||
filename,
|
||||
originalSize: processedImage.originalSize,
|
||||
compressedSize: processedImage.compressedSize,
|
||||
uploadedAt: Date.now(),
|
||||
width: processedImage.width,
|
||||
height: processedImage.height,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Failed to store image in Firestore:', error);
|
||||
console.error('Failed to upload image through secure API:', error);
|
||||
throw new Error('Failed to upload image');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve an image from Firestore
|
||||
* @param collectionName - Firestore collection name
|
||||
* Retrieve an image through secure API
|
||||
* @param collectionName - Collection name
|
||||
* @param documentId - Document ID
|
||||
* @param orgId - Organization ID
|
||||
* @param userId - User ID for authentication
|
||||
* @returns Promise with stored image data or null if not found
|
||||
*/
|
||||
export const getImage = async (
|
||||
collectionName: string,
|
||||
documentId: string
|
||||
documentId: string,
|
||||
orgId: string,
|
||||
userId: string
|
||||
): Promise<StoredImage | null> => {
|
||||
if (!db) {
|
||||
throw new Error('Firebase not initialized');
|
||||
}
|
||||
|
||||
try {
|
||||
const docRef = doc(db, collectionName, documentId);
|
||||
const docSnap = await getDoc(docRef);
|
||||
const result = await secureApi.getImage(orgId, userId, collectionName, documentId);
|
||||
|
||||
if (docSnap.exists()) {
|
||||
const data = docSnap.data();
|
||||
return data.logo || null;
|
||||
}
|
||||
|
||||
return null;
|
||||
return result; // getImage already returns StoredImage | null
|
||||
} catch (error) {
|
||||
console.error('Failed to retrieve image from Firestore:', error);
|
||||
console.error('Failed to retrieve image through secure API:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete an image from Firestore
|
||||
* @param collectionName - Firestore collection name
|
||||
* Delete an image through secure API
|
||||
* @param collectionName - Collection name
|
||||
* @param documentId - Document ID
|
||||
* @param orgId - Organization ID
|
||||
* @param userId - User ID for authentication
|
||||
* @returns Promise indicating success
|
||||
*/
|
||||
export const deleteImage = async (
|
||||
collectionName: string,
|
||||
documentId: string
|
||||
documentId: string,
|
||||
orgId: string,
|
||||
userId: string
|
||||
): Promise<boolean> => {
|
||||
if (!db) {
|
||||
throw new Error('Firebase not initialized');
|
||||
}
|
||||
|
||||
try {
|
||||
const docRef = doc(db, collectionName, documentId);
|
||||
const docSnap = await getDoc(docRef);
|
||||
const result = await secureApi.deleteImage(orgId, userId, collectionName, documentId);
|
||||
|
||||
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;
|
||||
return result; // deleteImage already returns boolean
|
||||
} catch (error) {
|
||||
console.error('Failed to delete image from Firestore:', error);
|
||||
console.error('Failed to delete image through secure API:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Company-specific image upload (convenience function)
|
||||
* Requires authentication context to get userId
|
||||
*/
|
||||
export const uploadCompanyLogo = async (
|
||||
file: File,
|
||||
orgId: string
|
||||
orgId: string,
|
||||
userId: string
|
||||
): Promise<StoredImage> => {
|
||||
return uploadImage(file, 'company-logos', orgId, 128, 128);
|
||||
return uploadImage(file, 'company-logos', orgId, orgId, userId, 128, 128);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get company logo (convenience function)
|
||||
* Requires authentication context to get userId
|
||||
*/
|
||||
export const getCompanyLogo = async (orgId: string): Promise<StoredImage | null> => {
|
||||
return getImage('company-logos', orgId);
|
||||
export const getCompanyLogo = async (
|
||||
orgId: string,
|
||||
userId: string
|
||||
): Promise<StoredImage | null> => {
|
||||
return getImage('company-logos', orgId, orgId, userId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete company logo (convenience function)
|
||||
* Requires authentication context to get userId
|
||||
*/
|
||||
export const deleteCompanyLogo = async (orgId: string): Promise<boolean> => {
|
||||
return deleteImage('company-logos', orgId);
|
||||
export const deleteCompanyLogo = async (
|
||||
orgId: string,
|
||||
userId: string
|
||||
): Promise<boolean> => {
|
||||
return deleteImage('company-logos', orgId, orgId, userId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook-based convenience functions that automatically get userId from auth context
|
||||
* Use these in React components where useAuth is available
|
||||
*/
|
||||
export const useImageStorage = () => {
|
||||
// Note: This would need to be implemented in a React component context
|
||||
// where useAuth() is available. For now, we provide the functions that require
|
||||
// explicit userId parameter.
|
||||
|
||||
return {
|
||||
uploadImage,
|
||||
getImage,
|
||||
deleteImage,
|
||||
uploadCompanyLogo,
|
||||
getCompanyLogo,
|
||||
deleteCompanyLogo,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user