Skip to content

Commit

Permalink
Feat: Update 'LikeButton' component logic
Browse files Browse the repository at this point in the history
- Moved the Like interface outside the component and added a new `error`
property.
- Updated 'LikeButtonProps' interface to include `projectsLikes` prop.
- Renamed 'setLoadingToFalse' function to 'setLoadingFalseAfterTimeout'.
- Removed projects likes fetching logic from 'updateLikeCount'.
- Added new conditions in 'updateLikeCount' to handle various scenarios.
- Updated 'handleLikeSubmit' function to handle error states and removed
unnecessary function invocations.
  • Loading branch information
ITurres committed Mar 9, 2024
1 parent b1b9ea9 commit cffadb4
Showing 1 changed file with 44 additions and 22 deletions.
66 changes: 44 additions & 22 deletions src/components/UI/LikeButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@ import '../../styles/animations/loading-icon.scss';

import involvement from '../../services/involvementAPI/involvementAPI.ts';

interface Like {
// * disable camelcase since 'item_id' is the name of the property in the API response.
// eslint-disable-next-line camelcase
item_id: string;
likes: number;
error?: boolean;
}
interface LikeButtonProps {
itemId: string;
projectsLikes: Like[];
}

const LikeButton: React.FC<LikeButtonProps> = ({ itemId }) => {
const LikeButton: React.FC<LikeButtonProps> = ({ itemId, projectsLikes }) => {
const [wasLiked, setWasLiked] = useState(false);
const [likeCount, setLikeCount] = useState(0);
const [error, setError] = useState(false);
Expand All @@ -41,61 +49,77 @@ const LikeButton: React.FC<LikeButtonProps> = ({ itemId }) => {
// ! terminate the loading state after a certain time.
// ? this is to prevent the loading state from being stuck.
// * and show the user the like button again.
const setLoadingToFalse = useCallback(() => {
const setLoadingFalseAfterTimeout = useCallback(() => {
setTimeout(() => {
setLoading(false);
}, maximumLoadingTime);
}, []);

interface Like {
// * disable camelcase since 'item_id' is the name of the property in the API response.
// eslint-disable-next-line camelcase
item_id: string;
likes: number;
}

const updateLikeCount = useCallback(async () => {
const likes: Like[] = (await involvement.getLikes()) as Like[];
const updateLikeCount = useCallback(() => {
// ? When the Involvement API App ID is new, it will return an empty ary with an empty object
// ? while fetching the projectsLikes at 'projectsPage',
// * here we will receive an array with one empty object, thats the 1 length.
// * so just terminate the loading state, and show the like button with no likes.
if (projectsLikes.length === 1) {
setLoadingFalseAfterTimeout();
return;
}

if (likes.length === 0) {
// ? If an error was catch at the 'projectsPage' while fetching the projectsLikes,
// ? we will receive an array with one object with the error property set to true.
if (projectsLikes[0].error) {
setError(true);
// ? at this point the loading spinner is still showing.
// * so terminate the loading state, to show the error message.
setLoadingToFalse();
setLoadingFalseAfterTimeout();
return;
}

const likedProject = likes.find((like) => like.item_id === itemId);
const likedProject = projectsLikes.find(
(project) => project.item_id === itemId,
) as Like | undefined;

if (likedProject) {
setLikeCount(likedProject.likes);
// ? at this point the loading spinner is still showing because of the initial API request.
// * so terminate the loading state, to show the like button with the like count.
setLoadingToFalse();
setLoadingFalseAfterTimeout();
} else {
// * If a project has no likes, then terminate the loading state,
// * to show the like button with no likes.
setLoadingFalseAfterTimeout();
}
}, [itemId, setLoadingToFalse]);
}, [itemId, setLoadingFalseAfterTimeout, projectsLikes]);

useEffect(() => {
updateLikeCount();
}, [itemId, updateLikeCount]);

const handleLikeSubmit = async () => {
setWasLiked((liked) => !liked);
// ? Since 'wasLiked' was false, now it will be set to true. This is to
// ? trigger the function 'styleButton' to add the 'liked' class to the button.
setWasLiked((wasLiked) => !wasLiked);

// * shows an instant update of the like count.
if (!wasLiked) {
setLikeCount((count) => count + 1);
// * set 'wasLiked' to false, so that the user can like the project again.
setWasLiked((wasLiked) => !wasLiked);
}

if (error) {
if (projectsLikes[0].error || error) {
// ? at this point, there was an error already, so user will attempt to like again.
// * so trigger the loading state again.
setLoading(true);
// * after some time, terminate the loading state, to show like button again.
setLoadingToFalse();
setLoadingFalseAfterTimeout();
// * and finally show the error message.
setError(true);
return;
}

// ? If after all, the error state is still false, then the user can like the project.
// * i.e. POST the like to the API.
const likePosted = await involvement.postLike(itemId);

if (likePosted === 'error') {
Expand All @@ -104,8 +128,6 @@ const LikeButton: React.FC<LikeButtonProps> = ({ itemId }) => {
}

setLoading(false);
// * after posting a like, update the like count.
updateLikeCount();
};

if (loading) {
Expand Down Expand Up @@ -137,7 +159,7 @@ const LikeButton: React.FC<LikeButtonProps> = ({ itemId }) => {
{(likeCount > 0 || error) && (
<span className="like-button__text">
&nbsp;
{!error ? likeCount : 'Error'}
{error ? 'Error' : likeCount }
</span>
)}
</button>
Expand Down

0 comments on commit cffadb4

Please sign in to comment.