Skip to content

Commit

Permalink
completed datepicker popper component
Browse files Browse the repository at this point in the history
  • Loading branch information
ali-ahnaf committed Jan 30, 2025
1 parent 7775a4b commit 87b9172
Show file tree
Hide file tree
Showing 5 changed files with 1,373 additions and 1,123 deletions.
2 changes: 1 addition & 1 deletion client/src/components/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ const EventCard = ({ sx, event, onDelete, handleEditClick, hideMenu }: EventCard
}}
onClick={chip.action}
deleteIcon={chip.endIcon}
onDelete={chip.endIconAction}
onDelete={chip.endIcon && chip.endIconAction}
/>
</Tooltip>
</ListItem>
Expand Down
40 changes: 22 additions & 18 deletions client/src/pages/Home/MyEventsView/DateNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft';
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
import { Box, IconButton } from '@mui/material';
import { styled } from '@mui/material/styles';
import Grid from '@mui/material/Grid2';

import React, { ReactNode } from 'react';

interface DateNavigatorProps {
Expand All @@ -17,28 +19,30 @@ const StyledButton = styled(IconButton)(({ theme }) => ({
boxShadow: 'none',
color: theme.palette.primary.main,
},
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}));

const DateNavigator: React.FC<DateNavigatorProps> = ({ children, onPrevClick, onNextClick }) => {
return (
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
mb: 1,
}}
>
<StyledButton size="small" onClick={onPrevClick}>
<KeyboardArrowLeft sx={{ fontSize: 30 }} />
</StyledButton>
{children}
<StyledButton size="small" onClick={onNextClick}>
<KeyboardArrowRight sx={{ fontSize: 30 }} />
</StyledButton>
<Box sx={{ flexGrow: 1 }}>
<Grid
container
spacing={3}
sx={{
alignItems: 'center',
}}
>
<Grid size="grow">
<StyledButton size="small" onClick={onPrevClick}>
<KeyboardArrowLeft sx={{ fontSize: 30 }} />
</StyledButton>
</Grid>
<Grid size={6}>{children}</Grid>
<Grid size="grow">
<StyledButton size="small" onClick={onNextClick}>
<KeyboardArrowRight sx={{ fontSize: 30 }} />
</StyledButton>
</Grid>
</Grid>
</Box>
);
};
Expand Down
51 changes: 31 additions & 20 deletions client/src/pages/Home/MyEventsView/DatePickerPopper.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Box, Button, Chip, Divider, Fade, List, ListItem, Paper, Popper } from '@mui/material';
import { StaticDatePicker, PickersShortcutsItem, PickersShortcutsProps } from '@mui/x-date-pickers';
import { Box, Chip, ClickAwayListener, Divider, Fade, List, ListItem, Popper } from '@mui/material';
import { StaticDatePicker, PickersShortcutsItem, PickersShortcutsProps, type PickerChangeHandlerContext, type DateValidationError } from '@mui/x-date-pickers';
import dayjs from 'dayjs';
import { useState } from 'react';
import { useEffect, useRef } from 'react';

