-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(ProfilePage): Refactor ProfilePage
1. Hide avatar on right top on profile page. 2. Redesign user's profile page. 3. Add sign out dialog to double confirm when user are trying to sign out.
- Loading branch information
Showing
3 changed files
with
205 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,173 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import React, { useState } from 'react'; | ||
|
||
import { CircularProgress } from '@mui/material'; | ||
import { Email, Phone, School, CalendarToday, ListAlt } from '@mui/icons-material'; | ||
import { | ||
Avatar, | ||
Typography, | ||
Divider, | ||
Box, | ||
Button, | ||
Card, | ||
CardContent, | ||
CircularProgress, | ||
useTheme, | ||
} from '@mui/material'; | ||
import { useParams, useNavigate } from 'react-router-dom'; | ||
|
||
import ProfileCard from './ProfileCard'; | ||
import { handleSignOut } from '../utils/firebase'; | ||
import { getUserProfile } from '../utils/firestore'; | ||
import SignOutDialog from './SignOutDialog'; | ||
import useUserProfile from '../hooks/useUserProfile'; | ||
|
||
export default function ProfilePage() { | ||
const { id } = useParams(); | ||
const [profileData, setProfileData] = useState(null); | ||
const [loading, setLoading] = useState(true); | ||
|
||
const navigate = useNavigate(); | ||
const { userProfile: profileData, loading } = useUserProfile({ uid: id }); | ||
const [signOutDialogOpen, setSignOutDialogOpen] = useState(false); | ||
|
||
useEffect(() => { | ||
const fetchProfile = async () => { | ||
const data = await getUserProfile(id); | ||
if (data) { | ||
setProfileData(data); | ||
} else { | ||
handleSignOut(); | ||
} | ||
setLoading(false); | ||
}; | ||
|
||
fetchProfile(); | ||
}, [id]); | ||
const theme = useTheme(); | ||
|
||
const handleEditClick = () => { | ||
navigate('/edit-profile'); | ||
}; | ||
|
||
const handleSignOutDialogOpen = () => { | ||
setSignOutDialogOpen(true); | ||
}; | ||
|
||
if (loading) { | ||
return <CircularProgress />; | ||
} | ||
|
||
return ( | ||
<div> | ||
<ProfileCard | ||
profileData={profileData} | ||
onEditClick={handleEditClick} | ||
onSignOutClick={() => handleSignOut(navigate)} | ||
/> | ||
</div> | ||
<Box sx={{ maxWidth: 700, margin: 'auto', padding: 3 }}> | ||
{/* Profile Header with Avatar and Name */} | ||
<Box sx={{ display: 'flex', alignItems: 'center', flexDirection: 'column', mb: 4 }}> | ||
<Avatar | ||
sx={{ width: 100, height: 100, bgcolor: theme.palette.primary, mb: 2 }} | ||
src={profileData?.profilePic || ''} | ||
alt={profileData?.name} | ||
> | ||
{profileData?.name?.[0]} | ||
</Avatar> | ||
<Typography variant="h4" sx={{ fontWeight: 'bold' }}> | ||
{profileData?.name} | ||
</Typography> | ||
</Box> | ||
|
||
{/* Contact Info Section */} | ||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold', mb: 1 }}> | ||
Contact Info | ||
</Typography> | ||
|
||
<Card variant="outlined" sx={{ mb: 3, borderRadius: 2 }}> | ||
<CardContent> | ||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}> | ||
<Box sx={{ display: 'flex', alignItems: 'center' }}> | ||
<Email sx={{ mr: 1, color: 'grey.600' }} /> | ||
<Typography variant="body2" color="textSecondary"> | ||
</Typography> | ||
</Box> | ||
<Typography variant="body2">{profileData?.email}</Typography> | ||
</Box> | ||
|
||
<Divider sx={{ my: 1 }} /> | ||
|
||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}> | ||
<Box sx={{ display: 'flex', alignItems: 'center' }}> | ||
<Phone sx={{ mr: 1, color: 'grey.600' }} /> | ||
<Typography variant="body2" color="textSecondary"> | ||
Phone | ||
</Typography> | ||
</Box> | ||
<Typography variant="body2">{profileData?.phoneNumber}</Typography> | ||
</Box> | ||
</CardContent> | ||
</Card> | ||
|
||
{/* Bio Section */} | ||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold', mb: 1 }}> | ||
Bio | ||
</Typography> | ||
|
||
<Card variant="outlined" sx={{ mb: 3, borderRadius: 2 }}> | ||
<CardContent> | ||
<Typography variant="body2" color="textSecondary"> | ||
{profileData?.description} | ||
</Typography> | ||
</CardContent> | ||
</Card> | ||
|
||
{/* Study Info Section */} | ||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold', mb: 1 }}> | ||
Study Info | ||
</Typography> | ||
|
||
<Card variant="outlined" sx={{ mb: 3, borderRadius: 2 }}> | ||
<CardContent> | ||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}> | ||
<Box sx={{ display: 'flex', alignItems: 'center' }}> | ||
<CalendarToday sx={{ mr: 1, color: 'grey.600' }} /> | ||
<Typography variant="body2" color="textSecondary"> | ||
Year | ||
</Typography> | ||
</Box> | ||
<Typography variant="body2">{profileData?.year}</Typography> | ||
</Box> | ||
|
||
<Divider sx={{ my: 1 }} /> | ||
|
||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}> | ||
<Box sx={{ display: 'flex', alignItems: 'center' }}> | ||
<School sx={{ mr: 1, color: 'grey.600' }} /> | ||
<Typography variant="body2" color="textSecondary"> | ||
{profileData?.major && profileData.major.includes(',') ? 'Majors' : 'Major'} | ||
</Typography> | ||
</Box> | ||
<Typography variant="body2">{profileData?.major}</Typography> | ||
</Box> | ||
|
||
<Divider sx={{ my: 1 }} /> | ||
|
||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}> | ||
<Box sx={{ display: 'flex', alignItems: 'center' }}> | ||
<ListAlt sx={{ mr: 1, color: 'grey.600' }} /> | ||
<Typography variant="body2" color="textSecondary"> | ||
Selected Courses | ||
</Typography> | ||
</Box> | ||
<Typography variant="body2">{profileData?.selectedCourses?.join(', ')}</Typography> | ||
</Box> | ||
</CardContent> | ||
</Card> | ||
|
||
{/* Edit and Sign Out Buttons */} | ||
<Box | ||
sx={{ | ||
display: 'flex', | ||
justifyContent: 'center', | ||
flexDirection: 'column', | ||
alignItems: 'center', | ||
mt: 4, | ||
}} | ||
> | ||
<Button variant="contained" onClick={handleEditClick} sx={{ mb: 2, width: '150px' }}> | ||
Edit Profile | ||
</Button> | ||
<Button | ||
variant="contained" | ||
color="secondary" | ||
sx={{ | ||
backgroundColor: 'theme.palette.secondary.main', | ||
width: '150px', | ||
}} | ||
onClick={handleSignOutDialogOpen} | ||
> | ||
Sign Out | ||
</Button> | ||
</Box> | ||
|
||
{/* Sign Out Confirmation Dialog */} | ||
<SignOutDialog open={signOutDialogOpen} onClose={() => setSignOutDialogOpen(false)} /> | ||
</Box> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React from 'react'; | ||
|
||
import { | ||
Dialog, | ||
DialogActions, | ||
DialogContent, | ||
DialogContentText, | ||
DialogTitle, | ||
Button, | ||
} from '@mui/material'; | ||
import { useNavigate } from 'react-router-dom'; | ||
|
||
import { handleSignOut } from '../utils/firebase'; | ||
|
||
export default function SignOutDialog({ open, onClose }) { | ||
const navigate = useNavigate(); | ||
|
||
const confirmSignOut = () => { | ||
handleSignOut(navigate); | ||
onClose(); | ||
}; | ||
|
||
return ( | ||
<Dialog open={open} onClose={onClose}> | ||
<DialogTitle>Confirm Sign Out</DialogTitle> | ||
<DialogContent> | ||
<DialogContentText>Are you sure you want to sign out?</DialogContentText> | ||
</DialogContent> | ||
<DialogActions> | ||
<Button onClick={onClose} color="primary"> | ||
Cancel | ||
</Button> | ||
<Button onClick={confirmSignOut} color="secondary"> | ||
Sign Out | ||
</Button> | ||
</DialogActions> | ||
</Dialog> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters