-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor: change dashbard menu items order * refactor: change dashbard menu items order * feat: set up explore user profiles page scaffolding * feat: add new sidebar nav item * feat: style explore user profiles card grid * refactor: change dashbard menu items order * feat: set up explore user profiles page scaffolding * feat: add new sidebar nav item * feat: style explore user profiles card grid * feat: set up userprofile routing * feat: remove unneeded sidebar link item * fix: set user data upon refresh page * feat: implement getUserProfile endpoint * feat: implement user profile permissions logic * feat: set up user profile page HTML structure * chore: install eslint to ensure proper usage of react hooks * fix: set user data after retrieving tokens via manual login * feat: style profile section of userprofilepage * feat: create profile component files * feat: display user book list * feat: implement user profile settings logic * feat: implement explore users page logic * feat: implement user book stats and progress on change profile picture * fix: remove align center from book list grid * chore: remove console.log
- Loading branch information
1 parent
55928a4
commit 3046dec
Showing
11 changed files
with
577 additions
and
37 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
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
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
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,59 @@ | ||
import { useParams } from "react-router-dom"; | ||
import { | ||
Box, | ||
Flex, | ||
Heading, | ||
Image, | ||
Spacer, | ||
Stack, | ||
Switch, | ||
Text, | ||
Divider, | ||
Button, | ||
Icon, | ||
SlideFade, | ||
SimpleGrid, | ||
useColorModeValue | ||
} from "@chakra-ui/react"; | ||
import ProfileBookRow from "./ProfileBookRow"; | ||
|
||
export default function ProfileBookList({ bookList }) { | ||
const containerColor = useColorModeValue("whiteAlpha.900", "gray.800"); | ||
|
||
return ( | ||
<Box> | ||
<Heading mb={"20px"}>Book List</Heading> | ||
<Flex | ||
flexDirection={"column"} | ||
columnGap={"50px"} | ||
height="100%" | ||
padding={"20px"} | ||
bg={containerColor} | ||
borderRadius={"5px"} | ||
> | ||
<SlideFade in={bookList.length > 0} out={bookList.length === 0}> | ||
<SimpleGrid | ||
spacing={10} | ||
justifyContent={"center"} | ||
columns={[1, 1, 1, 1, 2, 3]} | ||
p={5} | ||
> | ||
{bookList.map((bookObject, index) => { | ||
return ( | ||
<ProfileBookRow | ||
key={index} | ||
title={bookObject.book.title} | ||
author={bookObject.book.author} | ||
cover={bookObject.book.cover_image} | ||
status = {bookObject.status} | ||
rating = {bookObject.rating} | ||
currentPage = {bookObject.current_page} | ||
/> | ||
); | ||
})} | ||
</SimpleGrid> | ||
</SlideFade> | ||
</Flex> | ||
</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,56 @@ | ||
import { | ||
Card, | ||
Flex, | ||
Box, | ||
Text, | ||
Spacer, | ||
CardHeader, | ||
Heading, | ||
CardBody, | ||
Stack, | ||
CardFooter, | ||
Button, | ||
Image, | ||
Badge, | ||
Alert, | ||
} from "@chakra-ui/react"; | ||
|
||
export default function ProfileBookRow({ | ||
title, | ||
author, | ||
cover, | ||
status, | ||
rating, | ||
lastUpdated, | ||
}) { | ||
return ( | ||
<Card | ||
direction={{ base: "column", sm: "row" }} | ||
overflow="hidden" | ||
variant="outline" | ||
> | ||
<Image | ||
objectFit="cover" | ||
maxW={{ base: "100%", sm: "200px" }} | ||
src={cover} | ||
alt="Caffe Latte" | ||
/> | ||
|
||
<Stack> | ||
<CardBody> | ||
<Heading size="md">{title}</Heading> | ||
<Text size={"md"} py="2"> | ||
Written by {author} | ||
</Text> | ||
<Text py="2"> | ||
<Alert status="success" variant="subtle" width={"full"}> | ||
{status} | ||
</Alert> | ||
</Text> | ||
<Text py="2">Last updated {lastUpdated}</Text> | ||
<Text py="2">{ rating ? "Rating: " + rating : ""}</Text> | ||
</CardBody> | ||
</Stack> | ||
</Card> | ||
); | ||
} |
201 changes: 201 additions & 0 deletions
201
client/src/components/UserProfile/ProfileSettingsStats.jsx
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,201 @@ | ||
import { useParams } from "react-router-dom"; | ||
import { | ||
Box, | ||
Flex, | ||
Heading, | ||
Image, | ||
Spacer, | ||
Stack, | ||
Switch, | ||
Text, | ||
Divider, | ||
Button, | ||
useColorModeValue, | ||
useColorMode, | ||
} from "@chakra-ui/react"; | ||
import apiClient from "../../services/apiClient"; | ||
import { useEffect, useState } from "react"; | ||
import BookList from "./../../pages/BookList"; | ||
export default function ProfileSettingsStats({ userProfile, isOriginalUser }) { | ||
// styling related | ||
const { colorMode, toggleColorMode } = useColorMode(); | ||
const containerColor = useColorModeValue("whiteAlpha.900", "gray.800"); | ||
const orangeTextTheme = useColorModeValue("orange.500", "orange.200"); | ||
// settings related | ||
const [isProfilePrivate, setIsProfilePrivate] = useState(userProfile.private); | ||
const [selectedImage, setSelectedImage] = useState(null); | ||
// book stats related | ||
const [bookList, setBookList] = useState(userProfile.book_list); | ||
const [bookCountByCategory, setBookCountByCategory] = useState({ | ||
All: 0, | ||
"Not started": 0, | ||
Dropped: 0, | ||
Completed: 0, | ||
}); | ||
|
||
async function handleOnPrivacyToggle() { | ||
await apiClient.editProfile(userProfile.user.username, { | ||
private: !isProfilePrivate, | ||
}); | ||
setIsProfilePrivate(!isProfilePrivate); | ||
} | ||
|
||
function handleImageChange(event) { | ||
const file = event.target.files[0]; | ||
setSelectedImage(file); | ||
} | ||
|
||
function handleUpload() { | ||
if (selectedImage) { | ||
apiClient.uploadProfilePicture({ image_url: selectedImage }); | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
let categoryCountObject = { | ||
All: 0, | ||
"Not started": 0, | ||
Dropped: 0, | ||
Completed: 0, | ||
}; | ||
if (userProfile) { | ||
bookList.map((element, index) => { | ||
categoryCountObject[`${element.status}`] += 1; | ||
categoryCountObject.All += 1; | ||
}); | ||
|
||
setBookCountByCategory(categoryCountObject); | ||
} | ||
}, [bookList]); | ||
|
||
return ( | ||
<> | ||
<Heading textColor={orangeTextTheme}>User Profile</Heading> | ||
<Flex | ||
columnGap={"50px"} | ||
height="100%" | ||
maxHeight={"30vh"} | ||
padding={"20px"} | ||
bg={containerColor} | ||
borderRadius={"5px"} | ||
> | ||
<Image | ||
boxSize="250px" | ||
objectFit="cover" | ||
src={`http://localhost:8000${userProfile.profile_picture}`} | ||
alt="Dan Abramov" | ||
fallbackSrc="https://via.placeholder.com/250" | ||
/> | ||
{/* Profile and Settings */} | ||
{isOriginalUser && | ||
<Box | ||
display="flex" | ||
flexDirection={"column"} | ||
rowGap={"10px"} | ||
width={"full"} | ||
maxWidth={"425px"} | ||
> | ||
<Text color={orangeTextTheme} fontWeight={"bold"}> | ||
{userProfile.user.first_name} {userProfile.user.last_name} | ||
</Text> | ||
<Text>Favorite Book: {userProfile.favorite_book.title}</Text> | ||
<Text>{userProfile.book_list.length} book entries</Text> | ||
{isOriginalUser && ( | ||
<Stack direction="row"> | ||
<Text>Private Profile</Text> | ||
<Spacer /> | ||
<Switch | ||
colorScheme="orange" | ||
size="lg" | ||
isChecked={isProfilePrivate} | ||
onChange={handleOnPrivacyToggle} | ||
/> | ||
</Stack> | ||
)} | ||
{isOriginalUser && ( | ||
<Stack direction="row"> | ||
<Text>Dark mode</Text> | ||
<Spacer /> | ||
<Switch | ||
colorScheme="orange" | ||
size="lg" | ||
onChange={toggleColorMode} | ||
isChecked={colorMode === "dark" ? true : false} | ||
/> | ||
</Stack> | ||
)} | ||
{isOriginalUser && ( | ||
<Stack direction={"row"} alignItems={"center"}> | ||
<Box | ||
width={"full"} | ||
fontWeight={"semibold"} | ||
colorScheme="orange" | ||
bg={colorMode == "light" ? "gray.100" : "gray.700"} | ||
padding={"9px"} | ||
borderRadius={"5px"} | ||
> | ||
<label | ||
htmlFor="file-upload" | ||
style={{ marginBottom: "1rem" }} | ||
width="100%" | ||
> | ||
<Box _hover={{ cursor: "pointer" }} width={"full"}> | ||
Edit Profile Picture | ||
</Box> | ||
</label> | ||
<input | ||
id="file-upload" | ||
type="file" | ||
onChange={handleImageChange} | ||
style={{ display: "none" }} | ||
accept="image/jpeg,image/png,image/gif" | ||
/> | ||
</Box> | ||
<Button colorScheme="orange" onClick={handleUpload} width={"50%"}> | ||
Upload | ||
</Button> | ||
</Stack> | ||
)} | ||
</Box>} | ||
|
||
{/* Book Stats */} | ||
<Box | ||
display="flex" | ||
flexDirection={"column"} | ||
rowGap={"10px"} | ||
width={"full"} | ||
maxWidth={"425px"} | ||
> | ||
<Text color={orangeTextTheme} fontWeight={"bold"}> | ||
Book Stats | ||
</Text> | ||
<Stack direction="row"> | ||
<Text>Favorite Book:</Text> | ||
<Spacer /> | ||
<Text>{userProfile.favorite_book.title}</Text> | ||
</Stack> | ||
<Stack direction="row"> | ||
<Text>All</Text> | ||
<Spacer /> | ||
<Text>{bookCountByCategory.All}</Text> | ||
</Stack> | ||
<Stack direction="row"> | ||
<Text>Completed</Text> | ||
<Spacer /> | ||
<Text>{bookCountByCategory.Completed}</Text> | ||
</Stack> | ||
<Stack direction="row"> | ||
<Text>Not yet started</Text> | ||
<Spacer /> | ||
<Text>{bookCountByCategory["Not started"]}</Text> | ||
</Stack> | ||
<Stack direction="row"> | ||
<Text>Dropped</Text> | ||
<Spacer /> | ||
<Text>{bookCountByCategory.Dropped}</Text> | ||
</Stack> | ||
</Box> | ||
</Flex> | ||
</> | ||
); | ||
} |
Oops, something went wrong.