diff --git a/frontend/src/components/RecentListens.tsx b/frontend/src/components/RecentListens.tsx index 5246350..527cde3 100644 --- a/frontend/src/components/RecentListens.tsx +++ b/frontend/src/components/RecentListens.tsx @@ -1,9 +1,11 @@ -import React, { useState, useEffect } from "react"; -import { useAuth } from "../hooks/use-auth"; -import { Listen } from "../api/entities/listen"; -import { getRecentListens } from "../api/api"; +import { format, formatDistanceToNow } from "date-fns"; +import React, { useEffect, useState } from "react"; import { Redirect } from "react-router-dom"; -import { formatDistanceToNow } from "date-fns"; +import { getRecentListens } from "../api/api"; +import { Listen } from "../api/entities/listen"; +import { useAuth } from "../hooks/use-auth"; +import { ReloadIcon } from "../icons/Reload"; +import { getPaginationItems } from "../util/getPaginationItems"; const LISTENS_PER_PAGE = 15; @@ -15,66 +17,120 @@ export const RecentListens: React.FC = () => { const [listens, setListens] = useState([]); const [isLoading, setIsLoading] = useState(true); - useEffect(() => { - (async () => { - setIsLoading(true); + const loadListensForPage = async () => { + setIsLoading(true); - try { - const listensFromApi = await getRecentListens({ - page, - limit: LISTENS_PER_PAGE, - }); + try { + const listensFromApi = await getRecentListens({ + page, + limit: LISTENS_PER_PAGE, + }); - if (totalPages !== listensFromApi.meta.totalPages) { - setTotalPages(listensFromApi.meta.totalPages); - } - setListens(listensFromApi.items); - } catch (err) { - console.error("Error while fetching recent listens:", err); - } finally { - setIsLoading(false); + if (totalPages !== listensFromApi.meta.totalPages) { + setTotalPages(listensFromApi.meta.totalPages); } - })(); + setListens(listensFromApi.items); + } catch (err) { + console.error("Error while fetching recent listens:", err); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + loadListensForPage(); }, [user, page, totalPages]); if (!user) { return ; } - if (isLoading) { - return ( -
- Loading Listens + return ( +
+
+
+

Recent listens

+ +
+
+ {isLoading && ( +
+ Loading Listens +
+ )} + {listens.length === 0 && ( +
+

Could not find any listens!

+
+ )} + {listens.length > 0 && ( +
+ {listens.map((listen) => ( + + ))} +
+ )} +
+
- ); - } +
+ ); +}; + +const Pagination: React.FC<{ + page: number; + totalPages: number; + setPage: (newPage: number) => void; +}> = ({ page, totalPages, setPage }) => { + const disabledBtn = "opacity-50 cursor-default"; + const pageButtons = getPaginationItems(page, totalPages, 1); + + const isFirstPage = page === 1; + const isLastPage = page === totalPages; return ( -
-

Recent listens

-
- {listens.length === 0 && ( -
-

Could not find any listens!

+
+ + {pageButtons.map((buttonPage) => + buttonPage ? ( + + ) : ( +
+ ...
- )} - {listens.map((listen) => ( - - ))} -
-
-

Page: {page}

- {page !== 1 && ( -

- -

- )} - {page !== totalPages && ( -

- -

- )} -
+ ) + )} +
); }; @@ -85,9 +141,17 @@ const ListenItem: React.FC<{ listen: Listen }> = ({ listen }) => { const timeAgo = formatDistanceToNow(new Date(listen.playedAt), { addSuffix: true, }); + const dateTime = format(new Date(listen.playedAt), "PP p"); return ( -
- {trackName} - {artists} - {timeAgo} +
+
{trackName}
+
{artists}
+
+ {timeAgo} +
); }; diff --git a/frontend/src/icons/Reload.tsx b/frontend/src/icons/Reload.tsx new file mode 100644 index 0000000..c0bc2c0 --- /dev/null +++ b/frontend/src/icons/Reload.tsx @@ -0,0 +1,18 @@ +import React from "react"; + +export const ReloadIcon: React.FC> = (props) => { + return ( + + + + + + ); +}; diff --git a/frontend/src/util/getPaginationItems.ts b/frontend/src/util/getPaginationItems.ts new file mode 100644 index 0000000..0b6a232 --- /dev/null +++ b/frontend/src/util/getPaginationItems.ts @@ -0,0 +1,29 @@ +export const getPaginationItems = ( + currentPage: number, + totalPages: number, + delta: number = 1 +): (number | null)[] => { + const left = currentPage - delta; + const right = currentPage + delta; + + const range = Array.from(Array(totalPages)) + .map((e, i) => i + 1) + .filter((i) => i === 1 || i === totalPages || (i >= left && i <= right)) + .reduce((pages: (number | null)[], page, i) => { + if (pages.length !== 0) { + const prevPage = pages[pages.length - 1]; + if (prevPage !== null) { + const diff = page - prevPage; + if (diff > 1) { + pages.push(null); + } + } + } + + pages.push(page); + + return pages; + }, []); + + return range; +};