Untitled
unknown
javascript
a year ago
14 kB
18
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