Reputation: 13
I am using the DND calendar of react-big-calendar. The problem I am facing is that on every render it scrolls the view back to top, whenever a state changes or a call is made to an API, it renders the Calendar and the view takes me back to the top
import React, { useState, useEffect, useMemo } from "react";
import { Calendar, momentLocalizer } from "react-big-calendar";
import "react-big-calendar/lib/css/react-big-calendar.css";
import moment from "moment";
import { Box, Text } from "@chakra-ui/react";
import CustomToolbar from "./CustomToolbar";
import withDragAndDrop from "react-big-calendar/lib/addons/dragAndDrop";
import "react-big-calendar/lib/addons/dragAndDrop/styles.css";
import axios from "axios";
import firebase, { auth } from "../../firebase/firebase";
import { useAuthState } from "react-firebase-hooks/auth";
import { Droppable } from "react-beautiful-dnd";
import { fetchEvents, getAccessToken } from "../../helper/CalendarHelpers";
import "moment/locale/en-gb";
import {
ContextMenu,
ContextMenuItem,
ContextMenuList,
ContextMenuTrigger,
} from "@saas-ui/react";
const server = process.env.REACT_APP_BACKEND_URL;
const localizer = momentLocalizer(moment);
const MyCalendar = ({ setEvents, events }) => {
const DnDCalendar = withDragAndDrop(Calendar);
const [user] = useAuthState(auth);
const [date, setDate] = useState(moment());
const [startDay, setStartDay] = useState("Sunday");
const [loading, setLoading] = useState(false);
const [scrollPosition, setScrollPosition] = useState(0);
const [scrolltime, setscrolltime] = useState(new Date(0, 0, 0, 7));
useEffect(() => {
fetchEvents(user, setEvents);
}, []);
const configureStartDay = (startDay) => {
const dayIndex = ["su", "mo", "tu", "we", "th", "fr", "sa"].indexOf(
startDay.slice(0, 2).toLowerCase()
);
if (dayIndex === -1) {
throw new Error("Invalid start day");
}
moment.updateLocale("en", {
week: {
dow: dayIndex,
},
});
return "en";
};
useEffect(() => {
firebase
.firestore()
.collection("calendar")
.doc(user.uid)
.get()
.then((snap) => {
if (snap.exists) {
if (snap?.data()?.startingDay) {
setStartDay(snap?.data()?.startingDay);
}
}
})
.catch((error) => {
console.log("Error in Calendar.js===>", error);
});
}, [user.uid]);
const memoizedEvents = useMemo(() => {
const CustomHeader = ({ date }) => {
const formattedDate = moment(date).format("ddd DD");
return (
<Box
style={{
userSelect: "none",
display: "flex",
flex: "1",
flexDirection: "column",
}}
>
<Text
style={{
fontSize: "1rem",
fontWeight: "normal",
color: "#777272",
}}
>
{formattedDate.split(" ")[0]}
</Text>
<Text
style={{
fontSize: "1rem",
fontWeight: "bold",
}}
>
{formattedDate.split(" ")[1]}
</Text>
</Box>
);
};
return CustomHeader;
}, []);
const handleDateSelect = (date) => {
setDate(moment(date.toDate()));
};
const handleNavigate = (navigate, view) => {
if (navigate === "prev") {
setDate(date.clone().subtract(1, view));
} else if (navigate === "next") {
setDate(date.clone().add(1, view));
}
};
const updateEvent = async (data) => {
const { start, end, event, isAllDay } = data;
if (isAllDay) {
if (start.getDate() === end.getDate()) {
start.setHours(0, 0, 0, 0);
end.setDate(start.getDate() + 1);
end.setHours(0, 0, 0, 0);
}
}
const updatedEvent = { ...event, start, end };
let neweve = events.filter((x) => x.id !== updatedEvent.id);
setEvents([...neweve, updatedEvent]);
setscrolltime(start);
try {
const userId = user.uid;
const calendarId = event.calendarId;
let accessToken;
let type;
const calendarDoc = await firebase
.firestore()
.collection("calendar")
.doc(userId)
.get();
if (calendarId) {
type = "refresh";
accessToken = getAccessToken(
calendarId,
calendarDoc.data().AllCalendar
);
}
await axios.put(`${server}/google/calendar/update-event/${event.id}`, {
calendarId: calendarId,
updatedEvent: updatedEvent,
accessToken: accessToken,
type: type,
});
} catch (error) {
console.error("Error updating event:", error);
}
};
const handleDelete = async (event) => {
try {
const userId = user.uid;
const calendarId = event.calendarId;
let accessToken;
console.log("CALENDAR ID===>", calendarId);
let type;
const calendarDoc = await firebase
.firestore()
.collection("calendar")
.doc(userId)
.get();
if (calendarId) {
type = "refresh";
accessToken = getAccessToken(
calendarId,
calendarDoc.data().AllCalendar
);
}
const filteredEvents = events.filter((e) => e.id !== event.id);
setEvents(filteredEvents);
await axios.delete(`${server}/google/calendar/delete-event/${event.id}`, {
data: {
calendarId: calendarId,
accessToken: accessToken,
},
});
} catch (error) {
console.log("Error in Delete", error);
}
};
const onEventDrop = async (data) => {
await updateEvent(data);
};
const onEventResize = async (data) => {
await updateEvent(data);
};
const eventStyleGetter = () => {
const style = {
backgroundColor: "#EAF6FF",
color: "#1C67D2",
};
return { style };
};
const customTimeFormat = (date) => moment(date).format("h A");
const customEvents = ({ event, children }) => {
return (
<ContextMenu>
<ContextMenuTrigger longPressDisabled={true}>
<div>{children}</div>
</ContextMenuTrigger>
<ContextMenuList pos={"relative"} bg={"#33373d"} minW={0} pt={0} pb={0}>
<ContextMenuItem
style={{
backgroundColor: "#33373d",
color: "white",
fontSize: 14,
}}
borderRadius={"0.375rem"}
onClick={() => {
handleDelete(event);
}}
>
Delete
</ContextMenuItem>
</ContextMenuList>
</ContextMenu>
);
};
const CustomTimeSlot = ({ children, value }) => {
return (
<Droppable droppableId={"Calendar-" + value}>
{(provided) => (
<Box
ref={provided.innerRef}
{...provided.droppableProps}
style={{ display: "flex", alignItems: "center" }}
>
{children}
{provided.placeholder}
</Box>
)}
</Droppable>
);
};
const CustomWeek = (props) => {
return <Box bg={"red"}>{console.log(props)}</Box>;
};
return (
<Box mx={6} style={{ height: "94vh", width: "100vw" }}>
<style>
{`
.rbc-addons-dnd-row-body .rbc-row:nth-of-type(2) {
display: none !important;
}
.rbc-event-allday {
border: 2px solid #756ece !important;
background-color : #dfe1f6 !important;
}
.rbc-event {
border: 2px solid #756ece !important;
background-color : #dfe1f6 !important;
}
.rbc-label{
font-size: 12px !important;
color:#777272;
}
.rbc-time-header-content{
margin-left:45px;
}
.rbc-label rbc-time-header-gutter {
display: none !important;
}
div.rbc-header.rbc-today p.chakra-text.css-0{
color: #3761EE !important;
}
div.rbc-header.rbc-today {
border-bottom: 2px solid #3761EE;
}
div.rbc-header.rbc-today {
background-color: white;
}
.rbc-day-slot .rbc-event-content {
display: flex !important;
justify-content: center !important;
align-items: center !important;
text-align: center !important;
font-weight: 550 !important;
color: #756ece !important;}
.rbc-day-slot .rbc-event{
text-align:center;
font-weight:550;
border: 2px solid #756ece !important;
background-color : #dfe1f6 !important;
}
.rbc-day-slot .rbc-events-container {
margin-right:0px !important;
}
div.rbc-day-slot.rbc-time-column.rbc-now.rbc-today{
background-color:white;
}
.rbc-day-slot .rbc-event-label {
display:none;
}
.rbc-timeslot-group {
min-height:70px;
}
.rbc-header + .rbc-header {
border-left: 1px solid #ddd;
border-top: 1px solid #FFFFFF;
border-bottom: 0px;
}
.rbc-time-view{
border:none;
width: auto;
}
.rbc-time-content{
border-top:1px solid #ddd
overflow-y:scroll;
}
.rbc-time-content::-webkit-scrollbar {
display: none;
}
div.rbc-time-header.rbc-overflowing {
margin-right: -2px !important;
}
.rbc-header{
border-bottom:0;
text-align: start;
padding-left: 20px;
}
.rbc-current-time-indicator {
background-color: #3761EE !important;
}
.rbc-time-gutter .rbc-timeslot-group {
display: block !important;
width: 50px !important;
}
.rbc-time-header{
display:block !important
}
`}
</style>
<DnDCalendar
key={"12345"}
allDayAccessor="isAllDay"
showAllEvents={true}
showMultiDayTimes={true}
localizer={localizer}
events={events}
startAccessor="start"
endAccessor="end"
defaultView="week"
onEventDrop={onEventDrop}
onEventResize={onEventResize}
resizable
style={{
height: "100%",
width: "100%",
}}
components={{
toolbar: (props) => (
<CustomToolbar
{...props}
onNavigate={handleNavigate}
date={date}
onDateChange={handleDateSelect}
/>
),
header: memoizedEvents,
eventWrapper: customEvents,
timeSlotWrapper: CustomTimeSlot,
week: CustomWeek,
}}
date={date.toDate()}
eventPropGetter={eventStyleGetter}
formats={{
timeGutterFormat: (date) => customTimeFormat(date),
}}
culture={configureStartDay(startDay)}
/>
</Box>
);
};
export default MyCalendar;
I have tried the enableAutoScroll prop as well but to no luck, I have also tried numerous things but couldn't understand the problem behind it. I would really appreciate the help.
Thanks a lot.
Upvotes: 1
Views: 438
Reputation: 1
Just declare const DnDCalendar = withDragAndDrop(Calendar)
outside the MyCalendar component
and your problem will be solved
Upvotes: 0
Reputation: 321
Try this way:
const [shouldScroll, setShouldScroll] = useState(false);
// ... other code
useEffect(() => {
setShouldScroll(true); // Set flag on initial load (optional)
fetchEvents(user, setEvents);
}, [user]);
// ... other code
return (
<BigCalendar
// ... other props
scrollToTime={shouldScroll ? scrolltime : null} // Pass scrollTime only when flag is true
// ... other props
/>
);
Upvotes: 0