Profile.jsx
Navnit Rai
Posted on September 22, 2024
import {
Avatar,
Button,
Container,
Heading,
HStack,
Image,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Stack,
Text,
useDisclosure,
VStack,
} from '@chakra-ui/react'; // Chakra UI components for UI layout
import React, { useEffect, useState } from 'react'; // React and hooks
import toast from 'react-hot-toast'; // For notifications
import { RiDeleteBin7Fill } from 'react-icons/ri'; // Delete icon
import { useDispatch, useSelector } from 'react-redux'; // For Redux state management
import { Link } from 'react-router-dom'; // For routing
import {
removeFromPlaylist,
updateProfilePicture,
} from '../../redux/actions/profile'; // Actions for profile management
import { cancelSubscription, loadUser } from '../../redux/actions/user'; // User actions
import { fileUploadCss } from '../Auth/Register'; // CSS for file upload
const Profile = ({ user }) => {
const dispatch = useDispatch();
const { loading, message, error } = useSelector(state => state.profile); // Profile state
const {
loading: subscriptionLoading,
message: subscriptionMessage,
error: subscriptionError,
} = useSelector(state => state.subscription); // Subscription state
// Handler to remove course from playlist
const removeFromPlaylistHandler = async id => {
await dispatch(removeFromPlaylist(id)); // Dispatch action to remove from playlist
dispatch(loadUser()); // Reload user data
};
// Handler to change the profile picture
const changeImageSubmitHandler = async (e, image) => {
e.preventDefault(); // Prevent default form submission
const myForm = new FormData(); // Create form data
myForm.append('file', image); // Append the image file
await dispatch(updateProfilePicture(myForm)); // Dispatch action to update profile picture
dispatch(loadUser()); // Reload user data
};
// Handler to cancel the subscription
const cancelSubscriptionHandler = () => {
dispatch(cancelSubscription()); // Dispatch action to cancel subscription
};
// Effect to handle notifications and state changes
useEffect(() => {
if (error) {
toast.error(error); // Show error toast
dispatch({ type: 'clearError' }); // Clear error from state
}
if (message) {
toast.success(message); // Show success toast
dispatch({ type: 'clearMessage' }); // Clear message from state
}
if (subscriptionMessage) {
toast.success(subscriptionMessage); // Show subscription success toast
dispatch({ type: 'clearMessage' }); // Clear subscription message
dispatch(loadUser()); // Reload user data
}
if (subscriptionError) {
toast.error(subscriptionError); // Show subscription error toast
dispatch({ type: 'clearError' }); // Clear subscription error
}
}, [dispatch, error, message, subscriptionError, subscriptionMessage]);
// Modal control for changing photo
const { isOpen, onClose, onOpen } = useDisclosure();
return (
<Container minH={'95vh'} maxW="container.lg" py="8">
<Heading children="Profile" m="8" textTransform={'uppercase'} />
<Stack
justifyContent={'flex-start'}
direction={['column', 'row']}
alignItems={'center'}
spacing={['8', '16']}
padding="8"
>
<VStack>
<Avatar boxSize={'48'} src={user.avatar.url} /> {/* User avatar */}
<Button onClick={onOpen} colorScheme={'yellow'} variant="ghost">
Change Photo
</Button>
</VStack>
<VStack spacing={'4'} alignItems={['center', 'flex-start']}>
<HStack>
<Text children="Name" fontWeight={'bold'} />
<Text children={user.name} />
</HStack>
<HStack>
<Text children="Email" fontWeight={'bold'} />
<Text children={user.email} />
</HStack>
<HStack>
<Text children="CreatedAt" fontWeight={'bold'} />
<Text children={user.createdAt.split('T')[0]} /> {/* Format created date */}
</HStack>
{user.role !== 'admin' && (
<HStack>
<Text children="Subscription" fontWeight={'bold'} />
{user.subscription && user.subscription.status === 'active' ? (
<Button
isLoading={subscriptionLoading}
onClick={cancelSubscriptionHandler}
color={'yellow.500'}
variant="unstyled"
>
Cancel Subscription
</Button>
) : (
<Link to="/subscribe">
<Button colorScheme={'yellow'}>Subscribe</Button>
</Link>
)}
</HStack>
)}
<Stack direction={['column', 'row']} alignItems={'center'}>
<Link to="/updateprofile">
<Button>Update Profile</Button>
</Link>
<Link to="/changepassword">
<Button>Change Password</Button>
</Link>
</Stack>
</VStack>
</Stack>
<Heading children="Playlist" size={'md'} my="8" />
{user.playlist.length > 0 && (
<Stack
direction={['column', 'row']}
alignItems={'center'}
flexWrap="wrap"
p="4"
>
{user.playlist.map(element => (
<VStack w="48" m="2" key={element.course}>
<Image
boxSize={'full'}
objectFit="contain"
src={element.poster} // Course poster
/>
<HStack>
<Link to={`/course/${element.course}`}>
<Button variant={'ghost'} colorScheme="yellow">
Watch Now
</Button>
</Link>
<Button
isLoading={loading}
onClick={() => removeFromPlaylistHandler(element.course)} // Remove course from playlist
>
<RiDeleteBin7Fill /> {/* Delete icon */}
</Button>
</HStack>
</VStack>
))}
</Stack>
)}
<ChangePhotoBox
changeImageSubmitHandler={changeImageSubmitHandler}
isOpen={isOpen}
onClose={onClose}
loading={loading}
/>
</Container>
);
};
export default Profile;
// Component for changing the profile photo
function ChangePhotoBox({
isOpen,
onClose,
changeImageSubmitHandler,
loading,
}) {
const [image, setImage] = useState(''); // State for the selected image
const [imagePrev, setImagePrev] = useState(''); // State for the preview image
// Handler to read the selected image
const changeImage = e => {
const file = e.target.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
setImagePrev(reader.result); // Set preview image
setImage(file); // Set selected image
};
};
// Close handler for modal
const closeHandler = () => {
onClose();
setImagePrev(''); // Reset preview image
setImage(''); // Reset selected image
};
return (
<Modal isOpen={isOpen} onClose={closeHandler}>
<ModalOverlay backdropFilter={'blur(10px)'} />
<ModalContent>
<ModalHeader>Change Photo</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Container>
<form onSubmit={e => changeImageSubmitHandler(e, image)}>
<VStack spacing={'8'}>
{imagePrev && <Avatar src={imagePrev} boxSize={'48'} />} {/* Preview of the new image */}
<Input
type={'file'}
css={{ '&::file-selector-button': fileUploadCss }} // Custom CSS for file input
onChange={changeImage} // Handler for file input change
/>
<Button
isLoading={loading}
w="full"
colorScheme={'yellow'}
type="submit" // Submit button to change the photo
>
Change
</Button>
</VStack>
</form>
</Container>
</ModalBody>
<ModalFooter>
<Button mr="3" onClick={closeHandler}> // Cancel button
Cancel
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
💖 💪 🙅 🚩
Navnit Rai
Posted on September 22, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.