Created
June 20, 2025 09:01
-
-
Save muindetuva/85c59cc9bc23759951ee36bbf3be808e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // components/MyUploadForm.tsx | |
| 'use client'; | |
| import React, { useState, useRef, useCallback } from 'react'; | |
| import { db, storage } from '../firebase/config'; // Adjust path if needed | |
| import { collection, addDoc, serverTimestamp } from 'firebase/firestore'; | |
| import { ref, uploadBytes, getDownloadURL } from 'firebase/storage'; // Import uploadBytes | |
| const MyUploadForm: React.FC = () => { | |
| const [title, setTitle] = useState<string>(''); | |
| const [description, setDescription] = useState<string>(''); | |
| const [statusMessage, setStatusMessage] = useState<string>(''); | |
| const [isSubmitting, setIsSubmitting] = useState<boolean>(false); | |
| const fileInputRef = useRef<HTMLInputElement>(null); | |
| const handleSubmit = useCallback(async (e: React.FormEvent<HTMLFormElement>) => { | |
| e.preventDefault(); | |
| setIsSubmitting(true); | |
| setStatusMessage('Submitting...'); | |
| // Basic validation for required text fields | |
| if (!title || !description) { | |
| setStatusMessage('Please fill in the title and description.'); | |
| setIsSubmitting(false); | |
| return; | |
| } | |
| const imageUrls: string[] = []; // Initialize as empty array | |
| const filesToUpload = fileInputRef.current?.files; // Get the FileList | |
| try { | |
| if (filesToUpload && filesToUpload.length > 0) { | |
| setStatusMessage('Uploading images...'); | |
| for (let i = 0; i < filesToUpload.length; i++) { | |
| const file = filesToUpload[i]; | |
| const imageFileName = `${Date.now()}-${file.name}`; | |
| const imageRef = ref(storage, `reports/${imageFileName}`); | |
| // --- Use uploadBytes and await its completion --- | |
| const uploadResult = await uploadBytes(imageRef, file); | |
| const url = await getDownloadURL(uploadResult.ref); // Get URL from the result's ref | |
| imageUrls.push(url); | |
| } | |
| setStatusMessage('All images uploaded. Saving data...'); | |
| } else { | |
| setStatusMessage('No images selected. Saving data...'); | |
| } | |
| // --- Store Data (including image URLs) in Cloud Firestore --- | |
| try { | |
| const docData = { | |
| title, | |
| description, | |
| imageUrls: imageUrls, // Will be empty array if no images uploaded | |
| createdAt: serverTimestamp(), | |
| }; | |
| await addDoc(collection(db, "formData"), docData); | |
| console.log("Document written successfully!"); | |
| setStatusMessage('Form submitted successfully!'); | |
| setTitle(''); | |
| setDescription(''); | |
| if (fileInputRef.current) { | |
| fileInputRef.current.value = ''; // Clear file input | |
| } | |
| } catch (firestoreError: any) { | |
| console.error("Error writing document to Firestore: ", firestoreError); | |
| setStatusMessage(`Data storage failed: ${firestoreError.message}`); | |
| } finally { | |
| setIsSubmitting(false); // Ensure loading state is reset | |
| } | |
| } catch (overallError: any) { | |
| // This catches errors from image upload loop (e.g., network errors, permission issues) | |
| console.error("An error occurred during form submission:", overallError); | |
| setStatusMessage(`Submission error: ${overallError.message}`); | |
| setIsSubmitting(false); | |
| } | |
| }, [title, description]); | |
| return ( | |
| <div className="max-w-md mx-auto p-6 bg-white shadow-md rounded-lg"> | |
| <h2 className="text-2xl font-bold mb-4 text-center">Upload Form</h2> | |
| <form onSubmit={handleSubmit} className="space-y-4"> | |
| <div> | |
| <label htmlFor="title" className="block text-sm font-medium text-gray-700">Title:</label> | |
| <input | |
| type="text" | |
| id="title" | |
| name="title" | |
| value={title} | |
| onChange={(e) => setTitle(e.target.value)} | |
| required | |
| className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" | |
| /> | |
| </div> | |
| <div> | |
| <label htmlFor="description" className="block text-sm font-medium text-gray-700">Description:</label> | |
| <textarea | |
| id="description" | |
| name="description" | |
| value={description} | |
| onChange={(e) => setDescription(e.target.value)} | |
| required | |
| rows={4} | |
| className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" | |
| ></textarea> | |
| </div> | |
| <div> | |
| <label htmlFor="image" className="block text-sm font-medium text-gray-700">Upload Image (Optional):</label> | |
| <input | |
| type="file" | |
| id="image" | |
| name="image" | |
| accept="image/*" | |
| ref={fileInputRef} | |
| // Add 'multiple' if you want to allow selecting more than one file | |
| className="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100" | |
| /> | |
| </div> | |
| <button | |
| type="submit" | |
| disabled={isSubmitting} | |
| className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed" | |
| > | |
| {isSubmitting ? 'Submitting...' : 'Submit Data'} | |
| </button> | |
| </form> | |
| {statusMessage && ( | |
| <div className="mt-4 p-3 rounded-md text-sm text-center" | |
| style={{ backgroundColor: statusMessage.includes('failed') ? '#fee2e2' : (statusMessage.includes('successfully') ? '#d1fae5' : '#e0f2fe'), | |
| color: statusMessage.includes('failed') ? '#991b1b' : (statusMessage.includes('successfully') ? '#065f46' : '#2563eb') }}> | |
| {statusMessage} | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| }; | |
| export default MyUploadForm; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment