From e48e55d9d6f2c1dcf45d94a01d661de1129a0c8a Mon Sep 17 00:00:00 2001 From: ITurres Date: Mon, 4 Mar 2024 23:03:36 -0300 Subject: [PATCH 1/3] Feat: Update 'LikeButton' to show loading state Now the Like button will have its loading state and spinner. This loading spinner will be shown in two situations, at first render, i.e when the likes are being fetch, and when the user likes a project, i.e if the user likes it, it will render the spinner until the request its finish and showing the updated number of likes or an error message if the request fails. This will certaintly enhance the user experience. --- src/components/UI/LikeButton.tsx | 54 ++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/src/components/UI/LikeButton.tsx b/src/components/UI/LikeButton.tsx index d53744b..8eea8f3 100644 --- a/src/components/UI/LikeButton.tsx +++ b/src/components/UI/LikeButton.tsx @@ -6,12 +6,12 @@ import React, { } from 'react'; import { SlLike } from 'react-icons/sl'; +import { VscLoading } from 'react-icons/vsc'; import '../../styles/UI/LikeButton.scss'; import involvement from '../../services/involvementAPI/involvementAPI.ts'; -/* eslint-disable no-undef */ interface LikeButtonProps { itemId: string; } @@ -20,6 +20,8 @@ const LikeButton: React.FC = ({ itemId }) => { const [wasLiked, setWasLiked] = useState(false); const [likeCount, setLikeCount] = useState(0); const [error, setError] = useState(false); + const [loading, setLoading] = useState(true); + const maximumLoadingTime = 5000; const likeBtn = useRef(null); @@ -35,6 +37,15 @@ const LikeButton: React.FC = ({ itemId }) => { } }, [wasLiked, styleButton]); + // ! 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(() => { + 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 @@ -45,12 +56,21 @@ const LikeButton: React.FC = ({ itemId }) => { const updateLikeCount = useCallback(async () => { const likes: Like[] = (await involvement.getLikes()) as Like[]; + if (likes.length === 0) { + setError(true); + // ? at this point the loading spinner is still showing. + // * so terminate the loading state, to show the error message. + setLoadingToFalse(); + return; + } + const likedProject = likes.find((like) => like.item_id === itemId); if (likedProject) { setLikeCount(likedProject.likes); + setLoadingToFalse(); } - }, [itemId]); + }, [itemId, setLoadingToFalse]); useEffect(() => { updateLikeCount(); @@ -64,26 +84,54 @@ const LikeButton: React.FC = ({ itemId }) => { setLikeCount((count) => count + 1); } + if (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(); + return; + } + const likePosted = await involvement.postLike(itemId); if (likePosted === 'error') { setError(true); + return; } + setLoading(false); // * after posting a like, update the like count. updateLikeCount(); }; + if (loading) { + return ( + + ); + } + return (