version 10
This commit is contained in:
parent
968b83badc
commit
e87d7c53d1
@ -7,6 +7,9 @@ import CartPage from './CartPage';
|
||||
import AdminLayout from './AdminLayout';
|
||||
import AdminRoute from './AdminRoute';
|
||||
import ProductManagement from './ProductManagement';
|
||||
import ProductForm from './ProductForm';
|
||||
import SellerManagement from './SellerManagement';
|
||||
import CategoryManagement from './CategoryManagement';
|
||||
import { CartProvider } from './CartContext';
|
||||
import { AuthProvider } from './AuthContext';
|
||||
|
||||
@ -32,8 +35,10 @@ function App() {
|
||||
<Route path="/admin/*" element={<AdminRoute />}>
|
||||
<Route element={<AdminLayout />}>
|
||||
<Route path="products" element={<ProductManagement />} />
|
||||
<Route path="categories" element={<div>Category Management (To be implemented)</div>} />
|
||||
<Route path="sellers" element={<div>Seller Management (To be implemented)</div>} />
|
||||
<Route path="products/create" element={<ProductForm />} />
|
||||
<Route path="products/edit/:id" element={<ProductForm />} />
|
||||
<Route path="categories" element={<CategoryManagement />} />
|
||||
<Route path="sellers" element={<SellerManagement />} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Routes>
|
||||
@ -43,4 +48,4 @@ function App() {
|
||||
)
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App;
|
||||
74
frontend/src/CategoryManagement.tsx
Normal file
74
frontend/src/CategoryManagement.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
|
||||
interface Category {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
|
||||
const CategoryManagement: React.FC = () => {
|
||||
const [categories, setCategories] = useState<Category[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchCategories();
|
||||
}, []);
|
||||
|
||||
const fetchCategories = () => {
|
||||
axios.get('http://127.0.0.1:8000/categories/')
|
||||
.then(response => {
|
||||
setCategories(response.data);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching categories:', error);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const deleteCategory = (id: number) => {
|
||||
if (window.confirm('Are you sure you want to delete this category?')) {
|
||||
axios.delete(`http://127.0.0.1:8000/categories/${id}/`)
|
||||
.then(() => fetchCategories())
|
||||
.catch(error => console.error('Error deleting category:', error));
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) return <div className="text-center p-4">Loading...</div>;
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h2 className="text-xl font-bold mb-4">Category Management</h2>
|
||||
<table className="min-w-full bg-white border border-gray-200">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="py-2 px-4 border-b">ID</th>
|
||||
<th className="py-2 px-4 border-b">Name</th>
|
||||
<th className="py-2 px-4 border-b">Slug</th>
|
||||
<th className="py-2 px-4 border-b">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{categories.map(category => (
|
||||
<tr key={category.id}>
|
||||
<td className="py-2 px-4 border-b">{category.id}</td>
|
||||
<td className="py-2 px-4 border-b">{category.name}</td>
|
||||
<td className="py-2 px-4 border-b">{category.slug}</td>
|
||||
<td className="py-2 px-4 border-b">
|
||||
<button
|
||||
onClick={() => deleteCategory(category.id)}
|
||||
className="bg-red-500 text-white px-2 py-1 rounded"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CategoryManagement;
|
||||
44
frontend/src/ProductForm.tsx
Normal file
44
frontend/src/ProductForm.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
const ProductForm: React.FC = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
const [formData, setFormData] = useState({ name: '', price: '', description: '', category: '' });
|
||||
const [categories, setCategories] = useState<{ id: number; name: string }[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
axios.get('http://127.0.0.1:8000/categories/')
|
||||
.then(res => setCategories(res.data));
|
||||
|
||||
if (id) {
|
||||
axios.get(`http://127.0.0.1:8000/products/${id}/`)
|
||||
.then(res => setFormData(res.data));
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const action = id ? axios.put(`http://127.0.0.1:8000/products/${id}/`, formData) : axios.post('http://127.0.0.1:8000/products/', formData);
|
||||
action.then(() => navigate('/admin/products'));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h2 className="text-xl font-bold mb-4">{id ? 'Edit' : 'Create'} Product</h2>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<input className="block w-full p-2 border" placeholder="Name" value={formData.name} onChange={e => setFormData({...formData, name: e.target.value})} />
|
||||
<input className="block w-full p-2 border" placeholder="Price" value={formData.price} onChange={e => setFormData({...formData, price: e.target.value})} />
|
||||
<textarea className="block w-full p-2 border" placeholder="Description" value={formData.description} onChange={e => setFormData({...formData, description: e.target.value})} />
|
||||
<select className="block w-full p-2 border" value={formData.category} onChange={e => setFormData({...formData, category: e.target.value})}>
|
||||
<option value="">Select Category</option>
|
||||
{categories.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
|
||||
</select>
|
||||
<button type="submit" className="bg-blue-500 text-white p-2 rounded">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProductForm;
|
||||
@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
interface Product {
|
||||
id: number;
|
||||
@ -41,7 +42,10 @@ const ProductManagement: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h2 className="text-xl font-bold mb-4">Product Management</h2>
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h2 className="text-xl font-bold">Product Management</h2>
|
||||
<Link to="/admin/products/create" className="bg-green-500 text-white px-4 py-2 rounded">Create Product</Link>
|
||||
</div>
|
||||
<table className="min-w-full bg-white border border-gray-200">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -58,6 +62,7 @@ const ProductManagement: React.FC = () => {
|
||||
<td className="py-2 px-4 border-b">{product.name}</td>
|
||||
<td className="py-2 px-4 border-b">{product.price}</td>
|
||||
<td className="py-2 px-4 border-b">
|
||||
<Link to={`/admin/products/edit/${product.id}`} className="bg-blue-500 text-white px-2 py-1 rounded mr-2">Edit</Link>
|
||||
<button
|
||||
onClick={() => deleteProduct(product.id)}
|
||||
className="bg-red-500 text-white px-2 py-1 rounded"
|
||||
@ -73,4 +78,4 @@ const ProductManagement: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default ProductManagement;
|
||||
export default ProductManagement;
|
||||
74
frontend/src/SellerManagement.tsx
Normal file
74
frontend/src/SellerManagement.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
|
||||
interface Seller {
|
||||
id: number;
|
||||
store_name: string;
|
||||
is_verified: boolean;
|
||||
}
|
||||
|
||||
const SellerManagement: React.FC = () => {
|
||||
const [sellers, setSellers] = useState<Seller[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchSellers();
|
||||
}, []);
|
||||
|
||||
const fetchSellers = () => {
|
||||
axios.get('http://127.0.0.1:8000/sellers/')
|
||||
.then(response => {
|
||||
setSellers(response.data);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching sellers:', error);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const deleteSeller = (id: number) => {
|
||||
if (window.confirm('Are you sure you want to delete this seller?')) {
|
||||
axios.delete(`http://127.0.0.1:8000/sellers/${id}/`)
|
||||
.then(() => fetchSellers())
|
||||
.catch(error => console.error('Error deleting seller:', error));
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) return <div className="text-center p-4">Loading...</div>;
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h2 className="text-xl font-bold mb-4">Seller Management</h2>
|
||||
<table className="min-w-full bg-white border border-gray-200">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="py-2 px-4 border-b">ID</th>
|
||||
<th className="py-2 px-4 border-b">Store Name</th>
|
||||
<th className="py-2 px-4 border-b">Verified</th>
|
||||
<th className="py-2 px-4 border-b">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{sellers.map(seller => (
|
||||
<tr key={seller.id}>
|
||||
<td className="py-2 px-4 border-b">{seller.id}</td>
|
||||
<td className="py-2 px-4 border-b">{seller.store_name}</td>
|
||||
<td className="py-2 px-4 border-b">{seller.is_verified ? 'Yes' : 'No'}</td>
|
||||
<td className="py-2 px-4 border-b">
|
||||
<button
|
||||
onClick={() => deleteSeller(seller.id)}
|
||||
className="bg-red-500 text-white px-2 py-1 rounded"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SellerManagement;
|
||||
Loading…
x
Reference in New Issue
Block a user