Skip to content

Commit

Permalink
Massive improvement of the whole structure, nomenclatures, redux appr…
Browse files Browse the repository at this point in the history
…oach and everything else.
  • Loading branch information
raphaelcordon committed Dec 9, 2024
1 parent 4c58f66 commit e8ae56f
Show file tree
Hide file tree
Showing 33 changed files with 284 additions and 221 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
<script type="module" src="/src/index.jsx"></script>
</body>
</html>
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"react-router-dom": "^6.26.2",
"react-toastify": "^10.0.6"
"react-toastify": "^10.0.6",
"reselect": "^5.1.1"
},
"devDependencies": {
"@eslint/js": "^9.9.0",
Expand Down
7 changes: 0 additions & 7 deletions src/App.jsx

This file was deleted.

30 changes: 12 additions & 18 deletions src/components/navBar/userMenuComponent.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Link, NavLink, useNavigate } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { logoutUser, loginUser } from "../../store/slices/userReducer.js"; // Import loginUser
import { logoutUser, loginUser } from "../../store/reducers/userReducer.js"; // Import loginUser
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faRightFromBracket, faGear, faArrowRightToBracket, faBell } from "@fortawesome/free-solid-svg-icons";
import useGetAuthenticatedUser from "../../hooks/useGetAuthenticatedUser.jsx";
Expand All @@ -17,26 +17,20 @@ const UserMenuComponent = () => {
const { logout } = useLogout();

// Check localStorage and update Redux state
useEffect(() => {
const localToken = window.localStorage.getItem("resenhando:authToken");
if (localToken && !token) {
dispatch(loginUser(localToken));
useEffect(()=> {
const localStorageToken = window.localStorage.getItem("resenhando:authToken");

if (localStorageToken && !token) {
dispatch(loginUser(localStorageToken));
}
}, [dispatch, token]);

const fetchUser = useCallback(async () => {
if (token && !user) {
try {
await getUser();
} catch (err) {
console.error("Failed to fetch user data:", err);
}
if (localStorageToken && token && !user) {
fetchUser();
}
}, [getUser, token, user]);
}, [dispatch, token, user]);

useEffect(() => {
fetchUser();
}, [fetchUser]);
const fetchUser = async () => {
await getUser();
};

return (
<div className="h-full w-full flex justify-end">
Expand Down
3 changes: 2 additions & 1 deletion src/components/review/cardComponents/reviewCardComponent.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import truncateText from "../../../hooks/common/truncateText.js";
import AdjustDatetime from "../../../hooks/common/AdjustDatetime.js";

// This component is shown at main components for ARTISTS, ALBUMS and TRACKS
const ReviewCardComponent = ({ review }) => {
const { id, coverImage, reviewTitle, reviewBody, reviewType, spotifyId, createdAt, user } = review;

const formattedDate = new Date(createdAt).toLocaleDateString('en-GB');
const formattedDate = AdjustDatetime(createdAt);

return (
<div className="w-full lg:w-72 shadow m-0 hover:opacity-60">
Expand Down
127 changes: 78 additions & 49 deletions src/components/review/commonComponents/reviewViewBody.jsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,96 @@
import {useEffect, useState} from "react";
import AdjustDatetime from "../../../hooks/common/AdjustDatetime.js";

const reviewViewBody = ({reviewProp}) => {

const {finalReviewContent, imageUrl, reviewTitle, reviewBody} = reviewProp;
const {finalReviewContent, review} = reviewProp;
const [reviewType, setReviewType] = useState("");
const formattedDate = AdjustDatetime(review.createdAt);

useEffect(() => {
switch (review.reviewType) {
case 0:
setReviewType("artist");
break;
case 1:
setReviewType("album");
break;
case 2:
setReviewType("track");
break;
}
});

return (
<div className="w-full flex flex-col md:flex-row justify-start md:justify-center">
{/* Image block */}
<div className="w-42 md:w-1/2 md:h-full">
<img src={imageUrl} alt={finalReviewContent.name} className="w-full h-full md:h-full object-cover block"/>
<img src={review.coverImage} alt={finalReviewContent.name} className="w-full h-full md:h-full object-cover block"/>
</div>

{/* Review */}
<div className="md:w-1/2 w-[95vw] p-6">
<h2 className="text-xl font-semibold text-start mt-2 mb-2">
Review about: "{finalReviewContent.name}"
</h2>
<div className="mb-4">{reviewTitle}</div>
<div className="mb-4">{reviewBody}</div>
<div className="w-full md:w-1/2 md:p-4 md:pt-0 flex flex-col">

<div className="flex flex-col justify-between text-sm text-gray-600 font-light text-start py-4 px-1">
<div className="">
Review about the {reviewType} <b>{finalReviewContent.name}</b>
</div>
<div>Created at {formattedDate} by <b>{review.user.firstName} {review.user.lastName}</b></div>
</div>

{!finalReviewContent.track ? (

<>
{/* Genres */}
<div className="pb-4">
<span className="font-bold">Genres: </span>
{finalReviewContent.genres ? (
<span className="w-full text-sm pl-1">{finalReviewContent.genres}</span>
) : (
<span className="text-sm text-gray-500 pl-1">Not defined</span>
)}
</div>
{/* Review Title and Body */}
<div className="bg-gray-100 py-0 px-1 mb-4 w-full">
<div className="mb-4 text-2xl font-bold">{review.reviewTitle}</div>
<div className="mb-4">{review.reviewBody}</div>
</div>

{/* Followers */}
<div className="pb-4">
<span className="font-bold">Spotify followers:</span>
<span className="text-sm md:text-base font-bold pl-1">{finalReviewContent.followers}</span>
</div>
</>
<div className="w-full p-2 md:p-0 flex flex-col">
{!finalReviewContent.track ? (

<>
{/* Genres */}
<div className="pb-4">
<span className="font-bold">Genres: </span>
{finalReviewContent.genres ? (
<span className="w-full text-sm pl-1">{finalReviewContent.genres}</span>
) : (
<span className="text-sm text-gray-500 pl-1">Not defined</span>
)}
</div>

{/* Followers */}
<div className="pb-4">
<span className="font-bold">Spotify followers:</span>
<span className="text-sm md:text-base font-bold pl-1">{finalReviewContent.followers}</span>
</div>
</>

) : (
<>
{/* Release Data */}
<div className="pb-4">
<span className="font-bold">Release Date:</span>
<span className="text-sm md:text-base font-bold pl-1">{finalReviewContent.releaseDate}</span>
</div>
</>
)}

) : (
<>
{/* Release Data */}
<div className="pb-4">
<span className="font-bold">Release Date:</span>
<span className="text-sm md:text-base font-bold pl-1">{finalReviewContent.releaseDate}</span>
{/* Popularity */}
<div className="flex items-center">
<span className="font-bold mr-2">Artist Popularity:</span>
<div className="flex-1 bg-gray-300 rounded-lg h-4 relative">
<div
className="bg-green-500 h-4 rounded-lg"
style={{width: `${finalReviewContent.popularity}%`}}
></div>
</div>
</>
)}

{/* Popularity */}
<div className="flex items-center">
<span className="font-bold mr-2">Artist Popularity:</span>
<div className="flex-1 bg-gray-300 rounded-lg h-4 relative">
<div
className="bg-green-500 h-4 rounded-lg"
style={{width: `${finalReviewContent.popularity}%`}}
></div>
<span className="text-sm md:text-base font-bold pl-2">{finalReviewContent.popularity}%</span>
</div>

{/* Embedded Radio */}
<div className="w-full flex justify-center items-center mt-4">
<iframe src={finalReviewContent.radioUrl} width="1024" height="500" allow="encrypted-media"></iframe>
</div>
<span className="text-sm md:text-base font-bold pl-2">{finalReviewContent.popularity}%</span>
</div>

{/* Embedded Radio */}
<div className="w-full flex justify-center items-center mt-2">
<iframe src={finalReviewContent.radioUrl} width="1024" height="500" allow="encrypted-media"></iframe>
</div>

</div>
Expand Down
34 changes: 15 additions & 19 deletions src/components/review/detailingComponents/reviewArtistDetailed.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import ButtonCreateReview from "../../buttons/buttonCreateReview.jsx";
import ButtonCreateReview from "../../buttons/buttonCreateReview";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {useDispatch, useSelector} from "react-redux";
import truncateText from "../../../hooks/common/truncateText";
import titleText from "../../../hooks/common/titleText";
import {NavLink} from "react-router-dom";
import { faCircleDown } from '@fortawesome/free-solid-svg-icons';
import ReviewWriteArtist from "./../writingComponents/reviewWriteNewArtist.jsx";
import {useState} from "react";
import truncateText from "../../../hooks/common/truncateText.js";
import titleText from "../../../hooks/common/titleText.js";
import {addSpotifyArtist} from "../../../store/reducers/spotifyArtistReducer";

// The component details an ARTIST before the user decides to write a review about it
const ReviewArtistDetailed = ({ item }) => {

const dispatch = useDispatch();
dispatch(addSpotifyArtist(item));

const { id, name, uri, href, genres, popularity } = item;
const image = item.images?.[0];
const imageUrl = image?.url;
Expand All @@ -16,15 +21,6 @@ const ReviewArtistDetailed = ({ item }) => {
const externalUrl = item.externalUrls.spotify;
const radio = `${externalUrl.substring(0, 25)}embed/${externalUrl.substring(25, externalUrl.length)}`;

const [writingReview, setWritingReview] = useState(false);
const handleStartReview = () => {
setWritingReview(true);
};

if (writingReview) {
return <ReviewWriteArtist item={item} />;
}

const ListGenres = (genres) => {
const preparedList = genres.map((genre) => `${titleText(genre)}`)
return preparedList.toString().replaceAll(',', ', ');
Expand All @@ -36,7 +32,6 @@ const ReviewArtistDetailed = ({ item }) => {
target.scrollIntoView({ behavior: "smooth", block: "center" });
}
};

return (
<div className="h-full w-full flex flex-col justify-between">

Expand All @@ -62,10 +57,11 @@ const ReviewArtistDetailed = ({ item }) => {
</div>

{/* Button Create Review */}
<div className="w-full mt-4 flex justify-center" id="createArtistReview">
<ButtonCreateReview buttonName={`Write a review about ${truncateText(name, 20)}`}
onClick={handleStartReview}/>
</div>
<NavLink to={`/reviewWriteArtist/${item.id}/`}>
<div className="w-full mt-4 flex justify-center" id="createArtistReview">
<ButtonCreateReview buttonName={`Write a review about ${truncateText(name, 20)}`} />
</div>
</NavLink>

{/* Text block */}
<article
Expand Down
2 changes: 2 additions & 0 deletions src/hooks/common/AdjustDatetime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const AdjustDatetime = (dateToBeFormated) => new Date(dateToBeFormated).toLocaleDateString('en-GB');
export default AdjustDatetime;
3 changes: 2 additions & 1 deletion src/hooks/useAuth.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useDispatch} from "react-redux";
import {useCallback, useState} from "react";
import {loginUser, storeUserData} from "../store/slices/userReducer.js";
import {loginUser, storeUserData} from "../store/reducers/userReducer.js";
import {AuthenticateUser} from "../axios/accountAxios.js";

const useAuth = () => {
Expand All @@ -14,6 +14,7 @@ const useAuth = () => {
window.localStorage.setItem("resenhando:authToken", authResponse.token);
dispatch(loginUser(authResponse.token));
dispatch(storeUserData(authResponse.userLoggedIn))
console.log(authResponse.userLoggedIn)
} catch (error) {
setError(error.message || "An error occurred during login.");
throw error;
Expand Down
6 changes: 3 additions & 3 deletions src/hooks/useCreateReview.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {useDispatch} from "react-redux";
import {useCallback, useState} from "react";
import {storeReviewArtistData} from "../store/slices/reviewArtistReducer.js";
import {storeReviewAlbumData} from "../store/slices/reviewAlbumReducer.js";
import {storeReviewTrackData} from "../store/slices/reviewTrackReducer.js";
import {storeReviewArtistData} from "../store/reducers/reviewArtistReducer.js";
import {storeReviewAlbumData} from "../store/reducers/reviewAlbumReducer.js";
import {storeReviewTrackData} from "../store/reducers/reviewTrackReducer.js";
import {Create} from "../axios/reviewAxios.js";

const useCreateReview = () => {
Expand Down
20 changes: 20 additions & 0 deletions src/hooks/useFetchAllReviewsOnLoading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useDispatch } from "react-redux";
import { GetReviews } from "../axios/reviewAxios.js";
import { storeReviewArtistData } from "../store/reducers/reviewArtistReducer.js";
import {storeReviewAlbumData} from "../store/reducers/reviewAlbumReducer.js";
import {storeReviewTrackData} from "../store/reducers/reviewTrackReducer.js";

export default function useFetchAllReviewsOnLoading() {
const dispatch = useDispatch();

return async (skip = 0, take = 8) => {
const artist = await GetReviews(0, skip, take);
dispatch(storeReviewArtistData(artist));

const album = await GetReviews(1, skip, take);
dispatch(storeReviewAlbumData(album));

const track = await GetReviews(2, skip, take);
dispatch(storeReviewTrackData(track));
};
};
4 changes: 2 additions & 2 deletions src/hooks/useGetAuthenticatedUser.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useDispatch } from "react-redux";
import { useCallback, useState } from "react";
import { storeUserData, logoutUser } from "../store/slices/userReducer.js";
import { storeUserData, logoutUser } from "../store/reducers/userReducer.js";
import { GetFromClaim } from "../axios/userAxios.js";

const useGetAuthenticatedUser = () => {
Expand All @@ -11,7 +11,7 @@ const useGetAuthenticatedUser = () => {
setError(null);
try {
const res = await GetFromClaim();
dispatch(storeUserData(res.data)); // Store user data if successful
dispatch(storeUserData(res)); // Store user data if successful
} catch (error) {
setError(error);
window.localStorage.removeItem("resenhando:authToken");
Expand Down
Loading

0 comments on commit e8ae56f

Please sign in to comment.