Skip to content

Commit

Permalink
refactor(ProfilePage): Refactor ProfilePage
Browse files Browse the repository at this point in the history
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
ZL-Asica committed Oct 10, 2024
1 parent 59dc75b commit e2279e2
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 35 deletions.
181 changes: 153 additions & 28 deletions src/components/ProfilePage.jsx
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">
Email
</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>
);
}
39 changes: 39 additions & 0 deletions src/components/SignOutDialog.jsx
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>
);
}
20 changes: 13 additions & 7 deletions src/components/common/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export default function Header() {
const { user, handleProfileClick, signInAndCheckFirstTimeUser } = useAuthNavigation();
const theme = useTheme();

const isProfilePage = window.location.pathname.includes('/profile/');

return (
<AppBar position="sticky" sx={{ backgroundColor: theme.palette.primary.light, color: '#000' }}>
<Toolbar sx={{ position: 'relative', justifyContent: 'space-between' }}>
Expand All @@ -30,14 +32,18 @@ export default function Header() {
</Typography>

{/* Right side: Sign In button or user avatar */}
{user ? (
<IconButton edge="end" color="inherit" onClick={handleProfileClick}>
<Avatar alt={user.displayName} src={user.photoURL} />
</IconButton>
{!isProfilePage ? (
user ? (
<IconButton edge="end" color="inherit" onClick={handleProfileClick}>
<Avatar alt={user.displayName} src={user.photoURL} />
</IconButton>
) : (
<Button color="inherit" onClick={signInAndCheckFirstTimeUser}>
Sign In
</Button>
)
) : (
<Button color="inherit" onClick={signInAndCheckFirstTimeUser}>
Sign In
</Button>
<Box sx={{ width: '48px' }} />
)}
</Toolbar>
</AppBar>
Expand Down

0 comments on commit e2279e2

Please sign in to comment.