// https://mui.com/x/react-date-pickers/shortcuts/
const shortcutItems: PickersShortcutsItem<unknown>[] = [
Expand Down Expand Up @@ -71,20 +71,36 @@ interface DatePickerPopperProps {
setCurrentDate: React.Dispatch<React.SetStateAction<dayjs.Dayjs>>;
open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
anchorEl: HTMLElement | null;
}

const DatePickerPopper = ({ open, setOpen, currentDate, setCurrentDate }: DatePickerPopperProps) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const DatePickerPopper = ({ open, setOpen, currentDate, setCurrentDate, anchorEl }: DatePickerPopperProps) => {
const hasMounted = useRef(false);

const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
setOpen((prev) => !prev);
useEffect(() => {
if (!open) {
hasMounted.current = false;
}
}, [open]);

const handleClickAway = () => {
// on initial mount, this method gets called. to prevent that, the flag hasMounted has been used
if (!hasMounted.current) {
hasMounted.current = true;
return;
}
setOpen(false);
};

return (
<Box>
<Button onClick={handleClick}>Open Date Picker</Button>
const onDateChange = (newDate: dayjs.Dayjs | null, _?: PickerChangeHandlerContext<DateValidationError>) => {
if (newDate) {
setCurrentDate(newDate);
setOpen(false);
}
};

return (
<ClickAwayListener onClickAway={handleClickAway}>
<Popper sx={{ zIndex: 1200 }} open={open} anchorEl={anchorEl} placement="bottom" transition>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
Expand All @@ -94,14 +110,9 @@ const DatePickerPopper = ({ open, setOpen, currentDate, setCurrentDate }: DatePi
}}
>
<StaticDatePicker
onChange={(newDate, context) => {
if (!context?.shortcut) {
if (newDate) {
setCurrentDate(newDate);
setOpen(false);
}
}
}}
onAccept={(value, context) => console.log(value, context)}
onError={(err, val) => console.log(err, val)}
onChange={onDateChange}
value={currentDate}
slots={{
shortcuts: DatePickerShortcuts,
Expand Down Expand Up @@ -130,7 +141,7 @@ const DatePickerPopper = ({ open, setOpen, currentDate, setCurrentDate }: DatePi
</Fade>
)}
</Popper>
</Box>
</ClickAwayListener>
);
};

Expand Down
150 changes: 35 additions & 115 deletions client/src/pages/Home/MyEventsView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,81 +6,19 @@ import EventCard from '@components/EventCard';
import { ROUTES } from '@config/routes';
import { FormData } from '@helpers/types';
import { convertToRFC3339, getTimeZoneString, renderError } from '@helpers/utility';
import { Box, Chip, Divider, List, ListItem, Skeleton, Stack, Typography } from '@mui/material';
import { Box, Divider, Skeleton, Stack, Tooltip, Typography } from '@mui/material';
import { BookRoomDto, EventResponse, IConferenceRoom } from '@quickmeet/shared';
import React, { useEffect, useRef, useState } from 'react';
import toast from 'react-hot-toast';
import { useNavigate } from 'react-router-dom';
import EditEventsView from './EditEventsView';
import { DatePicker, PickersShortcutsProps, PickersShortcutsItem } from '@mui/x-date-pickers';
import dayjs from 'dayjs';
import DatePickerPopper from '@/pages/Home/MyEventsView/DatePickerPopper';

interface MyEventsViewProps {
redirectedDate?: string;
}

// https://mui.com/x/react-date-pickers/shortcuts/
const shortcutItems: PickersShortcutsItem<unknown>[] = [
{
label: 'Reset',
getValue: () => {
return dayjs(new Date());
},
},
];

function DatePickerShortcuts(props: PickersShortcutsProps<dayjs.Dayjs | null>) {
const { items, onChange, isValid, changeImportance = 'accept' } = props;

if (items == null || items.length === 0) {
return null;
}

const resolvedItems = items.map((item) => {
const newValue = item.getValue({ isValid });

return {
label: item.label,
onClick: () => {
onChange(newValue, changeImportance, item);
},
disabled: !isValid(newValue),
};
});

return (
<Box
sx={{
gridRow: 1,
gridColumn: 2,
}}
>
<List
dense
sx={(theme) => ({
display: 'flex',
px: theme.spacing(1),
'& .MuiListItem-root': {
pl: 0,
pr: theme.spacing(1),
py: 0,
},
})}
>
{resolvedItems.map((item) => {
return (
<ListItem key={item.label}>
<Chip {...item} />
</ListItem>
);
})}
</List>
<Divider />
</Box>
);
}

export default function MyEventsView({ redirectedDate }: MyEventsViewProps) {
const [loading, setLoading] = useState(true);
const [editLoading, setEditLoading] = useState(false);
Expand All @@ -93,9 +31,11 @@ export default function MyEventsView({ redirectedDate }: MyEventsViewProps) {
const api = useApi();
const { preferences } = usePreferences();

const [datePickerOpen, setDatePickerOpen] = useState(false);
const [datePickerOpen, setDatePickerOpen] = useState<boolean>(false);

const [currentDate, setCurrentDate] = useState<dayjs.Dayjs>(dayjs(redirectedDate) || dayjs());
const [datePickerAnchorEl, setDatePickerAnchorEl] = useState<null | HTMLElement>(null);

const abortControllerRef = useRef<AbortController | null>(null);

useEffect(() => {
Expand Down Expand Up @@ -139,6 +79,13 @@ export default function MyEventsView({ redirectedDate }: MyEventsViewProps) {
};
}, []);

const handleDatePopperClick = (event: React.MouseEvent<HTMLElement>) => {
console.log(datePickerOpen);

setDatePickerAnchorEl(event.currentTarget);
setDatePickerOpen(true);
};

const handleDeleteClick = (id: string) => {
setDeleteEventId(id);
setDeleteEventViewOpen(true);
Expand Down Expand Up @@ -282,63 +229,29 @@ export default function MyEventsView({ redirectedDate }: MyEventsViewProps) {
sx={{
display: 'flex',
overflow: 'hidden',
justifyContent: 'center',
flexDirection: 'column',
px: 2,
}}
>
<Box>
<DatePickerPopper currentDate={currentDate} setCurrentDate={setCurrentDate} open={datePickerOpen} setOpen={setDatePickerOpen} />
<Box
sx={{
display: 'flex',
mb: 1,
}}
>
{/* Date Navigator */}
<DateNavigator onPrevClick={handlePrevDate} onNextClick={handleNextDate}>
<DatePicker
format="MMMM DD, YYYY"
onChange={(newDate) => {
if (newDate) {
setCurrentDate(newDate);
}
}}
value={currentDate}
slots={{
shortcuts: DatePickerShortcuts,
}}
slotProps={{
inputAdornment: {
position: 'start',
sx: {
input: {
cursor: 'pointer',
},
},
},
field: {
readOnly: true,
},
shortcuts: {
items: shortcutItems,
changeImportance: 'set',
},
}}
sx={{
'.MuiOutlinedInput-root': {
'& fieldset': {
border: 'none',
},
},
'.MuiInputBase-input': {
color: (theme) => theme.palette.common.black,
fontFamily: 'inherit',
fontSize: '1.1rem',
fontWeight: 400,
cursor: 'default',
p: 0,
},
'.MuiSvgIcon-root': {
color: (theme) => theme.palette.grey[50],
},
'.MuiButtonBase-root': { cursor: 'pointer' },
}}
/>
<Tooltip title={'Open up the calender'}>
<Typography
sx={{
cursor: 'pointer',
}}
onClick={handleDatePopperClick}
variant="subtitle1"
>
{currentDate.format('ddd MMM D, YYYY')}
</Typography>
</Tooltip>
</DateNavigator>
</Box>

Expand Down Expand Up @@ -391,6 +304,13 @@ export default function MyEventsView({ redirectedDate }: MyEventsViewProps) {
)}
</>
)}
<DatePickerPopper
currentDate={currentDate}
setCurrentDate={setCurrentDate}
open={datePickerOpen}
setOpen={setDatePickerOpen}
anchorEl={datePickerAnchorEl}
/>
</Box>
);
}
Loading

0 comments on commit 87b9172

Please sign in to comment.