feat: move headerToolbar functionality to Menubar component
- Remove headerToolbar from FullCalendar and set to false - Create CalendarLayout component to manage state between Menubar and Calendar - Add navigation controls (prev/today/next) to Menubar left-menu using MUI ButtonGroup - Add current date/time display (April 2024 format) to Menubar left-menu - Add view selector (Month/Week/Day) to Menubar right-menu using MUI Select - Implement real-time date synchronization between Calendar and Menubar
This commit is contained in:
@@ -1,11 +1,25 @@
|
||||
import React, { useState } from "react";
|
||||
import logo from "../../static/images/calendar.svg";
|
||||
import AppsIcon from "@mui/icons-material/Apps";
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||
import "./Menubar.css";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import { stringToColor } from "../../features/Events/EventDisplay";
|
||||
import { Avatar, IconButton, Popover } from "@mui/material";
|
||||
import {
|
||||
Avatar,
|
||||
IconButton,
|
||||
Popover,
|
||||
ButtonGroup,
|
||||
Button,
|
||||
Select,
|
||||
MenuItem,
|
||||
FormControl,
|
||||
Typography
|
||||
} from "@mui/material";
|
||||
import { push } from "redux-first-history";
|
||||
import { CalendarApi } from "@fullcalendar/core";
|
||||
|
||||
export type AppIconProps = {
|
||||
name: string;
|
||||
@@ -13,10 +27,18 @@ export type AppIconProps = {
|
||||
icon: string;
|
||||
};
|
||||
|
||||
export function Menubar() {
|
||||
export type MenubarProps = {
|
||||
calendarRef: React.RefObject<CalendarApi | null>;
|
||||
onRefresh: () => void;
|
||||
currentDate: Date;
|
||||
onDateChange?: (date: Date) => void;
|
||||
};
|
||||
|
||||
export function Menubar({ calendarRef, onRefresh, currentDate, onDateChange }: MenubarProps) {
|
||||
const user = useAppSelector((state) => state.user.userData);
|
||||
const applist: AppIconProps[] = (window as any).appList ?? [];
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
const [currentView, setCurrentView] = useState<string>("timeGridWeek");
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
if (!user) {
|
||||
@@ -30,37 +52,112 @@ export function Menubar() {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleNavigation = (action: 'prev' | 'next' | 'today') => {
|
||||
if (!calendarRef.current) return;
|
||||
|
||||
switch (action) {
|
||||
case 'prev':
|
||||
calendarRef.current.prev();
|
||||
break;
|
||||
case 'next':
|
||||
calendarRef.current.next();
|
||||
break;
|
||||
case 'today':
|
||||
calendarRef.current.today();
|
||||
break;
|
||||
}
|
||||
|
||||
// Notify parent about date change after navigation
|
||||
if (onDateChange) {
|
||||
const newDate = calendarRef.current.getDate();
|
||||
onDateChange(newDate);
|
||||
}
|
||||
};
|
||||
|
||||
const handleViewChange = (view: string) => {
|
||||
if (!calendarRef.current) return;
|
||||
setCurrentView(view);
|
||||
calendarRef.current.changeView(view);
|
||||
|
||||
// Notify parent about date change after view change
|
||||
if (onDateChange) {
|
||||
const newDate = calendarRef.current.getDate();
|
||||
onDateChange(newDate);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
onRefresh();
|
||||
};
|
||||
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
return (
|
||||
<>
|
||||
<header className="menubar">
|
||||
<MainTitle />
|
||||
<div className="menubar-item search-bar">
|
||||
<p>big search bar</p>
|
||||
</div>
|
||||
<div className="left-menu">
|
||||
<MainTitle />
|
||||
|
||||
<div className="navigation-controls">
|
||||
<ButtonGroup variant="outlined" size="small">
|
||||
<Button onClick={() => handleNavigation('prev')}>
|
||||
<ChevronLeftIcon />
|
||||
</Button>
|
||||
<Button onClick={() => handleNavigation('today')}>
|
||||
Today
|
||||
</Button>
|
||||
<Button onClick={() => handleNavigation('next')}>
|
||||
<ChevronRightIcon />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
|
||||
<div className="menubar-item">
|
||||
{applist.length > 0 && (
|
||||
<IconButton onClick={handleOpen}>
|
||||
<AppsIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
<Avatar
|
||||
sx={{
|
||||
bgcolor: stringToColor(
|
||||
user && user.family_name
|
||||
? user.family_name
|
||||
: user && user.email
|
||||
? user.email
|
||||
: ""
|
||||
),
|
||||
}}
|
||||
sizes="large"
|
||||
>
|
||||
{user?.name && user?.family_name
|
||||
? `${user.name[0]}${user.family_name[0]}`
|
||||
: (user?.email?.[0] ?? "")}
|
||||
</Avatar>
|
||||
<div className="current-date-time">
|
||||
<Typography variant="h6" component="div">
|
||||
{currentDate.toLocaleDateString('en-US', {
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
})}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<div className="right-menu">
|
||||
<div className="menubar-item">
|
||||
<FormControl size="small" sx={{ minWidth: 120, mr: 2 }}>
|
||||
<Select
|
||||
value={currentView}
|
||||
onChange={(e) => handleViewChange(e.target.value)}
|
||||
variant="outlined"
|
||||
>
|
||||
<MenuItem value="dayGridMonth">Month</MenuItem>
|
||||
<MenuItem value="timeGridWeek">Week</MenuItem>
|
||||
<MenuItem value="timeGridDay">Day</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
{applist.length > 0 && (
|
||||
<IconButton onClick={handleOpen} sx={{ mr: 1 }}>
|
||||
<AppsIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
<Avatar
|
||||
sx={{
|
||||
bgcolor: stringToColor(
|
||||
user && user.family_name
|
||||
? user.family_name
|
||||
: user && user.email
|
||||
? user.email
|
||||
: ""
|
||||
),
|
||||
}}
|
||||
sizes="large"
|
||||
>
|
||||
{user?.name && user?.family_name
|
||||
? `${user.name[0]}${user.family_name[0]}`
|
||||
: (user?.email?.[0] ?? "")}
|
||||
</Avatar>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<Popover
|
||||
@@ -88,7 +185,7 @@ export function Menubar() {
|
||||
export function MainTitle() {
|
||||
return (
|
||||
<div className="menubar-item tc-home">
|
||||
<img className="logo" src={logo} />
|
||||
<img className="logo" src={logo} alt="Calendar" />
|
||||
<p>
|
||||
<span className="twake">Twake</span>
|
||||
<span className="calendar-text">Calendar</span>
|
||||
@@ -102,6 +199,7 @@ function AppIcon({ prop }: { prop: AppIconProps }) {
|
||||
<a
|
||||
href={prop.link}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
style={{ textDecoration: "none", color: "inherit" }}
|
||||
>
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user