Merge pull request #54 from linagora/4-story-manage-attendance
4 story manage attendance
This commit is contained in:
@@ -9,6 +9,9 @@ main {
|
||||
height: 90vh;
|
||||
}
|
||||
|
||||
.calendarListHeader {
|
||||
padding-top: 10px;
|
||||
}
|
||||
.sidebar {
|
||||
border-right: 2px gray;
|
||||
width: 20vw;
|
||||
@@ -27,6 +30,18 @@ main {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.declined-event {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.tentative-event {
|
||||
}
|
||||
|
||||
.needs-action-event {
|
||||
opacity: 0.7;
|
||||
border: dashed 1px #ffffff;
|
||||
}
|
||||
|
||||
.fc .fc-timegrid-slot {
|
||||
height: 30px !important;
|
||||
min-height: 30px !important;
|
||||
|
||||
@@ -27,12 +27,17 @@ import { Calendars } from "../../features/Calendars/CalendarTypes";
|
||||
import { push } from "redux-first-history";
|
||||
import EventDisplayModal from "../../features/Events/EventDisplay";
|
||||
import { createSelector } from "@reduxjs/toolkit";
|
||||
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import AccessTimeIcon from "@mui/icons-material/AccessTime";
|
||||
import { userAttendee } from "../../features/User/userDataTypes";
|
||||
|
||||
export default function CalendarApp() {
|
||||
const calendarRef = useRef<CalendarApi | null>(null);
|
||||
const [selectedDate, setSelectedDate] = useState(new Date());
|
||||
const [selectedMiniDate, setSelectedMiniDate] = useState(new Date());
|
||||
const tokens = useAppSelector((state) => state.user.tokens);
|
||||
const user = useAppSelector((state) => state.user.userData);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
if (!tokens) {
|
||||
@@ -372,6 +377,82 @@ export default function CalendarApp() {
|
||||
center: "prev,today,next",
|
||||
right: "dayGridMonth,timeGridWeek,timeGridDay",
|
||||
}}
|
||||
eventContent={(arg) => {
|
||||
const event = arg.event;
|
||||
if (!calendars[arg.event._def.extendedProps.calId]) return;
|
||||
|
||||
const attendees = event._def.extendedProps.attendee || [];
|
||||
let Icon = null;
|
||||
let titleStyle: React.CSSProperties = {};
|
||||
const ownerEmails = new Set(
|
||||
calendars[arg.event._def.extendedProps.calId].ownerEmails?.map(
|
||||
(email) => email.toLowerCase()
|
||||
)
|
||||
);
|
||||
const showSpecialDisplay = attendees.filter((att: userAttendee) =>
|
||||
ownerEmails.has(att.cal_address.toLowerCase())
|
||||
);
|
||||
if (!showSpecialDisplay[0]) return;
|
||||
switch (showSpecialDisplay[0].partstat) {
|
||||
case "DECLINED":
|
||||
Icon = null;
|
||||
titleStyle.textDecoration = "line-through";
|
||||
break;
|
||||
case "TENTATIVE":
|
||||
Icon = HelpOutlineIcon;
|
||||
break;
|
||||
case "NEEDS-ACTION":
|
||||
Icon = AccessTimeIcon;
|
||||
break;
|
||||
case "ACCEPTED":
|
||||
Icon = null;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{Icon && <Icon fontSize="small" />}
|
||||
<span style={titleStyle}>{event.title}</span>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
eventDidMount={(arg) => {
|
||||
const attendees = arg.event._def.extendedProps.attendee || [];
|
||||
if (!calendars[arg.event._def.extendedProps.calId]) return;
|
||||
const ownerEmails = new Set(
|
||||
calendars[arg.event._def.extendedProps.calId].ownerEmails?.map(
|
||||
(email) => email.toLowerCase()
|
||||
)
|
||||
);
|
||||
const showSpecialDisplay = attendees.filter((att: userAttendee) =>
|
||||
ownerEmails.has(att.cal_address.toLowerCase())
|
||||
);
|
||||
|
||||
if (!showSpecialDisplay[0]) return;
|
||||
|
||||
// Clear previously applied classes
|
||||
arg.el.classList.remove(
|
||||
"declined-event",
|
||||
"tentative-event",
|
||||
"needs-action-event"
|
||||
);
|
||||
|
||||
switch (showSpecialDisplay[0].partstat) {
|
||||
case "DECLINED":
|
||||
arg.el.classList.add("declined-event");
|
||||
break;
|
||||
case "TENTATIVE":
|
||||
arg.el.classList.add("tentative-event");
|
||||
break;
|
||||
case "NEEDS-ACTION":
|
||||
arg.el.classList.add("needs-action-event");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<EventPopover
|
||||
anchorEl={anchorEl}
|
||||
|
||||
@@ -7,11 +7,17 @@ export default function CalendarSelection({
|
||||
selectedCalendars: string[];
|
||||
setSelectedCalendars: Function;
|
||||
}) {
|
||||
const tokens = useAppSelector((state) => state.user.tokens);
|
||||
const userId = useAppSelector((state) => state.user.userData.openpaasId);
|
||||
const dispatch = useAppDispatch();
|
||||
const calendars = useAppSelector((state) => state.calendars.list);
|
||||
|
||||
const personnalCalendars = Object.keys(calendars).filter(
|
||||
(id) => id.split("/")[0] === userId
|
||||
);
|
||||
const delegatedCalendars = Object.keys(calendars).filter(
|
||||
(id) => id.split("/")[0] !== userId && calendars[id].delegated
|
||||
);
|
||||
const sharedCalendars = Object.keys(calendars).filter(
|
||||
(id) => id.split("/")[0] !== userId && !calendars[id].delegated
|
||||
);
|
||||
const handleCalendarToggle = (name: string) => {
|
||||
setSelectedCalendars((prev: string[]) =>
|
||||
prev.includes(name) ? prev.filter((n) => n !== name) : [...prev, name]
|
||||
@@ -20,28 +26,11 @@ export default function CalendarSelection({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>personnalCalendars</h3>
|
||||
{Object.keys(calendars)
|
||||
.filter((id) => id.split("/")[0] === userId)
|
||||
.map((id) => {
|
||||
return (
|
||||
<div key={id}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
style={{ backgroundColor: calendars[id].color }}
|
||||
checked={selectedCalendars.includes(id)}
|
||||
onChange={() => handleCalendarToggle(id)}
|
||||
/>
|
||||
{calendars[id].name}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<h3>sharedCalendars</h3>
|
||||
{Object.keys(calendars)
|
||||
.filter((id) => id.split("/")[0] !== userId)
|
||||
.map((id) => (
|
||||
<span className="calendarListHeader">
|
||||
<h3>Personnal Calendars</h3>
|
||||
</span>
|
||||
{personnalCalendars.map((id) => {
|
||||
return (
|
||||
<div key={id}>
|
||||
<label>
|
||||
<input
|
||||
@@ -53,7 +42,48 @@ export default function CalendarSelection({
|
||||
{calendars[id].name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
{delegatedCalendars.length > 0 && (
|
||||
<>
|
||||
<span className="calendarListHeader">
|
||||
<h3>Delegated Calendars</h3>
|
||||
</span>
|
||||
{delegatedCalendars.map((id) => (
|
||||
<div key={id}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
style={{ backgroundColor: calendars[id].color }}
|
||||
checked={selectedCalendars.includes(id)}
|
||||
onChange={() => handleCalendarToggle(id)}
|
||||
/>
|
||||
{calendars[id].name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{sharedCalendars.length > 0 && (
|
||||
<>
|
||||
<span className="calendarListHeader">
|
||||
<h3>Shared Calendars</h3>
|
||||
</span>
|
||||
{sharedCalendars.map((id) => (
|
||||
<div key={id}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
style={{ backgroundColor: calendars[id].color }}
|
||||
checked={selectedCalendars.includes(id)}
|
||||
onChange={() => handleCalendarToggle(id)}
|
||||
/>
|
||||
{calendars[id].name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user