feat: adding provider crud
This commit is contained in:
parent
86d0d56e38
commit
c20e04557b
@ -6,6 +6,7 @@ import Box from '@mui/material/Box';
|
||||
|
||||
import Products from './private/products/Products';
|
||||
import Clients from './private/clients/Clients';
|
||||
import Providers from './private/providers/Providers';
|
||||
|
||||
function App() {
|
||||
const [zone, setZone] = useState('public'); // Could be 'public' | 'restricted' | 'private'
|
||||
@ -30,6 +31,7 @@ function App() {
|
||||
|
||||
{zone === 'public' && currentView === 'Products' && <Products />}
|
||||
{zone === 'public' && currentView === 'Clients' && <Clients />}
|
||||
{zone === 'public' && currentView === 'Providers' && <Providers />}
|
||||
</Box>
|
||||
<Footer zone={zone} />
|
||||
</Box>
|
||||
|
||||
@ -3,6 +3,7 @@ import fendiLogo from '/favicon.png'
|
||||
import { AppBar, Toolbar, Typography, InputBase, IconButton, Box } from '@mui/material';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import MenuDrawer from './MenuDrawer';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
|
||||
export default function AppHeader({ zone = 'public', onSelectMenuItem }) {
|
||||
|
||||
@ -29,7 +30,7 @@ export default function AppHeader({ zone = 'public', onSelectMenuItem }) {
|
||||
<Toolbar sx={{ justifyContent: 'space-between', flexWrap: 'wrap' }}>
|
||||
<Box display="flex" alignItems="center">
|
||||
<IconButton edge="start" color="inherit" onClick={() => setMenuOpen(true)}>
|
||||
<img src={fendiLogo} alt="Fendi logo" style={{ height: 40 }} />
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import { Drawer, List, ListItem, ListItemText, useMediaQuery } from '@mui/materi
|
||||
const menuOptions = {
|
||||
public: ['Home', 'Explore', 'Contact'],
|
||||
restricted: ['Dashboard', 'Projects', 'Support'],
|
||||
private: ['Products', 'Clients', 'Categories', 'Users', 'Orders', 'Settings', 'Logout'],
|
||||
private: ['Products', 'Clients', 'Providers', 'Logout'],
|
||||
};
|
||||
|
||||
export default function MenuDrawer({ zone = 'public', open, onClose, onSelect }) {
|
||||
|
||||
92
src/private/providers/AddOrEditProviderForm.jsx
Normal file
92
src/private/providers/AddOrEditProviderForm.jsx
Normal file
@ -0,0 +1,92 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Box, Button, TextField, Avatar, Typography, Paper } from '@mui/material';
|
||||
|
||||
export default function AddOrEditProviderForm({ onAdd, initialData, onCancel }) {
|
||||
const [provider, setProvider] = useState({
|
||||
name: '',
|
||||
email: '',
|
||||
phone: '',
|
||||
location: '',
|
||||
category: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (initialData) {
|
||||
setProvider(initialData);
|
||||
} else {
|
||||
setProvider({
|
||||
name: '',
|
||||
email: '',
|
||||
phone: '',
|
||||
location: '',
|
||||
category: '',
|
||||
});
|
||||
}
|
||||
}, [initialData]);
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setProvider((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (onAdd) {
|
||||
onAdd(provider);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ px: 2, py: 3 }}>
|
||||
<Box display="flex" flexDirection={{ xs: 'column', md: 'row' }} gap={4}>
|
||||
<Box flex={1}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Name"
|
||||
name="name"
|
||||
value={provider.name}
|
||||
onChange={handleChange}
|
||||
margin="normal"
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={provider.email}
|
||||
onChange={handleChange}
|
||||
margin="normal"
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Phone"
|
||||
name="phone"
|
||||
value={provider.phone}
|
||||
onChange={handleChange}
|
||||
margin="normal"
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Location"
|
||||
name="location"
|
||||
value={provider.location}
|
||||
onChange={handleChange}
|
||||
margin="normal"
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Category"
|
||||
name="category"
|
||||
value={provider.category}
|
||||
onChange={handleChange}
|
||||
margin="normal"
|
||||
/>
|
||||
|
||||
<Box display="flex" justifyContent="flex-end" gap={1} mt={3}>
|
||||
<Button onClick={onCancel} className="button-transparent">Cancel</Button>
|
||||
<Button variant="contained" onClick={handleSubmit} className="button-gold">Save</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
173
src/private/providers/Providers.jsx
Normal file
173
src/private/providers/Providers.jsx
Normal file
@ -0,0 +1,173 @@
|
||||
import SectionContainer from '../../components/SectionContainer.jsx';
|
||||
import { useState } from 'react';
|
||||
import { DataGrid } from '@mui/x-data-grid';
|
||||
import { Typography, Button, Dialog, DialogTitle, DialogContent, IconButton, Box } from '@mui/material';
|
||||
import AddOrEditProviderForm from './AddOrEditProviderForm.jsx';
|
||||
|
||||
import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
||||
import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded';
|
||||
import '../../App.css';
|
||||
|
||||
const columnsBase = [
|
||||
{ field: 'name', headerName: 'Name', flex: 1 },
|
||||
{ field: 'location', headerName: 'Location', flex: 1 },
|
||||
{ field: 'category', headerName: 'Category', flex: 1 },
|
||||
{ field: 'email', headerName: 'Email', flex: 1 },
|
||||
{ field: 'phone', headerName: 'Phone', flex: 1 }
|
||||
];
|
||||
|
||||
export default function Providers({ children, maxWidth = 'lg', sx = {} }) {
|
||||
const [rows, setRows] = useState([
|
||||
{
|
||||
id: 1,
|
||||
name: '2G2 S.R.L.',
|
||||
email: 'info@2g2.it',
|
||||
phone: '+39 055 123456',
|
||||
location: 'Via Alessandro Volta, 29, 50041, Calenzano',
|
||||
category: 'Fabrics',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '3MC S.R.L.',
|
||||
email: 'contact@3mc.it',
|
||||
phone: '+39 055 654321',
|
||||
location: 'Via Mugellese, 20/22, 50013, Campi Bisenzio',
|
||||
category: 'FJ, Metal & Hard Accessories',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'A.M.F. S.P.A.',
|
||||
email: 'info@amfspa.it',
|
||||
phone: '+39 0424 789012',
|
||||
location: 'Via Bortolo Sacchi, 54/58, 36061, Bassano del Grappa',
|
||||
category: 'Leather Goods',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'AB CREATIVE S.R.L.S.',
|
||||
email: 'hello@abcreative.it',
|
||||
phone: '+39 055 987654',
|
||||
location: 'Via Della Pace Mondiale, 100, 50018, Scandicci',
|
||||
category: 'Material Embellishment',
|
||||
}
|
||||
]);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [editingProvider, setEditingProvider] = useState(null);
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [rowToDelete, setRowToDelete] = useState(null);
|
||||
|
||||
const handleAddOrEditProvider = (provider) => {
|
||||
if (editingProvider) {
|
||||
setRows(rows.map((row) => (row.id === editingProvider.id ? { ...editingProvider, ...provider } : row)));
|
||||
} else {
|
||||
const id = rows.length + 1;
|
||||
setRows([...rows, { id, company: provider.name, ...provider }]);
|
||||
}
|
||||
setOpen(false);
|
||||
setEditingProvider(null);
|
||||
};
|
||||
|
||||
const handleEditClick = (params) => {
|
||||
setEditingProvider(params.row);
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleDeleteClick = (row) => {
|
||||
setRowToDelete(row);
|
||||
setConfirmOpen(true);
|
||||
};
|
||||
|
||||
const confirmDelete = () => {
|
||||
setRows(rows.filter((row) => row.id !== rowToDelete.id));
|
||||
setRowToDelete(null);
|
||||
setConfirmOpen(false);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
...columnsBase,
|
||||
{
|
||||
field: 'actions',
|
||||
headerName: '',
|
||||
width: 130,
|
||||
renderCell: (params) => (
|
||||
<Box display="flex" alignItems="center" justifyContent="flex-end" height="100%" gap={2}>
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: '#DFCCBC',
|
||||
color: '#26201A',
|
||||
'&:hover': {
|
||||
backgroundColor: '#C2B2A4',
|
||||
},
|
||||
borderRadius: 2,
|
||||
p: 1,
|
||||
}}
|
||||
onClick={() => handleEditClick(params)}
|
||||
>
|
||||
<EditRoundedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: '#FBE9E7',
|
||||
color: '#C62828',
|
||||
'&:hover': {
|
||||
backgroundColor: '#EF9A9A',
|
||||
},
|
||||
borderRadius: 2,
|
||||
p: 1,
|
||||
}}
|
||||
onClick={() => handleDeleteClick(params.row)}
|
||||
>
|
||||
<DeleteRoundedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<SectionContainer sx={{ width: '100%' }}>
|
||||
<Typography variant="h4" gutterBottom color='#26201AFF'>
|
||||
Providers
|
||||
</Typography>
|
||||
|
||||
<Dialog open={open} onClose={() => { setOpen(false); setEditingProvider(null); }} fullWidth>
|
||||
<DialogTitle>{editingProvider ? 'Edit Provider' : 'Add Provider'}</DialogTitle>
|
||||
<DialogContent>
|
||||
<AddOrEditProviderForm onAdd={handleAddOrEditProvider} initialData={editingProvider} onCancel={() => { setOpen(false); setEditingProvider(null); }} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<Dialog open={confirmOpen} onClose={() => setConfirmOpen(false)}>
|
||||
<DialogTitle>Confirm Delete</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography>
|
||||
Are you sure you want to delete <strong>{rowToDelete?.name}</strong>?
|
||||
</Typography>
|
||||
<Box mt={2} display="flex" justifyContent="flex-end" gap={1}>
|
||||
<Button onClick={() => setConfirmOpen(false)} className='button-transparent'>Cancel</Button>
|
||||
<Button variant="contained" onClick={confirmDelete} className="button-gold">Delete</Button>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<Box mt={2}>
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
pageSize={5}
|
||||
rowsPerPageOptions={[5]}
|
||||
getRowSpacing={() => ({ top: 8, bottom: 8 })}
|
||||
/>
|
||||
|
||||
<Box display="flex" justifyContent="flex-end" mt={2}>
|
||||
<Button variant="contained" onClick={() => setOpen(true)} className="button-gold">
|
||||
Add Provider
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</SectionContainer>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user