Untitled
unknown
javascript
a year ago
14 kB
12
Indexable
import React, { useState, useEffect } from 'react'; import { collection, addDoc, deleteDoc, doc, updateDoc, getDocs } from 'firebase/firestore'; import { db } from '../../../../firebaseConfig'; // Adjust import path as needed import { Modal, Button, Form, Input, Select, InputNumber, notification, Image, List, Upload } from 'antd'; import { UploadOutlined, DeleteOutlined, DeleteTwoTone } from '@ant-design/icons'; import { uploadImage } from '../../../../features/uploadImage'; // Adjust import path as needed const { Option } = Select; const { TextArea } = Input; const Products = () => { const [products, setProducts] = useState([]); const [viewProduct, setViewProduct] = useState(null); const [isModalVisible, setIsModalVisible] = useState(false); const [isEditMode, setIsEditMode] = useState(false); const [form] = Form.useForm(); const [thumbnailUrl, setThumbnailUrl] = useState(''); const [imagesUrls, setImagesUrls] = useState([]); useEffect(() => { const fetchProducts = async () => { try { const productsCollection = collection(db, 'products'); const productSnapshot = await getDocs(productsCollection); const productsArray = productSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data(), })); setProducts(productsArray); } catch (error) { notification.error({ message: 'Error', description: 'Failed to fetch products.', }); } }; fetchProducts(); }, []); const showModal = (product) => { setIsEditMode(!!product); setViewProduct(product || {}); form.setFieldsValue({ ...product, images: product?.images ? product.images.join(', ') : '', ingredients: product?.ingredients ? product.ingredients.join(', ') : '' }); setThumbnailUrl(product?.thumbnail || ''); setImagesUrls(product?.images || []); setIsModalVisible(true); }; const handleCancel = () => { setIsModalVisible(false); form.resetFields(); setThumbnailUrl(''); setImagesUrls([]); }; const handleDelete = async (id) => { try { await deleteDoc(doc(db, 'products', id)); setProducts(products.filter(product => product.id !== id)); } catch (error) { notification.error({ message: 'Error', description: 'Failed to delete the product.', }); } }; const handleSave = async (values) => { try { const updatedValues = { ...values, thumbnail: thumbnailUrl, images: imagesUrls, ingredients: values.ingredients ? values.ingredients.split(',').map(ingredient => ingredient.trim()) : [] }; if (isEditMode) { await updateDoc(doc(db, 'products', viewProduct.id), updatedValues); } else { await addDoc(collection(db, 'products'), updatedValues); } const productsCollection = collection(db, 'products'); const productSnapshot = await getDocs(productsCollection); const productsArray = productSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data(), })); setProducts(productsArray); setIsModalVisible(false); form.resetFields(); setThumbnailUrl(''); setImagesUrls([]); notification.success({ message: 'Success', description: 'Product is saved successfully.', }); } catch (error) { console.error('Error saving product:', error); notification.error({ message: 'Error', description: 'Failed to save the product.', }); } }; const handleFileChange = async (info) => { const { fileList } = info; const newUrls = await Promise.all( fileList.map(async (file) => { if (file.status === 'done') { return file.response; // Assuming response contains the URL } else if (file.status === 'uploading') { try { const url = await uploadImage(file.originFileObj); return url; } catch (error) { console.error('Error uploading image:', error); return null; } } return null; }) ); setImagesUrls(prevUrls => [...new Set([...prevUrls, ...newUrls.filter(url => url !== null)])]); }; const customRequestHandler = async ({ file, onSuccess, onError }) => { try { const url = await uploadImage(file.originFileObj); onSuccess(url); // Trigger onSuccess with URL } catch (error) { console.error('Error uploading image:', error); onError(error); } }; const removeImage = (url) => { setImagesUrls(imagesUrls.filter(imageUrl => imageUrl !== url)); }; return ( <div className="container mx-auto p-6"> <h2 className="text-2xl font-bold mb-4">Products</h2> <Button type="primary" onClick={() => showModal(null)}>Add Product</Button> <table className="min-w-full divide-y divide-gray-200 mt-4"> <thead> <tr> <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th> <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th> <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Price</th> <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> </tr> </thead> <tbody className="bg-white divide-y divide-gray-200"> {products.map(product => ( <tr key={product.id}> <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{product.id}</td> <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{product.name}</td> <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${product.price}</td> <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{product.status}</td> <td className="px-6 py-4 whitespace-nowrap text-sm font-medium"> <Button onClick={() => showModal(product)} className="mr-2"> View </Button> <Button onClick={() => handleDelete(product.id)} type="text" danger> <DeleteOutlined /> </Button> </td> </tr> ))} </tbody> </table> <Modal title={isEditMode ? "Edit Product" : "View Product"} visible={isModalVisible} onCancel={handleCancel} footer={[ <Button key="back" onClick={handleCancel}> Cancel </Button>, <Button key="submit" type="primary" onClick={() => form.submit()} > Save </Button> ]} > <Form className='h-[27rem] overflow-y-auto overflow-x-hidden' form={form} layout="vertical" onFinish={handleSave} initialValues={viewProduct} > <Form.Item name="name" label="Name" rules={[{ required: true, message: 'Please enter the product name!' }]}> <Input /> </Form.Item> <Form.Item name="description" label="Description"> <TextArea rows={4} /> </Form.Item> <Form.Item name="price" label="Price" rules={[{ required: true, message: 'Please enter the price!' }]}> <InputNumber min={0} style={{ width: '100%' }} /> </Form.Item> <Form.Item name="availability" label="Availability"> <Select> <Option value="In Stock">In Stock</Option> <Option value="Out Of Stock">Out Of Stock</Option> </Select> </Form.Item> <Form.Item name="category" label="Category"> <Select mode="multiple"> <Option value="Pizza">Pizza</Option> <Option value="Burger">Burger</Option> <Option value="Pasta">Pasta</Option> {/* Add more options as needed */} </Select> </Form.Item> <Form.Item name="ingredients" label="Ingredients"> <Input /> </Form.Item> <Form.Item name="preparation_time" label="Preparation Time"> <Input /> </Form.Item> <Form.Item name="tags" label="Tags"> <Select> <Option value="Vegetarian">Vegetarian</Option> <Option value="Non-Vegetarian">Non-Vegetarian</Option> <Option value="Vegan">Vegan</Option> </Select> </Form.Item> <Form.Item name="status" label="Status"> <Select> <Option value="Active">Active</Option> <Option value="Inactive">Inactive</Option> </Select> </Form.Item> <Form.Item label="Thumbnail"> <Upload customRequest={async ({ file, onSuccess }) => { try { const url = await uploadImage(file); // Upload image and get URL setThumbnailUrl(url); onSuccess(url); // Trigger onSuccess with URL } catch (error) { console.error('Error uploading thumbnail:', error); } }} showUploadList={false} accept="image/*" > <Button icon={<UploadOutlined />}>Upload Thumbnail</Button> </Upload> {thumbnailUrl && ( <div className="mt-2 flex flex-col border shadow-dark w-max rounded"> <Image src={thumbnailUrl} width={100} /> <Button type="link" icon={<DeleteTwoTone twoToneColor="#ff0000" />} onClick={() => setThumbnailUrl('')} className='text-red-500 w-max' > Remove </Button> </div> )} </Form.Item> <Form.Item label="Images"> <Upload customRequest={customRequestHandler} showUploadList={false} accept="image/*" onChange={handleFileChange} multiple > <Button icon={<UploadOutlined />}>Upload Images</Button> </Upload> {imagesUrls.length > 0 && ( <List className='mt-4 overflow-x-hidden' grid={{ gutter: 16, column: 4 }} dataSource={imagesUrls} renderItem={(item) => ( <List.Item className='border shadow-dark rounded'> <Image src={item} height={100} width={100} /> <Button type="link" icon={<DeleteTwoTone twoToneColor="#ff0000" />} onClick={() => removeImage(item)} className='text-red-500' > Remove </Button> </List.Item> )} /> )} </Form.Item> </Form> </Modal> </div> ); }; export default Products;
Editor is loading...
Leave a Comment