Initial commit
This commit is contained in:
516
src/layout/MainLayout/Header.jsx
Normal file
516
src/layout/MainLayout/Header.jsx
Normal file
@@ -0,0 +1,516 @@
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
AppBar,
|
||||
Toolbar,
|
||||
IconButton,
|
||||
Box,
|
||||
InputBase,
|
||||
Badge,
|
||||
Avatar,
|
||||
Typography,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Divider,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Tooltip,
|
||||
Button,
|
||||
Stack,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
TextField,
|
||||
Grid,
|
||||
alpha,
|
||||
InputAdornment
|
||||
} from '@mui/material';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import NotificationsNoneIcon from '@mui/icons-material/NotificationsNone';
|
||||
import ChatIcon from '@mui/icons-material/Chat';
|
||||
import LogoutIcon from '@mui/icons-material/Logout';
|
||||
import LocalShippingOutlinedIcon from '@mui/icons-material/LocalShippingOutlined';
|
||||
import QrCodeScannerIcon from '@mui/icons-material/QrCodeScanner';
|
||||
import AcUnitIcon from '@mui/icons-material/AcUnit';
|
||||
import TwoWheelerIcon from '@mui/icons-material/TwoWheeler';
|
||||
import DoneAllIcon from '@mui/icons-material/DoneAll';
|
||||
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
|
||||
import SendIcon from '@mui/icons-material/Send';
|
||||
|
||||
import Logo from '@/components/Logo';
|
||||
|
||||
const RED = '#C01227';
|
||||
|
||||
const INITIAL_NOTIFICATIONS = [
|
||||
{ id: 1, icon: LocalShippingOutlinedIcon, title: 'Linehaul MH-04-AX-8822 from Mumbai Hub arrived', time: '5 min ago', to: '/inbound', read: false },
|
||||
{ id: 2, icon: QrCodeScannerIcon, title: 'Manifest #MNF-2940 sorted & sealed', time: '15 min ago', to: '/dispatch', read: false },
|
||||
{ id: 3, icon: TwoWheelerIcon, title: 'Last-mile Miler Deepak went online', time: '30 min ago', to: '/dispatch', read: false },
|
||||
{ id: 4, icon: AcUnitIcon, title: 'Cold Storage Zone C temperature stabilized at 4.2°C', time: '1 hr ago', to: '/inventory', read: true }
|
||||
];
|
||||
|
||||
const MESSAGES = [
|
||||
{ id: 1, name: 'Devendra (Gate Supervisor)', text: 'Jaipur vehicle is backing into Bay 4 now.', time: '3 min ago', initials: 'DS' },
|
||||
{ id: 2, name: 'Suresh (Sorter Zone A)', text: 'Completed sorting for South Delhi batch. Ready to verify.', time: '12 min ago', initials: 'SS' },
|
||||
{ id: 3, name: 'Neha (Last-mile Dispatcher)', text: 'We need 2 more milers for South Delhi route.', time: '45 min ago', initials: 'ND' }
|
||||
];
|
||||
|
||||
const NOTIFICATION_DETAILS = {
|
||||
1: {
|
||||
title: 'Linehaul Arrival: Mumbai Hub',
|
||||
desc: 'Linehaul vehicle MH-04-AX-8822 has checked in at gate terminal Bay 4. Manifest includes 480 mixed corporate shipments.',
|
||||
stats: [
|
||||
{ label: 'Carrier Plate', value: 'MH-04-AX-8822' },
|
||||
{ label: 'Origin Node', value: 'Mumbai Hub (BOM-02)' },
|
||||
{ label: 'Inbound Sorters', value: 'Allocated (Zone A & C)' },
|
||||
{ label: 'Cold Chain items', value: '18 items binned' }
|
||||
],
|
||||
actionText: 'Go to Inbound Station',
|
||||
to: '/inbound'
|
||||
},
|
||||
2: {
|
||||
title: 'Sealed Outbound Manifest #MNF-2940',
|
||||
desc: 'Sorting manifest #MNF-2940 has been closed, sealed, and audited by supervisor Suresh. Packages are loaded in transit cart.',
|
||||
stats: [
|
||||
{ label: 'Manifest ID', value: 'MNF-2940' },
|
||||
{ label: 'Route Zone', value: 'West Delhi (Dwarka)' },
|
||||
{ label: 'Packages Count', value: '42 items loaded' },
|
||||
{ label: 'Seal ID Code', value: 'SEAL-DEL-98402' }
|
||||
],
|
||||
actionText: 'Go to Outbound Dispatch',
|
||||
to: '/dispatch'
|
||||
},
|
||||
3: {
|
||||
title: 'Miler Deepak Sharma Online',
|
||||
desc: 'Last-mile EV miler Deepak Sharma logged into transit terminal app. Courier battery capacity 98% (Fully Charged).',
|
||||
stats: [
|
||||
{ label: 'Miler Name', value: 'Deepak Sharma' },
|
||||
{ label: 'Vehicle Class', value: 'EV Two-wheeler' },
|
||||
{ label: 'Capacity Limit', value: '35 kg' },
|
||||
{ label: 'Assigned Route', value: 'South Delhi (Saket)' }
|
||||
],
|
||||
actionText: 'Go to Outbound Dispatch',
|
||||
to: '/dispatch'
|
||||
},
|
||||
4: {
|
||||
title: 'Cold Storage Compliance Logged',
|
||||
desc: 'Sensor Zone C logged audit snapshot at 12:00 PM. Climate check parameters successfully verified at 4.2°C.',
|
||||
stats: [
|
||||
{ label: 'Chamber Area', value: 'Cold Zone Chamber C' },
|
||||
{ label: 'Sensor Reading', value: '4.2°C (Target: 2-8°C)' },
|
||||
{ label: 'Log ID', value: 'LOG-C-98248102' },
|
||||
{ label: 'Status', value: 'Optimal Compliance' }
|
||||
],
|
||||
actionText: 'Go to Storage & Bins',
|
||||
to: '/inventory'
|
||||
}
|
||||
};
|
||||
|
||||
const INITIAL_CHATS = {
|
||||
1: {
|
||||
name: 'Devendra (Gate Supervisor)',
|
||||
initials: 'DS',
|
||||
chat: [
|
||||
{ sender: 'them', text: 'Jaipur vehicle is backing into Bay 4 now. Sorters are ready.', time: '11:20 AM' },
|
||||
{ sender: 'me', text: 'Excellent. Please verify temperature logs for the cold container immediately upon opening.', time: '11:21 AM' },
|
||||
{ sender: 'them', text: 'Got it, Rajesh. Handled by sorter Devendra.', time: '11:22 AM' }
|
||||
]
|
||||
},
|
||||
2: {
|
||||
name: 'Suresh (Sorter Zone A)',
|
||||
initials: 'SS',
|
||||
chat: [
|
||||
{ sender: 'them', text: 'Completed sorting for South Delhi batch. Ready to verify.', time: '11:10 AM' },
|
||||
{ sender: 'me', text: 'Have all exceptions been routed to Zone D?', time: '11:12 AM' },
|
||||
{ sender: 'them', text: 'Yes, 3 damaged boxes are in Zone D. Rest are loaded in the manifest bags.', time: '11:15 AM' }
|
||||
]
|
||||
},
|
||||
3: {
|
||||
name: 'Neha (Last-mile Dispatcher)',
|
||||
initials: 'ND',
|
||||
chat: [
|
||||
{ sender: 'them', text: 'We need 2 more milers for South Delhi route. Surge in fashion orders.', time: '10:40 AM' },
|
||||
{ sender: 'me', text: 'Let me ping Deepak and Yashpal to see if they can start early shift.', time: '10:45 AM' },
|
||||
{ sender: 'them', text: 'Deepak just logged online. Still need one more.', time: '11:05 AM' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export default function Header({ onToggle }) {
|
||||
const navigate = useNavigate();
|
||||
const [account, setAccount] = useState(null);
|
||||
const [notifAnchor, setNotifAnchor] = useState(null);
|
||||
const [msgAnchor, setMsgAnchor] = useState(null);
|
||||
|
||||
// Dialog State
|
||||
const [selectedNotif, setSelectedNotif] = useState(null);
|
||||
const [selectedChatId, setSelectedChatId] = useState(null);
|
||||
const [chats, setChats] = useState(INITIAL_CHATS);
|
||||
const [typedMessage, setTypedMessage] = useState('');
|
||||
|
||||
const [notifications, setNotifications] = useState(INITIAL_NOTIFICATIONS);
|
||||
const [search, setSearch] = useState('');
|
||||
|
||||
const unread = notifications.filter((n) => !n.read).length;
|
||||
|
||||
const openNotif = (e) => setNotifAnchor(e.currentTarget);
|
||||
const closeNotif = () => setNotifAnchor(null);
|
||||
const markAllRead = () => setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));
|
||||
|
||||
const onNotifClick = (n) => {
|
||||
setNotifications((prev) => prev.map((x) => (x.id === n.id ? { ...x, read: true } : x)));
|
||||
closeNotif();
|
||||
if (NOTIFICATION_DETAILS[n.id]) {
|
||||
setSelectedNotif(NOTIFICATION_DETAILS[n.id]);
|
||||
} else {
|
||||
navigate(n.to);
|
||||
}
|
||||
};
|
||||
|
||||
const onMessageClick = (mId) => {
|
||||
setMsgAnchor(null);
|
||||
setSelectedChatId(mId);
|
||||
};
|
||||
|
||||
const handleSendMessage = () => {
|
||||
if (!typedMessage.trim() || !selectedChatId) return;
|
||||
const now = new Date();
|
||||
const timeStr = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
|
||||
setChats((prev) => {
|
||||
const activeChat = prev[selectedChatId];
|
||||
return {
|
||||
...prev,
|
||||
[selectedChatId]: {
|
||||
...activeChat,
|
||||
chat: [
|
||||
...activeChat.chat,
|
||||
{ sender: 'me', text: typedMessage, time: timeStr }
|
||||
]
|
||||
}
|
||||
};
|
||||
});
|
||||
setTypedMessage('');
|
||||
};
|
||||
|
||||
const submitSearch = (e) => {
|
||||
e.preventDefault();
|
||||
const q = search.trim();
|
||||
if (q) navigate(`/routing?q=${encodeURIComponent(q)}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<AppBar
|
||||
position="fixed"
|
||||
elevation={0}
|
||||
sx={{
|
||||
bgcolor: '#FFFFFF',
|
||||
color: 'text.primary',
|
||||
zIndex: (t) => t.zIndex.drawer + 1,
|
||||
borderBottom: '1px solid',
|
||||
borderColor: 'grey.200'
|
||||
}}
|
||||
>
|
||||
<Toolbar sx={{ minHeight: 64, px: { xs: 1.5, sm: 2.5 }, gap: 1 }}>
|
||||
<IconButton color="inherit" edge="start" onClick={onToggle} sx={{ mr: 0.5 }}>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
|
||||
{/* Brand wordmark — left side */}
|
||||
<Box
|
||||
onClick={() => navigate('/dashboard')}
|
||||
sx={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
||||
>
|
||||
<Logo height={22} />
|
||||
</Box>
|
||||
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
|
||||
{/* Search */}
|
||||
<Box
|
||||
component="form"
|
||||
onSubmit={submitSearch}
|
||||
sx={{
|
||||
display: { xs: 'none', sm: 'flex' },
|
||||
alignItems: 'center',
|
||||
bgcolor: 'grey.100',
|
||||
borderRadius: 2,
|
||||
px: 1.5,
|
||||
py: 0.5,
|
||||
width: { sm: 240, md: 320 },
|
||||
border: '1px solid',
|
||||
borderColor: 'grey.200',
|
||||
'&:hover': { bgcolor: 'grey.200' }
|
||||
}}
|
||||
>
|
||||
<SearchIcon sx={{ fontSize: 20, mr: 1, color: 'text.secondary' }} />
|
||||
<InputBase
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder="Scan package, check destination…"
|
||||
sx={{ fontSize: '0.875rem', flex: 1 }}
|
||||
inputProps={{ 'aria-label': 'search' }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Tooltip title="Messages">
|
||||
<IconButton color="inherit" onClick={(e) => setMsgAnchor(e.currentTarget)}>
|
||||
<Badge badgeContent={MESSAGES.length} color="error">
|
||||
<ChatIcon />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Notifications">
|
||||
<IconButton color="inherit" onClick={openNotif}>
|
||||
<Badge badgeContent={unread} color="error">
|
||||
<NotificationsNoneIcon />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
<Box
|
||||
onClick={(e) => setAccount(e.currentTarget)}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
ml: 0.5,
|
||||
cursor: 'pointer',
|
||||
py: 0.5,
|
||||
px: 1,
|
||||
borderRadius: 2,
|
||||
'&:hover': { bgcolor: 'grey.100' }
|
||||
}}
|
||||
>
|
||||
<Avatar sx={{ width: 34, height: 34, bgcolor: RED, color: '#fff', fontWeight: 700 }}>RK</Avatar>
|
||||
<Box sx={{ display: { xs: 'none', md: 'block' }, lineHeight: 1.1 }}>
|
||||
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
|
||||
Rajesh Kumar
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
||||
Delhi Hub Manager
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Notifications dropdown */}
|
||||
<Menu
|
||||
anchorEl={notifAnchor}
|
||||
open={Boolean(notifAnchor)}
|
||||
onClose={closeNotif}
|
||||
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
||||
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||
PaperProps={{ sx: { mt: 1, width: 360, maxWidth: '90vw' } }}
|
||||
>
|
||||
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ px: 2, py: 1.25 }}>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
|
||||
Notifications
|
||||
</Typography>
|
||||
<Button size="small" startIcon={<DoneAllIcon fontSize="small" />} onClick={markAllRead} disabled={unread === 0}>
|
||||
Mark all read
|
||||
</Button>
|
||||
</Stack>
|
||||
<Divider />
|
||||
{notifications.length === 0 && (
|
||||
<MenuItem disabled>
|
||||
<ListItemText primary="No notifications" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{notifications.map((n) => {
|
||||
const Icon = n.icon;
|
||||
return (
|
||||
<MenuItem key={n.id} onClick={() => onNotifClick(n)} sx={{ py: 1.25, whiteSpace: 'normal', alignItems: 'flex-start' }}>
|
||||
<ListItemIcon sx={{ mt: 0.25 }}>
|
||||
<Avatar sx={{ width: 34, height: 34, bgcolor: n.read ? 'grey.200' : alpha(RED, 0.12), color: RED }}>
|
||||
<Icon fontSize="small" />
|
||||
</Avatar>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={n.title}
|
||||
secondary={n.time}
|
||||
primaryTypographyProps={{ fontSize: '0.875rem', fontWeight: n.read ? 500 : 700 }}
|
||||
secondaryTypographyProps={{ fontSize: '0.75rem' }}
|
||||
/>
|
||||
{!n.read && <Box sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: RED, mt: 1, ml: 0.5 }} />}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
|
||||
{/* Messages dropdown */}
|
||||
<Menu
|
||||
anchorEl={msgAnchor}
|
||||
open={Boolean(msgAnchor)}
|
||||
onClose={() => setMsgAnchor(null)}
|
||||
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
||||
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||
PaperProps={{ sx: { mt: 1, width: 340, maxWidth: '90vw' } }}
|
||||
>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 700, px: 2, py: 1.25 }}>
|
||||
Messages
|
||||
</Typography>
|
||||
<Divider />
|
||||
{MESSAGES.map((m) => (
|
||||
<MenuItem key={m.id} onClick={() => onMessageClick(m.id)} sx={{ py: 1.25, whiteSpace: 'normal', alignItems: 'flex-start' }}>
|
||||
<ListItemIcon sx={{ mt: 0.25 }}>
|
||||
<Avatar sx={{ width: 34, height: 34, bgcolor: alpha(RED, 0.12), color: RED, fontWeight: 700, fontSize: '0.8rem' }}>
|
||||
{m.initials}
|
||||
</Avatar>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={m.name}
|
||||
secondary={m.text}
|
||||
primaryTypographyProps={{ fontSize: '0.875rem', fontWeight: 700 }}
|
||||
secondaryTypographyProps={{ fontSize: '0.8rem' }}
|
||||
/>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ ml: 1, mt: 0.5, flexShrink: 0 }}>
|
||||
{m.time}
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
|
||||
{/* Account dropdown */}
|
||||
<Menu
|
||||
anchorEl={account}
|
||||
open={Boolean(account)}
|
||||
onClose={() => setAccount(null)}
|
||||
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
||||
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||
PaperProps={{ sx: { mt: 1, minWidth: 200 } }}
|
||||
>
|
||||
<MenuItem onClick={() => { setAccount(null); navigate('/login'); }} sx={{ color: 'error.main' }}>
|
||||
<ListItemIcon><LogoutIcon fontSize="small" color="error" /></ListItemIcon>
|
||||
Logout
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Toolbar>
|
||||
|
||||
{/* High Fidelity Notification Detail Dialog */}
|
||||
<Dialog open={Boolean(selectedNotif)} onClose={() => setSelectedNotif(null)} fullWidth maxWidth="sm">
|
||||
{selectedNotif && (
|
||||
<>
|
||||
<DialogTitle sx={{ fontWeight: 700, bgcolor: 'grey.50', py: 2 }}>
|
||||
{selectedNotif.title}
|
||||
</DialogTitle>
|
||||
<Divider />
|
||||
<DialogContent sx={{ py: 3 }}>
|
||||
<Typography variant="body1" sx={{ mb: 3 }}>
|
||||
{selectedNotif.desc}
|
||||
</Typography>
|
||||
<Typography variant="subtitle2" sx={{ fontWeight: 700, mb: 1.5, textTransform: 'uppercase', letterSpacing: '0.05em', color: 'text.secondary' }}>
|
||||
Operational Details
|
||||
</Typography>
|
||||
<Grid container spacing={2}>
|
||||
{selectedNotif.stats.map((stat, index) => (
|
||||
<Grid size={{ xs: 6 }} key={index}>
|
||||
<Box sx={{ p: 2, bgcolor: 'grey.50', borderRadius: 2, border: '1px solid', borderColor: 'grey.200' }}>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', fontWeight: 600 }}>
|
||||
{stat.label}
|
||||
</Typography>
|
||||
<Typography variant="subtitle2" sx={{ fontWeight: 700, mt: 0.5 }}>
|
||||
{stat.value}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<Divider />
|
||||
<DialogActions sx={{ p: 2 }}>
|
||||
<Button onClick={() => setSelectedNotif(null)}>Dismiss</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
endIcon={<ArrowForwardIcon fontSize="small" />}
|
||||
onClick={() => {
|
||||
setSelectedNotif(null);
|
||||
navigate(selectedNotif.to);
|
||||
}}
|
||||
>
|
||||
{selectedNotif.actionText}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
|
||||
{/* High Fidelity Chat Message Dialog */}
|
||||
<Dialog open={Boolean(selectedChatId)} onClose={() => setSelectedChatId(null)} fullWidth maxWidth="xs">
|
||||
{selectedChatId && chats[selectedChatId] && (
|
||||
<>
|
||||
<DialogTitle sx={{ fontWeight: 700, py: 2, display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
||||
<Avatar sx={{ bgcolor: alpha(RED, 0.12), color: RED, fontWeight: 700, width: 34, height: 34 }}>
|
||||
{chats[selectedChatId].initials}
|
||||
</Avatar>
|
||||
<Typography variant="h5" sx={{ fontWeight: 700 }}>
|
||||
{chats[selectedChatId].name}
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<Divider />
|
||||
<DialogContent sx={{ p: 2, bgcolor: 'grey.50', height: 280, display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
|
||||
<Stack spacing={2} sx={{ overflowY: 'auto', pr: 0.5, flexGrow: 1, mb: 2 }}>
|
||||
{chats[selectedChatId].chat.map((msg, idx) => (
|
||||
<Box
|
||||
key={idx}
|
||||
sx={{
|
||||
alignSelf: msg.sender === 'me' ? 'flex-end' : 'flex-start',
|
||||
maxWidth: '80%'
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
p: 1.5,
|
||||
borderRadius: 2,
|
||||
bgcolor: msg.sender === 'me' ? RED : '#FFFFFF',
|
||||
color: msg.sender === 'me' ? '#FFFFFF' : 'text.primary',
|
||||
boxShadow: '0 1px 2px rgba(0,0,0,0.08)',
|
||||
border: msg.sender === 'me' ? 'none' : '1px solid',
|
||||
borderColor: 'grey.200'
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1">
|
||||
{msg.text}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
sx={{
|
||||
display: 'block',
|
||||
mt: 0.5,
|
||||
textAlign: msg.sender === 'me' ? 'right' : 'left'
|
||||
}}
|
||||
>
|
||||
{msg.time}
|
||||
</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<Divider />
|
||||
<DialogActions sx={{ p: 1.5 }}>
|
||||
<TextField
|
||||
fullWidth
|
||||
size="small"
|
||||
placeholder="Type your message..."
|
||||
value={typedMessage}
|
||||
onChange={(e) => setTypedMessage(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && handleSendMessage()}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton onClick={handleSendMessage} size="small" color="primary">
|
||||
<SendIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogActions>
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
</AppBar>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user