From 41da958c6258e4017ecb6efcff41c27dfbef3842 Mon Sep 17 00:00:00 2001 From: sunny chen Date: Sat, 11 Oct 2025 22:14:22 +1100 Subject: [PATCH 01/14] fiinish remove friends UI: dialog + confirmation banner --- .../src/components/sidebar/friends/Friend.tsx | 26 ++- .../sidebar/friends/RemoveFriend.tsx | 159 ++++++++++++++++++ 2 files changed, 177 insertions(+), 8 deletions(-) create mode 100644 client/src/components/sidebar/friends/RemoveFriend.tsx diff --git a/client/src/components/sidebar/friends/Friend.tsx b/client/src/components/sidebar/friends/Friend.tsx index 2fbd142da..da55f1f08 100644 --- a/client/src/components/sidebar/friends/Friend.tsx +++ b/client/src/components/sidebar/friends/Friend.tsx @@ -6,6 +6,7 @@ import { useContext, useState } from 'react'; import { useGetUserSettingsQuery } from '../../../api/user/queries'; import { AppContext } from '../../../context/AppContext'; import UserProfile from './UserProfile'; +import RemoveFriend from './RemoveFriend'; const StyledFriendContainer = styled(Box, { shouldForwardProp: (prop) => prop !== 'isDarkMode' && prop !== 'sidebarCollapsed', @@ -28,22 +29,31 @@ interface FriendProps { } const Friend = ({ firstName }: FriendProps) => { - const [kebabOpen, setKebabOpen] = useState(false); const { sidebarCollapsed } = useContext(AppContext); const { isDarkMode } = useGetUserSettingsQuery(); + const [anchorEl, setAnchorEl] = useState(null); + + const handleKebabClick = (event: React.MouseEvent) => { + setAnchorEl(anchorEl ? null : event.currentTarget); + }; + + const handlePopoverClose = () => { + setAnchorEl(null); + }; + + const kebabOpen = Boolean(anchorEl); return ( {!sidebarCollapsed && ( - { - setKebabOpen((prev) => !prev); - }} - > - - + <> + + + + + )} diff --git a/client/src/components/sidebar/friends/RemoveFriend.tsx b/client/src/components/sidebar/friends/RemoveFriend.tsx new file mode 100644 index 000000000..44c7d2383 --- /dev/null +++ b/client/src/components/sidebar/friends/RemoveFriend.tsx @@ -0,0 +1,159 @@ +import { Alert, Button, Dialog, Popover, Snackbar, Typography } from '@mui/material'; +import { margin, minHeight, styled } from '@mui/system'; +import { min } from 'date-fns'; +import { useState } from 'react'; + +export const emptyProfile = 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'; + +const RemoveFriendDialog = styled(Dialog)(({ theme }) => ({ + '& .MuiDialog-paper': { + padding: theme.spacing(1), + borderRadius: theme.shape.borderRadius, + minWidth: '450px', + minHeight: '250px', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }, +})); + +const StyledContainer = styled('div')` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + margin: 25px; + gap: 15px; +`; + +const StyledButtonContainer = styled('div')` + display: flex; + flex-direction: row; + width: 100%; + gap: 20px; + justify-content: center; + align-items: center; +`; + +const CancelRemove = styled(Button)(({ theme }) => ({ + backgroundColor: theme.palette.grey[300], + color: theme.palette.text.primary, + width: '50%', + height: '40px', + textTransform: 'none', + fontWeight: 500, + '&:hover': { + backgroundColor: theme.palette.grey[400], + }, +})); + +const ConfirmRemove = styled(Button)(({ theme }) => ({ + backgroundColor: theme.palette.error.light, + color: theme.palette.error.contrastText, + width: '50%', + height: '40px', + textTransform: 'none', + fontWeight: 500, + '&:hover': { + backgroundColor: theme.palette.error.main, + }, +})); + +const StyledDialogTitle = styled(Typography)` + font-weight: 600; + font-size: 1.2rem; +`; + +const StyledDialogText = styled(Typography)` + font-size: 1.2rem; + color: gray; + text-align: left; +`; + +interface RemoveFriendProps { + anchorEl: HTMLElement | null; + open: boolean; + onClose: () => void; + firstName: string; + profileURL?: string; +} + +const RemoveFriend = ({ anchorEl, open, onClose, firstName, profileURL }: RemoveFriendProps) => { + const [openDialog, setOpenDialog] = useState(false); + const [showBanner, setShowBanner] = useState(false); + + const handleDialogClose = () => { + setOpenDialog(false); + }; + + const handleConfirmRemove = () => { + setOpenDialog(false); + setShowBanner(true); + }; + + const handleBannerClose = (_event?: React.SyntheticEvent | Event, reason?: string) => { + if (reason === 'clickaway') return; + setShowBanner(false); + }; + + return ( + <> + + + Remove {firstName}? + Are you sure you want to remove {firstName} from your friends? + + {/* */} + + Cancel + Confirm + + + + + + + + + + Removed friend from friendlist + + + + ); +}; +export default RemoveFriend; From 8723b8752ff366ee066d405953a09366546365f0 Mon Sep 17 00:00:00 2001 From: sunny chen Date: Wed, 15 Oct 2025 18:31:52 +1100 Subject: [PATCH 02/14] update confirm snackbar to be filled --- client/src/components/sidebar/friends/RemoveFriend.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/sidebar/friends/RemoveFriend.tsx b/client/src/components/sidebar/friends/RemoveFriend.tsx index 44c7d2383..7e488fc02 100644 --- a/client/src/components/sidebar/friends/RemoveFriend.tsx +++ b/client/src/components/sidebar/friends/RemoveFriend.tsx @@ -149,7 +149,7 @@ const RemoveFriend = ({ anchorEl, open, onClose, firstName, profileURL }: Remove onClose={handleBannerClose} anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} > - + Removed friend from friendlist From 8540abcebe2b0af9b21e64dec6600bb82d717475 Mon Sep 17 00:00:00 2001 From: sunny chen Date: Wed, 15 Oct 2025 18:33:06 +1100 Subject: [PATCH 03/14] update confirm snackbar location --- client/src/components/sidebar/friends/RemoveFriend.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/client/src/components/sidebar/friends/RemoveFriend.tsx b/client/src/components/sidebar/friends/RemoveFriend.tsx index 7e488fc02..57e3121cc 100644 --- a/client/src/components/sidebar/friends/RemoveFriend.tsx +++ b/client/src/components/sidebar/friends/RemoveFriend.tsx @@ -143,12 +143,7 @@ const RemoveFriend = ({ anchorEl, open, onClose, firstName, profileURL }: Remove - + Removed friend from friendlist From ef37df0aa306a47e54e36073ea1719749ab34764 Mon Sep 17 00:00:00 2001 From: sunny chen Date: Wed, 15 Oct 2025 18:36:49 +1100 Subject: [PATCH 04/14] change modal size --- client/src/components/sidebar/friends/RemoveFriend.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/sidebar/friends/RemoveFriend.tsx b/client/src/components/sidebar/friends/RemoveFriend.tsx index 57e3121cc..468d408db 100644 --- a/client/src/components/sidebar/friends/RemoveFriend.tsx +++ b/client/src/components/sidebar/friends/RemoveFriend.tsx @@ -9,7 +9,7 @@ const RemoveFriendDialog = styled(Dialog)(({ theme }) => ({ '& .MuiDialog-paper': { padding: theme.spacing(1), borderRadius: theme.shape.borderRadius, - minWidth: '450px', + minWidth: '400px', minHeight: '250px', display: 'flex', justifyContent: 'center', From 7352dee58189290aa8c45b045c076876f6300866 Mon Sep 17 00:00:00 2001 From: sunny chen Date: Wed, 15 Oct 2025 18:39:18 +1100 Subject: [PATCH 05/14] remove redundan imports and comments --- client/src/components/sidebar/friends/RemoveFriend.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/client/src/components/sidebar/friends/RemoveFriend.tsx b/client/src/components/sidebar/friends/RemoveFriend.tsx index 468d408db..bf487d812 100644 --- a/client/src/components/sidebar/friends/RemoveFriend.tsx +++ b/client/src/components/sidebar/friends/RemoveFriend.tsx @@ -1,6 +1,5 @@ import { Alert, Button, Dialog, Popover, Snackbar, Typography } from '@mui/material'; -import { margin, minHeight, styled } from '@mui/system'; -import { min } from 'date-fns'; +import { styled } from '@mui/system'; import { useState } from 'react'; export const emptyProfile = 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'; @@ -103,13 +102,6 @@ const RemoveFriend = ({ anchorEl, open, onClose, firstName, profileURL }: Remove Remove {firstName}? Are you sure you want to remove {firstName} from your friends? - - {/* */} Cancel Confirm From 1fb1b28eab51a7a4a10f526023cf4b993504a1f7 Mon Sep 17 00:00:00 2001 From: Mark Tran <29350857+marktran2@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:01:46 +1000 Subject: [PATCH 06/14] Change friends DTO data format and add extra routing for friend view --- client/src/App.tsx | 54 +++++++++++++++---- .../src/components/sidebar/friends/Friend.tsx | 21 +++++--- .../sidebar/friends/FriendsList.tsx | 12 +++-- .../components/sidebar/friends/friends.json | 45 ++++++++++++---- client/src/index.tsx | 13 +++++ 5 files changed, 114 insertions(+), 31 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index 41b60acfb..7a10ade95 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -4,7 +4,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import * as Sentry from '@sentry/react'; import React, { useContext, useEffect, useMemo } from 'react'; -import { Outlet } from 'react-router'; +import { Outlet, useLocation } from 'react-router'; import getCourseInfo from './api/getCourseInfo'; import getCoursesList from './api/getCoursesList'; @@ -134,6 +134,7 @@ const App: React.FC = () => { setAssignedColors, } = useContext(CourseContext); + const location = useLocation(); const { preferredTheme, isDarkMode, unscheduleClassesByDefault, convertToLocalTimezone } = useGetUserSettingsQuery(); const decodedAssignedColors = useColorsDecoder(assignedColors, preferredTheme); @@ -569,6 +570,46 @@ const App: React.FC = () => { }, }; + const timetableView = useMemo(() => { + const currentPathname = location.pathname; + const searchParams = location.search; + console.log(currentPathname); + if (currentPathname === '/home') { + return ( + <> + + + { + downloadIcsFile(selectedCourses, createdEvents, selectedClasses, firstDayOfTerm) + .then(() => { + /* do nothing */ + }) + .catch(() => { + /* do nothing */ + }); + }} + > + save to calendar + + +