332 lines
11 KiB
JavaScript

import React, { useState, useEffect, useContext } from 'react'
import { useNavigate } from 'react-router-dom'
import api from '../api'
import { AuthContext } from '../context/AuthContext'
import '../styles/global.css'
export default function Models() {
const navigate = useNavigate()
const { user } = useContext(AuthContext)
const [models, setModels] = useState([])
const [categories, setCategories] = useState([])
const [brands, setBrands] = useState([])
const [loading, setLoading] = useState(true)
const [showForm, setShowForm] = useState(false)
const [editingModel, setEditingModel] = useState(null)
const [formData, setFormData] = useState({
name: '',
category_id: '',
brand: '',
base_price: '',
sizes: '',
description: '',
})
// Redirect if not admin
useEffect(() => {
if (!user?.is_admin) {
navigate('/')
}
}, [user, navigate])
useEffect(() => {
fetchModels()
fetchCategories()
fetchBrands()
}, [])
const fetchModels = async () => {
try {
const response = await api.get('/models')
setModels(response.data)
} catch (error) {
console.error('Error fetching models:', error)
} finally {
setLoading(false)
}
}
const fetchCategories = async () => {
try {
const response = await api.get('/categories')
setCategories(response.data)
} catch (error) {
console.error('Error fetching categories:', error)
}
}
const fetchBrands = async () => {
try {
const response = await api.get('/brands')
setBrands(response.data.map(b => b.name).sort())
} catch (error) {
console.error('Error fetching brands:', error)
}
}
const handleChange = (e) => {
const { name, value } = e.target
setFormData({ ...formData, [name]: value })
}
const handleSubmit = async (e) => {
e.preventDefault()
const modelData = {
...formData,
category_id: parseInt(formData.category_id),
base_price: formData.base_price ? parseFloat(formData.base_price) : null,
sizes: formData.sizes ? formData.sizes.split(',').map(s => s.trim()) : [],
}
try {
if (editingModel) {
await api.put(`/models/${editingModel.id}`, modelData)
alert('Model updated successfully!')
} else {
await api.post('/models', modelData)
alert('Model created successfully!')
}
setShowForm(false)
setEditingModel(null)
resetForm()
fetchModels()
} catch (error) {
console.error('Error saving model:', error)
alert('Error saving model: ' + (error.response?.data?.detail || 'Unknown error'))
}
}
const handleEdit = (model) => {
setEditingModel(model)
setFormData({
name: model.name || '',
category_id: model.category_id || '',
brand: model.brand || '',
base_price: model.base_price || '',
sizes: Array.isArray(model.sizes) ? model.sizes.join(', ') : '',
description: model.description || '',
})
setShowForm(true)
setTimeout(() => {
window.scrollTo({ top: 0, behavior: 'smooth' })
}, 100)
}
const handleDelete = async (id) => {
if (!confirm('Are you sure you want to delete this model? This will unlink all associated products.')) return
try {
await api.delete(`/models/${id}`)
alert('Model deleted successfully!')
fetchModels()
} catch (error) {
console.error('Error deleting model:', error)
alert('Error deleting model: ' + (error.response?.data?.detail || 'Unknown error'))
}
}
const resetForm = () => {
setFormData({
name: '',
category_id: '',
brand: '',
base_price: '',
sizes: '',
description: '',
})
}
const handleCancel = () => {
setShowForm(false)
setEditingModel(null)
resetForm()
}
if (!user?.is_admin) {
return null
}
const getCategoryName = (categoryId) => {
const category = categories.find(c => c.id === categoryId)
return category ? category.name : 'Unknown'
}
return (
<div className="models-page" style={{ padding: '2rem', maxWidth: '1200px', margin: '0 auto' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '2rem' }}>
<h1>Manage Models</h1>
<button
className="btn btn-primary"
onClick={() => {
setShowForm(!showForm)
setEditingModel(null)
resetForm()
}}
>
{showForm ? 'Cancel' : '+ Add New Model'}
</button>
</div>
{showForm && (
<div style={{ backgroundColor: '#f5f5f5', padding: '2rem', borderRadius: '8px', marginBottom: '2rem' }}>
<h2>{editingModel ? 'Edit Model' : 'Create New Model'}</h2>
<form onSubmit={handleSubmit}>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem' }}>
<div className="form-group">
<label>Model Name * (e.g., 9060, Air Max 90)</label>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="9060"
required
/>
</div>
<div className="form-group">
<label>Brand *</label>
<select
name="brand"
value={formData.brand}
onChange={handleChange}
required
>
<option value="">Select Brand</option>
{brands.map(brand => (
<option key={brand} value={brand}>{brand}</option>
))}
</select>
</div>
<div className="form-group">
<label>Category *</label>
<select name="category_id" value={formData.category_id} onChange={handleChange} required>
<option value="">Select Category</option>
{categories.map(category => (
<option key={category.id} value={category.id}>
{category.name}
</option>
))}
</select>
</div>
<div className="form-group">
<label>Base Price (Default for all products)</label>
<input
type="number"
step="0.01"
name="base_price"
value={formData.base_price}
onChange={handleChange}
placeholder="129.99"
/>
</div>
<div className="form-group" style={{ gridColumn: '1 / -1' }}>
<label>Default Sizes (comma separated)</label>
<input
type="text"
name="sizes"
value={formData.sizes}
onChange={handleChange}
placeholder="7, 7.5, 8, 8.5, 9, 9.5, 10, 10.5, 11, 11.5, 12"
/>
</div>
<div className="form-group" style={{ gridColumn: '1 / -1' }}>
<label>Description</label>
<textarea
name="description"
value={formData.description}
onChange={handleChange}
rows="4"
placeholder="Model description..."
/>
</div>
</div>
<div style={{ marginTop: '1.5rem' }}>
<button type="submit" className="btn btn-primary" style={{ marginRight: '1rem' }}>
{editingModel ? 'Update Model' : 'Create Model'}
</button>
<button type="button" className="btn btn-secondary" onClick={handleCancel}>
Cancel
</button>
</div>
</form>
</div>
)}
<div>
<h2>Models ({models.length})</h2>
{loading ? (
<p>Loading...</p>
) : (
<div style={{ overflowX: 'auto' }}>
<table style={{ width: '100%', borderCollapse: 'collapse', marginTop: '1rem' }}>
<thead>
<tr style={{ backgroundColor: '#f0f0f0', textAlign: 'left' }}>
<th style={{ padding: '0.75rem', border: '1px solid #ddd' }}>ID</th>
<th style={{ padding: '0.75rem', border: '1px solid #ddd' }}>Model Name</th>
<th style={{ padding: '0.75rem', border: '1px solid #ddd' }}>Brand</th>
<th style={{ padding: '0.75rem', border: '1px solid #ddd' }}>Category</th>
<th style={{ padding: '0.75rem', border: '1px solid #ddd' }}>Base Price</th>
<th style={{ padding: '0.75rem', border: '1px solid #ddd' }}>Sizes</th>
<th style={{ padding: '0.75rem', border: '1px solid #ddd' }}>Actions</th>
</tr>
</thead>
<tbody>
{models.map(model => (
<tr key={model.id}>
<td style={{ padding: '0.75rem', border: '1px solid #ddd' }}>{model.id}</td>
<td style={{ padding: '0.75rem', border: '1px solid #ddd' }}>{model.name}</td>
<td style={{ padding: '0.75rem', border: '1px solid #ddd' }}>{model.brand}</td>
<td style={{ padding: '0.75rem', border: '1px solid #ddd' }}>{getCategoryName(model.category_id)}</td>
<td style={{ padding: '0.75rem', border: '1px solid #ddd' }}>
{model.base_price ? `$${parseFloat(model.base_price).toFixed(2)}` : '-'}
</td>
<td style={{ padding: '0.75rem', border: '1px solid #ddd', fontSize: '0.85em' }}>
{model.sizes ? model.sizes.join(', ') : '-'}
</td>
<td style={{ padding: '0.75rem', border: '1px solid #ddd' }}>
<button
onClick={() => handleEdit(model)}
style={{
marginRight: '0.5rem',
padding: '0.25rem 0.75rem',
backgroundColor: '#4CAF50',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Edit
</button>
<button
onClick={() => handleDelete(model.id)}
style={{
padding: '0.25rem 0.75rem',
backgroundColor: '#f44336',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
</div>
)
}