initial commit
This commit is contained in:
@@ -0,0 +1,403 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
TextField,
|
||||
Button,
|
||||
Select,
|
||||
MenuItem,
|
||||
Checkbox,
|
||||
ListItemText,
|
||||
OutlinedInput,
|
||||
styled,
|
||||
useTheme,
|
||||
LinearProgress
|
||||
} from '@mui/material';
|
||||
import AddAPhotoOutlinedIcon from '@mui/icons-material/AddAPhotoOutlined';
|
||||
import authService from '../../../services/authService';
|
||||
import { useRestaurant } from '../../../contexts/RestaurantContext';
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
const AccountProfile = () => {
|
||||
const theme = useTheme();
|
||||
const { restaurantId } = useRestaurant();
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [profileImage, setProfileImage] = useState(null);
|
||||
const [form, setForm] = useState({
|
||||
restaurant_name: '',
|
||||
restaurant_type: '',
|
||||
Address: '',
|
||||
City: '',
|
||||
Postal_code: '',
|
||||
Phone: '',
|
||||
Email: '',
|
||||
Operation_hour: '',
|
||||
host_type: '',
|
||||
collaboration_type: '',
|
||||
closed_days: [],
|
||||
equipment: [], // array of {name, quantity}
|
||||
Maximum_orders_per_day: 0,
|
||||
Number_of_Cheff: 0,
|
||||
Number_of_Waiters: 0,
|
||||
Number_of_Cookers: 0,
|
||||
});
|
||||
|
||||
const daysOfWeek = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
|
||||
|
||||
const Input = styled('input')({ display: 'none' });
|
||||
|
||||
useEffect(() => {
|
||||
const fetchProfile = async () => {
|
||||
if (!restaurantId) return;
|
||||
const data = await authService.getRestaurantProfile(restaurantId);
|
||||
console.log("PROFILE DATA ===>", data); // 👈 يوضح الأسماء الحقيقية
|
||||
if (data) {
|
||||
setForm({
|
||||
restaurant_name: data.restaurant_name,
|
||||
restaurant_type: data.restaurant_type,
|
||||
Address: data.Address,
|
||||
City: data.City,
|
||||
Postal_code: data.Postal_code,
|
||||
Phone: data.Phone,
|
||||
Email: data.Email,
|
||||
Operation_hour: data.Operation_hour,
|
||||
host_type: data.host_type,
|
||||
collaboration_type: data.collaboration_type,
|
||||
closed_days: data.closed_days || [],
|
||||
equipment: Object.entries(data.equipment || {}).map(([name, quantity]) => ({ name, quantity })),
|
||||
Maximum_orders_per_day: data.Maximum_orders_per_day ?? data.maximum_orders_per_day ?? 0,
|
||||
Number_of_Cheff: data.Number_of_Cheff ?? data.number_of_cheff ?? 0,
|
||||
Number_of_Waiters: data.Number_of_Waiters ?? data.number_of_waiters ?? 0,
|
||||
Number_of_Cookers: data.Number_of_Cookers ?? data.number_of_cookers ?? 0,
|
||||
});
|
||||
}
|
||||
};
|
||||
fetchProfile();
|
||||
}, [restaurantId]);
|
||||
|
||||
|
||||
const handleImageUpload = (event) => {
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
setProfileImage(event.target.files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (field, value) => setForm(prev => ({ ...prev, [field]: value }));
|
||||
|
||||
const handleEquipmentChange = (index, key, value) => {
|
||||
const newEquipment = [...form.equipment];
|
||||
newEquipment[index][key] = value;
|
||||
setForm(prev => ({ ...prev, equipment: newEquipment }));
|
||||
};
|
||||
|
||||
const addEquipment = () => {
|
||||
setForm(prev => ({
|
||||
...prev,
|
||||
equipment: [...prev.equipment, { name: '', quantity: 0 }]
|
||||
}));
|
||||
};
|
||||
|
||||
const removeEquipment = (index) => {
|
||||
const newEquipment = [...form.equipment];
|
||||
newEquipment.splice(index, 1);
|
||||
setForm(prev => ({ ...prev, equipment: newEquipment }));
|
||||
};
|
||||
|
||||
const renderField = (label, value, fieldKey, options = null) => (
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 1,
|
||||
pb: 1, // padding bottom
|
||||
borderBottom: '1px solid #ccc' // الخط الرمادي تحت كل حقل
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
fontSize: '18px',
|
||||
color: 'black'
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
|
||||
{editMode ? (
|
||||
options ? (
|
||||
<Select
|
||||
multiple
|
||||
value={form[fieldKey]}
|
||||
onChange={(e) => handleChange(fieldKey, e.target.value)}
|
||||
input={<OutlinedInput label={label} />}
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
>
|
||||
{options.map(day => (
|
||||
<MenuItem key={day} value={day}>
|
||||
<Checkbox checked={form[fieldKey].includes(day)} />
|
||||
<ListItemText primary={day.charAt(0).toUpperCase() + day.slice(1)} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
) : (
|
||||
<TextField
|
||||
value={value}
|
||||
onChange={(e) => handleChange(fieldKey, e.target.value)}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
sx={{
|
||||
'& input': { fontWeight: 500, fontSize: '16px', color: 'black' },
|
||||
'& input::placeholder': { color: '#969BA7' },
|
||||
'& .MuiOutlinedInput-root': {
|
||||
borderRadius: '10px',
|
||||
transition: '0.3s',
|
||||
'&.Mui-focused fieldset': {
|
||||
borderColor: theme.palette.primary.main,
|
||||
boxShadow: '0 0 0 2px rgba(255, 145, 77, 0.2)',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Typography
|
||||
variant="body1"
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
fontSize: '16px',
|
||||
color: 'gray'
|
||||
}}
|
||||
>
|
||||
{Array.isArray(value) ? value.join(', ') : value}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
|
||||
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!restaurantId) return;
|
||||
|
||||
const equipmentObj = {};
|
||||
form.equipment.forEach(eq => {
|
||||
if (eq.name) equipmentObj[eq.name] = eq.quantity;
|
||||
});
|
||||
|
||||
const payload = {
|
||||
...form,
|
||||
equipment: equipmentObj
|
||||
};
|
||||
|
||||
if (profileImage) payload.logo = profileImage;
|
||||
|
||||
const result = await authService.updateRestaurantProfile(restaurantId, payload);
|
||||
|
||||
if (result.success) {
|
||||
alert("Profile updated successfully!");
|
||||
setEditMode(false);
|
||||
|
||||
const updated = await authService.getRestaurantProfile(restaurantId);
|
||||
if (updated) setForm({
|
||||
...updated,
|
||||
equipment: Object.entries(updated.equipment || {}).map(([name, quantity]) => ({ name, quantity })),
|
||||
});
|
||||
} else {
|
||||
alert(`Update failed: ${result.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// داخل AccountProfile
|
||||
|
||||
const collaborationOptions = [
|
||||
{ value: 'fine_dining', label: 'Fine Dining' },
|
||||
{ value: 'catering_services', label: 'Catering Services' },
|
||||
{ value: 'fast_food', label: 'Fast Food' },
|
||||
{ value: 'cloud_kitchen', label: 'Cloud Kitchen' }
|
||||
];
|
||||
|
||||
|
||||
return (
|
||||
<Box sx={{ p: { xs: 2, sm: 3 }, backgroundColor: '#FFFFFF', borderRadius: 2, maxWidth: '100%' }}>
|
||||
<Typography variant="h4" sx={{ mb: 3, fontWeight: 'bold' }}>Restaurant Profile</Typography>
|
||||
|
||||
{/* صورة البروفايل */}
|
||||
{/* <Box sx={{ display: 'flex', alignItems: 'center', mb: 3 }}>
|
||||
<label htmlFor="icon-button-file">
|
||||
<Input accept="image/*" id="icon-button-file" type="file" onChange={handleImageUpload} />
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
width: 110, height: 110, border: '2px dashed #4C535F', borderRadius: 2,
|
||||
display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
|
||||
color: '#4C535F', cursor: 'pointer', textAlign: 'center', backgroundColor: '#f6f6f6'
|
||||
}}
|
||||
>
|
||||
<AddAPhotoOutlinedIcon sx={{ fontSize: 28, mb: 1 }} />
|
||||
<Typography sx={{ fontSize: '13px', fontWeight: 500 }}>Upload your photo</Typography>
|
||||
</Box>
|
||||
</label>
|
||||
</Box> */}
|
||||
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={100}
|
||||
sx={{
|
||||
mt: 2,
|
||||
mb: 3,
|
||||
height: 4,
|
||||
borderRadius: 2,
|
||||
backgroundColor: "#f0f0f0",
|
||||
"& .MuiLinearProgress-bar": { backgroundColor: theme.palette.primary.main },
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* الحقول */}
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 ,p:3, display: 'flex', flexWrap: 'wrap', border: '1px solid #e0e0e0', borderRadius: 2, boxShadow: '0px 4px 8px rgba(0, 0, 0, 0.1)'}}>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{renderField('Restaurant Name', form.restaurant_name, 'restaurant_name')}
|
||||
|
||||
{renderField('Restaurant Type', form.restaurant_type, 'restaurant_type')}
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{renderField('Address', form.Address, 'Address')}
|
||||
{renderField('City', form.City, 'City')}
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{renderField('Postal Code', form.Postal_code, 'Postal_code')}
|
||||
{renderField('Phone', form.Phone, 'Phone')}
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{renderField('Email', form.Email, 'Email')}
|
||||
{renderField('Operation Hours', form.Operation_hour, 'Operation_hour')}
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{renderField('Host Type', form.host_type, 'host_type')}
|
||||
<Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
<Typography variant="body2" sx={{ fontWeight: '500', fontSize: '16px' }}>Collaboration Type</Typography>
|
||||
{editMode ? (
|
||||
<Select
|
||||
value={form.collaboration_type || ''}
|
||||
onChange={(e) => handleChange('collaboration_type', e.target.value)}
|
||||
displayEmpty
|
||||
fullWidth
|
||||
sx={{
|
||||
'& .MuiOutlinedInput-root': {
|
||||
borderRadius: '10px',
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MenuItem value="">
|
||||
{/* <em>None</em> اختياري */}
|
||||
</MenuItem>
|
||||
{collaborationOptions.map(option => (
|
||||
<MenuItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
) : (
|
||||
<Typography variant="body1" sx={{ fontWeight: 500, fontSize: '15px' }}>
|
||||
{form.collaboration_type ? collaborationOptions.find(opt => opt.value === form.collaboration_type)?.label : 'None'}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{renderField('Closed Days', form.closed_days, 'closed_days', daysOfWeek)}
|
||||
</Box>
|
||||
|
||||
{/* القدرة التشغيلية */}
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{renderField('Maximum Orders per Day', form.Maximum_orders_per_day, 'Maximum_orders_per_day')}
|
||||
{renderField('Number of Chefs', form.Number_of_Cheff, 'Number_of_Cheff')}
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{renderField('Number of Waiters', form.Number_of_Waiters, 'Number_of_Waiters')}
|
||||
{renderField('Number of Cookers', form.Number_of_Cookers, 'Number_of_Cookers')}
|
||||
</Box>
|
||||
|
||||
{/* المعدات */}
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
<Typography variant="body2" sx={{ fontWeight: '500', fontSize: '16px' }}>Equipment Name</Typography>
|
||||
{form.equipment.map((eq, index) => (
|
||||
<Box key={index} sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
|
||||
<TextField
|
||||
|
||||
value={eq.name}
|
||||
onChange={(e) => handleEquipmentChange(index, 'name', e.target.value)}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
disabled={!editMode}
|
||||
sx={{ '& input': { fontWeight: 500, fontSize: '16px' } }}
|
||||
/>
|
||||
<TextField
|
||||
label="Quantity"
|
||||
type="number"
|
||||
value={eq.quantity}
|
||||
onChange={(e) => handleEquipmentChange(index, 'quantity', Number(e.target.value))}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
disabled={!editMode}
|
||||
sx={{ '& input': { fontWeight: 500, fontSize: '16px' } ,borderRadius:20}}
|
||||
/>
|
||||
{editMode && (
|
||||
<Button color="error" onClick={() => removeEquipment(index)}>
|
||||
Delete
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
{editMode && (
|
||||
<Button variant="outlined" onClick={addEquipment} startIcon={<AddIcon/>} sx={{ mt: 1, width: 'fit-content' , textTransform:'none' }}>
|
||||
Add Equipment
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* أزرار التحكم */}
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end', gap: 2, flexWrap: 'wrap', mt: 3 }}>
|
||||
{editMode ? (
|
||||
<>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() => setEditMode(false)}
|
||||
sx={{ px: 4, py: 1.5, borderRadius: 2, textTransform: 'none', fontWeight: 'bold' }}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSave}
|
||||
sx={{
|
||||
px: 4, py: 1.5, borderRadius: 2,
|
||||
textTransform: 'none', fontWeight: 'bold',
|
||||
color: '#FFF', backgroundColor: theme.palette.primary.main
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => setEditMode(true)}
|
||||
sx={{
|
||||
px: 4, py: 1.5, borderRadius: 2,
|
||||
textTransform: 'none', fontWeight: 'bold',
|
||||
color: '#FFF', backgroundColor: theme.palette.primary.main
|
||||
}}
|
||||
>
|
||||
Edit Profile
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountProfile;
|
||||
Reference in New Issue
Block a user