From 9b5d8002a0281f9b8a85cc31a6509c0489edac12 Mon Sep 17 00:00:00 2001 From: Taehee Choi Date: Tue, 15 Mar 2022 15:41:41 -0700 Subject: [PATCH] redux updates --- src/api-bodies/MockData.tsx | 10 ++- src/api-bodies/User.tsx | 10 +++ src/api-bodies/UserStatus.tsx | 7 ++ src/components/contacts/Utils.tsx | 18 ++++- .../contacts/contacts-components/Body.tsx | 1 + .../contacts/contacts-components/Sidebar.tsx | 21 +++-- .../body-components/LowerBody.tsx | 6 +- .../body-components/UpperBody.tsx | 50 ++++++++++-- .../sidebar-components/ContactItem.tsx | 12 ++- .../meeting-details/MeetingDetails.tsx | 4 +- src/components/meeting-details/Utils.tsx | 30 +++++++ .../meeting-details-components/Body.tsx | 36 +++++---- src/index.tsx | 10 +-- src/redux/slices/favoritesSlice.tsx | 3 +- .../slices/meetingsAndUserStatusSlice.tsx | 78 +++++++++++++++++++ src/redux/slices/meetingsSlice.tsx | 41 ---------- src/redux/slices/peopleSlice.tsx | 40 ---------- src/redux/slices/teamSlice.tsx | 41 ---------- src/redux/slices/usersSlice.tsx | 66 ++++++++++++++++ src/redux/store.tsx | 10 +-- src/styles.css | 5 ++ 21 files changed, 316 insertions(+), 183 deletions(-) create mode 100644 src/api-bodies/User.tsx create mode 100644 src/api-bodies/UserStatus.tsx create mode 100644 src/components/meeting-details/Utils.tsx create mode 100644 src/redux/slices/meetingsAndUserStatusSlice.tsx delete mode 100644 src/redux/slices/meetingsSlice.tsx delete mode 100644 src/redux/slices/peopleSlice.tsx delete mode 100644 src/redux/slices/teamSlice.tsx create mode 100644 src/redux/slices/usersSlice.tsx diff --git a/src/api-bodies/MockData.tsx b/src/api-bodies/MockData.tsx index 5b1ab73..e85a51e 100644 --- a/src/api-bodies/MockData.tsx +++ b/src/api-bodies/MockData.tsx @@ -1,4 +1,4 @@ -const people = [ +const userLites = [ { uuid: "0", emailAddress: "cth0604@gmail.com", @@ -58,7 +58,7 @@ const meetings = [ meetingId: "1", liveParticipantIds: [], registrantIds: ["0", "2", "4"], - start: "2022-03-13T17:30:00", + start: "2022-03-16T17:30:00", duration: 30, timezone: "", joinUrl: "", @@ -66,7 +66,7 @@ const meetings = [ }, { meetingId: "2", - liveParticipantIds: [], + liveParticipantIds: ["3", "5"], registrantIds: ["3", "5", "6"], start: "2022-03-13T17:30:00", duration: 30, @@ -83,4 +83,6 @@ const team = { directReports: [], }; -export { people, meetings, team }; +const favorites = ["2", "4"]; + +export { userLites, meetings, team, favorites }; diff --git a/src/api-bodies/User.tsx b/src/api-bodies/User.tsx new file mode 100644 index 0000000..1032cb6 --- /dev/null +++ b/src/api-bodies/User.tsx @@ -0,0 +1,10 @@ +interface User { + uuid: string; + emailAddress: string; + name: string; + role: string; + inMeeting: boolean; + meetingID: string | null; +} + +export default User; diff --git a/src/api-bodies/UserStatus.tsx b/src/api-bodies/UserStatus.tsx new file mode 100644 index 0000000..ddb4d18 --- /dev/null +++ b/src/api-bodies/UserStatus.tsx @@ -0,0 +1,7 @@ +interface UserStatus { + uuid: string; + inMeeting: boolean; + meetingID: string | null; +} + +export default UserStatus; diff --git a/src/components/contacts/Utils.tsx b/src/components/contacts/Utils.tsx index bedc302..203f320 100644 --- a/src/components/contacts/Utils.tsx +++ b/src/components/contacts/Utils.tsx @@ -16,10 +16,22 @@ const returnStatusColor = ( } }; -const getMeetingDuration = (meeting: DetailedMeeting) => { +const getUpcomingMeetingTime = (meeting: DetailedMeeting) => { const startDate = new Date(meeting.start); const endDate = new Date(startDate.getTime() + meeting.duration * 60000); - return `${startDate.toTimeString()} - ${endDate.toTimeString()}`; + const startTime = startDate + .toTimeString() + .split(" ")[0] + .split(":") + .slice(0, 2) + .join(":"); + const endTime = endDate + .toTimeString() + .split(" ")[0] + .split(":") + .slice(0, 2) + .join(":"); + return `${startTime} - ${endTime}`; }; -export { returnStatusColor, getMeetingDuration }; +export { returnStatusColor, getUpcomingMeetingTime }; diff --git a/src/components/contacts/contacts-components/Body.tsx b/src/components/contacts/contacts-components/Body.tsx index bb9f5ce..b477500 100644 --- a/src/components/contacts/contacts-components/Body.tsx +++ b/src/components/contacts/contacts-components/Body.tsx @@ -16,6 +16,7 @@ const Body: React.FC = (props) => { flexDirection: "column", width: "100%", height: "100%", + mt: 2, }} > diff --git a/src/components/contacts/contacts-components/Sidebar.tsx b/src/components/contacts/contacts-components/Sidebar.tsx index eecf63c..3358e18 100644 --- a/src/components/contacts/contacts-components/Sidebar.tsx +++ b/src/components/contacts/contacts-components/Sidebar.tsx @@ -11,10 +11,7 @@ import React from "react"; import { ExpandLess, ExpandMore } from "@mui/icons-material"; import ContactItem from "./sidebar-components/ContactItem"; import { useAppSelector } from "../../../redux/hooks"; -import { - selectFavoritesJSON, - selectTeamJSON, -} from "../../../redux/slices/peopleSlice"; +import { selectUsers, selectTeam } from "../../../redux/slices/usersSlice"; import { selectFavorites } from "../../../redux/slices/favoritesSlice"; import UserLite from "../../../api-bodies/UserLite"; @@ -28,11 +25,11 @@ const Sidebar: React.FC = (props) => { const [favoritesOpen, setFavoritesOpen] = React.useState(true); const [teamOpen, setTeamOpen] = React.useState(false); - const favorites = useAppSelector(selectFavorites); - const favoritesJSON = useAppSelector((state) => - selectFavoritesJSON(state, favorites) + const favoritesUuids = useAppSelector(selectFavorites); + const favorites = useAppSelector((state) => + selectUsers(state, favoritesUuids) ); - const teamJSON = useAppSelector(selectTeamJSON); + const team = useAppSelector(selectTeam); return ( = (props) => { {favoritesOpen ? : } - {favoritesJSON.map((favorite, i) => ( + {favorites.map((favorite, i) => ( = (props) => { setTeamOpen(!teamOpen)}> {teamOpen ? : } - + - {teamJSON.map((member, i) => ( + {team.map((member, i) => ( = (props) => { {meeting.topic} - {getMeetingDuration(meeting)} + {getUpcomingMeetingTime(meeting)} ))} diff --git a/src/components/contacts/contacts-components/body-components/UpperBody.tsx b/src/components/contacts/contacts-components/body-components/UpperBody.tsx index 39ad22f..d34ca7f 100644 --- a/src/components/contacts/contacts-components/body-components/UpperBody.tsx +++ b/src/components/contacts/contacts-components/body-components/UpperBody.tsx @@ -6,12 +6,34 @@ import GroupsIcon from "@mui/icons-material/Groups"; import AddIcon from "@mui/icons-material/Add"; import Status from "../../Status"; import UserLite from "../../../../api-bodies/UserLite"; +import UserStatus from "../../../../api-bodies/UserStatus"; +import { useAppSelector, useAppDispatch } from "../../../../redux/hooks"; +import { + selectUserStatus, + selectMeeting, +} from "../../../../redux/slices/meetingsAndUserStatusSlice"; +import { + selectFavorites, + addFavorite, + removeFavorite, +} from "../../../../redux/slices/favoritesSlice"; +import RemoveIcon from "@mui/icons-material/Remove"; interface Props { contactInfo: UserLite; } const UpperBody: React.FC = (props) => { + const dispatch = useAppDispatch(); + const userStatus: UserStatus | null = useAppSelector((state) => + selectUserStatus(state, props.contactInfo.uuid) + ); + const favoritesUuids = useAppSelector(selectFavorites); + const detailedMeeting = useAppSelector((state) => + selectMeeting(state, userStatus.meetingID) + ); + const status: Status = + userStatus && userStatus.inMeeting ? Status.Online : Status.Offline; return ( = (props) => { }} > {props.contactInfo.name} - + {!favoritesUuids.includes(props.contactInfo.uuid) ? ( + + ) : ( + + )} = (props) => { - {Status.Online} - MeetingName-1372 + {status} + {detailedMeeting ? ( + {detailedMeeting.topic} + ) : null} diff --git a/src/components/contacts/contacts-components/sidebar-components/ContactItem.tsx b/src/components/contacts/contacts-components/sidebar-components/ContactItem.tsx index 2b78288..9204fd0 100644 --- a/src/components/contacts/contacts-components/sidebar-components/ContactItem.tsx +++ b/src/components/contacts/contacts-components/sidebar-components/ContactItem.tsx @@ -5,6 +5,9 @@ import CircleIcon from "@mui/icons-material/Circle"; import { returnStatusColor } from "../../Utils"; import UserLite from "../../../../api-bodies/UserLite"; import Status from "../../Status"; +import { useAppSelector } from "../../../../redux/hooks"; +import { selectUserStatus } from "../../../../redux/slices/meetingsAndUserStatusSlice"; +import UserStatus from "../../../../api-bodies/UserStatus"; interface Props { contactInfo: UserLite; @@ -12,6 +15,11 @@ interface Props { } const ContactItem: React.FC = (props) => { + const userStatus: UserStatus | null = useAppSelector((state) => + selectUserStatus(state, props.contactInfo.uuid) + ); + const status: Status = + userStatus && userStatus.inMeeting ? Status.Online : Status.Offline; return ( { @@ -23,10 +31,10 @@ const ContactItem: React.FC = (props) => { - + ); }; diff --git a/src/components/meeting-details/MeetingDetails.tsx b/src/components/meeting-details/MeetingDetails.tsx index 0703c24..fdf65a4 100644 --- a/src/components/meeting-details/MeetingDetails.tsx +++ b/src/components/meeting-details/MeetingDetails.tsx @@ -12,7 +12,7 @@ const MeetingDetails: React.FC = () => { const meetingDetailsOpen = useAppSelector(selectMeetingDetailsOpen); const dispatch = useAppDispatch(); - return ( + return meetingDetailsOpen.meeting ? ( {
- ); + ) : null; }; export default MeetingDetails; diff --git a/src/components/meeting-details/Utils.tsx b/src/components/meeting-details/Utils.tsx new file mode 100644 index 0000000..4af92a2 --- /dev/null +++ b/src/components/meeting-details/Utils.tsx @@ -0,0 +1,30 @@ +import DetailedMeeting from "../../api-bodies/DetailedMeeting"; + +const getMeetingStatus = (meeting: DetailedMeeting) => { + const startDate = new Date(meeting.start); + const endDate = new Date(startDate.getTime() + meeting.duration * 60000); + const currentDate = new Date(); + if (currentDate > startDate && currentDate < endDate) return "Live"; + else if (currentDate < startDate) return "Scheduled"; + else return "Finished"; +}; + +const getUpcomingMeetingTime = (meeting: DetailedMeeting) => { + const startDate = new Date(meeting.start); + const endDate = new Date(startDate.getTime() + meeting.duration * 60000); + const startTime = startDate + .toTimeString() + .split(" ")[0] + .split(":") + .slice(0, 2) + .join(":"); + const endTime = endDate + .toTimeString() + .split(" ")[0] + .split(":") + .slice(0, 2) + .join(":"); + return `${startTime} - ${endTime}`; +}; + +export { getMeetingStatus, getUpcomingMeetingTime }; diff --git a/src/components/meeting-details/meeting-details-components/Body.tsx b/src/components/meeting-details/meeting-details-components/Body.tsx index e253b82..3eb9062 100644 --- a/src/components/meeting-details/meeting-details-components/Body.tsx +++ b/src/components/meeting-details/meeting-details-components/Body.tsx @@ -9,12 +9,20 @@ import { import React from "react"; import PersonOutlineIcon from "@mui/icons-material/PersonOutline"; import DetailedMeeting from "../../../api-bodies/DetailedMeeting"; +import { useAppSelector } from "../../../redux/hooks"; +import { selectUsers } from "../../../redux/slices/usersSlice"; +import { getMeetingStatus } from "../Utils"; +import UserLite from "../../../api-bodies/UserLite"; interface Props { - meeting: DetailedMeeting | null; + meeting: DetailedMeeting; } -const Body: React.FC = () => { +const Body: React.FC = (props) => { + const registrants: UserLite[] = useAppSelector((state) => + selectUsers(state, props.meeting.registrantIds) + ); + return ( = () => { }} > Feb 10, 2022 10:45 am - 11:00 am - Status: Live + Status: {getMeetingStatus(props.meeting)} Topic: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard @@ -56,20 +64,14 @@ const Body: React.FC = () => { - - - - - - -
- - - - - - - + {registrants.map((registrant, i) => ( + + + + + + + ))} diff --git a/src/index.tsx b/src/index.tsx index cb69700..be6fea4 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -5,14 +5,12 @@ import { AuthProvider } from "./context/AuthProvider"; import { Provider } from "react-redux"; import { store } from "./redux/store"; import { fetchFavorites } from "./redux/slices/favoritesSlice"; -import { fetchTeam } from "./redux/slices/teamSlice"; -import { fetchMeetings } from "./redux/slices/meetingsSlice"; -import { fetchPeople } from "./redux/slices/peopleSlice"; +import { fetchMeetings } from "./redux/slices/meetingsAndUserStatusSlice"; +import { fetchUsers } from "./redux/slices/usersSlice"; -store.dispatch(fetchPeople("")); -store.dispatch(fetchFavorites("")); -store.dispatch(fetchTeam("")); store.dispatch(fetchMeetings("")); +store.dispatch(fetchUsers("")); +store.dispatch(fetchFavorites("")); const Index: React.FC = () => { return ( diff --git a/src/redux/slices/favoritesSlice.tsx b/src/redux/slices/favoritesSlice.tsx index 5ac5d36..9d16211 100644 --- a/src/redux/slices/favoritesSlice.tsx +++ b/src/redux/slices/favoritesSlice.tsx @@ -1,5 +1,6 @@ import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { RootState } from "../store"; +import { favorites } from "../../api-bodies/MockData"; interface FavoritesState { favorites: string[]; @@ -34,7 +35,7 @@ export const fetchFavorites = createAsyncThunk( // const response = await client.post("/fakeApi/posts", initialPost); // !!! console.log(uuid); - return ["2", "4"]; + return favorites; } ); export const addFavorite = createAsyncThunk( diff --git a/src/redux/slices/meetingsAndUserStatusSlice.tsx b/src/redux/slices/meetingsAndUserStatusSlice.tsx new file mode 100644 index 0000000..c2aa309 --- /dev/null +++ b/src/redux/slices/meetingsAndUserStatusSlice.tsx @@ -0,0 +1,78 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import DetailedMeeting from "../../api-bodies/DetailedMeeting"; +import { RootState } from "../store"; +import { meetings } from "../../api-bodies/MockData"; +import UserStatus from "../../api-bodies/UserStatus"; + +interface MeetingsAndUserStatusState { + meetings: DetailedMeeting[]; + userStatuses: Record; +} + +const initialState: MeetingsAndUserStatusState = { + meetings: [], + userStatuses: {}, +}; + +export const meetingsAndUserStatusSlice = createSlice({ + name: "meetingsAndUserStatus", + initialState, + reducers: {}, + extraReducers(builder) { + builder.addCase(fetchMeetings.fulfilled, (state, action) => { + state.meetings = action.payload.meetings; + state.userStatuses = action.payload.userStatuses; + }); + }, +}); + +export const fetchMeetings = createAsyncThunk( + "meetingsAndUserStatus/fetchMeetings", + async (uuid: string) => { + // const response = await client.post("/fakeApi/posts", initialPost); + // !!! + console.log(uuid); + const userStatuses: Record = {}; + meetings.forEach((meeting) => { + meeting.liveParticipantIds.forEach((uuid) => { + userStatuses[uuid] = { + uuid: uuid, + inMeeting: true, + meetingID: meeting.meetingId, + }; + }); + }); + return { userStatuses: userStatuses, meetings: meetings }; + } +); + +export const selectMeetings = (state: RootState) => + state.meetingsAndUserStatuses.meetings; +export const selectMeeting = (state: RootState, meetingID: string | null) => { + return meetingID !== null + ? state.meetingsAndUserStatuses.meetings.find( + (meeting) => meeting.meetingId === meetingID + ) + : null; +}; +export const selectUserUpcomingMeetings = (state: RootState, uuid: string) => { + return state.meetingsAndUserStatuses.meetings.filter((meeting) => + meeting.registrantIds.includes(uuid) + ); +}; +export const selectUserStatus = ( + state: RootState, + uuid: string +): UserStatus => { + const userStatus = state.meetingsAndUserStatuses.userStatuses[uuid]; + if (userStatus) { + return userStatus; + } else { + return { + uuid: uuid, + inMeeting: false, + meetingID: null, + }; + } +}; +export default meetingsAndUserStatusSlice.reducer; diff --git a/src/redux/slices/meetingsSlice.tsx b/src/redux/slices/meetingsSlice.tsx deleted file mode 100644 index 272e764..0000000 --- a/src/redux/slices/meetingsSlice.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; -import DetailedMeeting from "../../api-bodies/DetailedMeeting"; -import { RootState } from "../store"; -import { meetings } from "../../api-bodies/MockData"; - -interface MeetingsState { - meetings: DetailedMeeting[]; -} - -const initialState: MeetingsState = { - meetings: [], -}; - -export const meetingsSlice = createSlice({ - name: "meetings", - initialState, - reducers: {}, - extraReducers(builder) { - builder.addCase(fetchMeetings.fulfilled, (state, action) => { - return action.payload; - }); - }, -}); - -export const fetchMeetings = createAsyncThunk( - "meetings/fetchMeetings", - async (uuid: string) => { - // const response = await client.post("/fakeApi/posts", initialPost); - // !!! - console.log(uuid); - return { meetings: meetings }; - } -); - -export const selectMeetings = (state: RootState) => state.meetings.meetings; -export const selectUserUpcomingMeetings = (state: RootState, uuid: string) => { - return state.meetings.meetings.filter((meeting) => - meeting.registrantIds.includes(uuid) - ); -}; -export default meetingsSlice.reducer; diff --git a/src/redux/slices/peopleSlice.tsx b/src/redux/slices/peopleSlice.tsx deleted file mode 100644 index ef76f52..0000000 --- a/src/redux/slices/peopleSlice.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; -import UserLite from "../../api-bodies/UserLite"; -import { RootState } from "../store"; -import { people } from "../../api-bodies/MockData"; - -interface PeopleState { - people: UserLite[]; -} - -const initialState: PeopleState = { - people: [], -}; - -export const peopleSlice = createSlice({ - name: "people", - initialState, - reducers: {}, - extraReducers(builder) { - builder.addCase(fetchPeople.fulfilled, (state, action) => { - console.log(action.payload); - state.people = action.payload; - }); - }, -}); - -export const fetchPeople = createAsyncThunk( - "people/fetchPeople", - async (uuid: string) => { - // const response = await client.post("/fakeApi/posts", initialPost); - // !!! - console.log(uuid); - return people; - } -); - -export const selectFavoritesJSON = (state: RootState, favorites: string[]) => { - return state.people.people.filter((p) => favorites.includes(p.uuid)); -}; -export const selectTeamJSON = (state: RootState) => state.people.people; -export default peopleSlice.reducer; diff --git a/src/redux/slices/teamSlice.tsx b/src/redux/slices/teamSlice.tsx deleted file mode 100644 index c6e7fe2..0000000 --- a/src/redux/slices/teamSlice.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; -import { RootState } from "../store"; -import { team } from "../../api-bodies/MockData"; - -interface TeamState { - user: string | null; - manager: string | null; - sameManager: string[]; - directReports: string[]; -} - -const initialState: TeamState = { - user: null, - manager: null, - sameManager: [], - directReports: [], -}; - -export const teamSlice = createSlice({ - name: "team", - initialState, - reducers: {}, - extraReducers(builder) { - builder.addCase(fetchTeam.fulfilled, (state, action) => { - return action.payload; - }); - }, -}); - -export const fetchTeam = createAsyncThunk( - "team/fetchTeam", - async (uuid: string) => { - // const response = await client.post("/fakeApi/posts", initialPost); - // !!! - console.log(uuid); - return team; - } -); - -export const selectTeam = (state: RootState) => state.team; -export default teamSlice.reducer; diff --git a/src/redux/slices/usersSlice.tsx b/src/redux/slices/usersSlice.tsx new file mode 100644 index 0000000..f07db6e --- /dev/null +++ b/src/redux/slices/usersSlice.tsx @@ -0,0 +1,66 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "../store"; +import { userLites, team } from "../../api-bodies/MockData"; +import UserLite from "../../api-bodies/UserLite"; + +interface TeamState { + user: string | null; + manager: string | null; + sameManager: string[]; + directReports: string[]; +} + +interface UsersState { + users: Record; + team: TeamState; +} + +const initialState: UsersState = { + users: {}, + team: { user: null, manager: null, sameManager: [], directReports: [] }, +}; + +export const usersSlice = createSlice({ + name: "users", + initialState, + reducers: {}, + extraReducers(builder) { + builder.addCase(fetchUsers.fulfilled, (state, action) => { + state.users = action.payload.users; + state.team = action.payload.team; + }); + }, +}); + +export const fetchUsers = createAsyncThunk( + "users/fetchUsers", + async (uuid: string) => { + // fetch userfull + // fetch managerfull + // now you have yourself, co-workers, manager, and direct reports (your team basically!) + // call setTeam reducer in teamSlice + console.log(uuid); + const users: Record = {}; + userLites.forEach((userLite) => { + users[userLite.uuid] = userLite; + }); + return { users: users, team: team }; + } +); + +export const selectUsers = (state: RootState, uuids: string[]): UserLite[] => { + const users: UserLite[] = []; + uuids.forEach((uuid) => users.push(state.users.users[uuid])); + return users; +}; +export const selectTeam = (state: RootState) => { + const team: UserLite[] = []; + if (state.users.team.manager !== null) + team.push(state.users.users[state.users.team.manager]); + state.users.team.sameManager.forEach((u) => team.push(state.users.users[u])); + state.users.team.directReports.forEach((u) => + team.push(state.users.users[u]) + ); + return team; +}; +export default usersSlice.reducer; diff --git a/src/redux/store.tsx b/src/redux/store.tsx index 23d0ab2..0d829d6 100644 --- a/src/redux/store.tsx +++ b/src/redux/store.tsx @@ -1,17 +1,15 @@ import { configureStore } from "@reduxjs/toolkit"; import meetingDetailsOpenReducer from "./slices/meetingDetailsOpenSlice"; import favoritesReducer from "./slices/favoritesSlice"; -import teamReducer from "./slices/teamSlice"; -import meetingsReducer from "./slices/meetingsSlice"; -import peopleReducer from "./slices/peopleSlice"; +import meetingsAndUserStatusReducer from "./slices/meetingsAndUserStatusSlice"; +import usersReducer from "./slices/usersSlice"; export const store = configureStore({ reducer: { meetingDetailsOpen: meetingDetailsOpenReducer, favorites: favoritesReducer, - team: teamReducer, - meetings: meetingsReducer, - people: peopleReducer, + meetingsAndUserStatuses: meetingsAndUserStatusReducer, + users: usersReducer, }, }); diff --git a/src/styles.css b/src/styles.css index 915ef09..3fc5a1e 100644 --- a/src/styles.css +++ b/src/styles.css @@ -5,3 +5,8 @@ body, #app > div { height: 100%; } + +html, +body { + overflow: hidden; +}