feat(frontend): style recent listens page

This commit is contained in:
Julian Tölle 2020-05-05 02:52:59 +02:00
parent 75d3e2edbd
commit 1d5cefb447
3 changed files with 165 additions and 54 deletions

View file

@ -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<Listen[]>([]);
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 <Redirect to="/" />;
}
if (isLoading) {
return (
<div>
<span>Loading Listens</span>
return (
<div className="lg:flex lg:justify-center p-4">
<div className="lg:flex-shrink-0 min-w-full lg:min-w-0 lg:w-2/3 max-w-screen-lg">
<div className="flex justify-between">
<p className="text-2xl font-normal text-gray-700">Recent listens</p>
<button
className="flex-shrink-0 mx-2 bg-transparent hover:bg-green-500 text-green-500 hover:text-white font-semibold py-2 px-4 border border-green-500 hover:border-transparent rounded"
onClick={loadListensForPage}
>
<ReloadIcon className="w-5 h-5 fill-current" />
</button>
</div>
<div>
{isLoading && (
<div>
<span>Loading Listens</span>
</div>
)}
{listens.length === 0 && (
<div>
<p>Could not find any listens!</p>
</div>
)}
{listens.length > 0 && (
<div className="table-auto my-2 w-full text-gray-700">
{listens.map((listen) => (
<ListenItem listen={listen} />
))}
</div>
)}
</div>
<Pagination page={page} totalPages={totalPages} setPage={setPage} />
</div>
);
}
</div>
);
};
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 (
<div>
<p>Recent listens</p>
<div>
{listens.length === 0 && (
<div>
<p>Could not find any listens!</p>
<div className="flex justify-center">
<button
className={`${
isFirstPage ? disabledBtn : "hover:bg-gray-400"
} bg-gray-300 text-gray-700 font-bold py-2 px-4 rounded-l`}
onClick={() => setPage(page - 1)}
disabled={isFirstPage}
>
Prev
</button>
{pageButtons.map((buttonPage) =>
buttonPage ? (
<button
className={`${
buttonPage === page
? "bg-green-300 hover:bg-green-400"
: "bg-gray-300 hover:bg-gray-400"
} text-gray-700 font-bold py-2 px-4`}
onClick={() => setPage(buttonPage)}
>
{buttonPage}
</button>
) : (
<div className="opacity-50 cursor-default bg-gray-300 text-gray-700 font-bold py-2 px-4 rounded-l">
...
</div>
)}
{listens.map((listen) => (
<ListenItem listen={listen} />
))}
</div>
<div>
<p>Page: {page}</p>
{page !== 1 && (
<p>
<button onClick={() => setPage(page - 1)}>Previous Page</button>
</p>
)}
{page !== totalPages && (
<p>
<button onClick={() => setPage(page + 1)}>Next Page</button>
</p>
)}
</div>
)
)}
<button
className={`${
isLastPage ? disabledBtn : "hover:bg-gray-400"
} bg-gray-300 text-gray-700 font-bold py-2 px-4 rounded-r`}
onClick={() => setPage(page + 1)}
disabled={isLastPage}
>
Next
</button>
</div>
);
};
@ -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 (
<div>
{trackName} - {artists} - {timeAgo}
<div className="hover:bg-gray-100 border-b border-gray-200 lg:flex lg:justify-around text-gray-700 px-4 py-2">
<div className="lg:w-1/3 font-bold">{trackName}</div>
<div className=" lg:w-1/3">{artists}</div>
<div
className=" lg:w-1/6 text-gray-500 font-thin text-sm"
title={dateTime}
>
{timeAgo}
</div>
</div>
);
};

View file

@ -0,0 +1,18 @@
import React from "react";
export const ReloadIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
x="0"
y="0"
viewBox="0 0 65 65"
fill="#fff"
{...props}
>
<g fill="fill">
<path d="M32.5 4.999a27.31 27.31 0 00-14.699 4.282l-5.75-5.75v16.11h16.11l-6.395-6.395a21.834 21.834 0 0110.734-2.82c12.171 0 22.073 9.902 22.073 22.074 0 2.899-.577 5.664-1.599 8.202l4.738 2.762A27.299 27.299 0 0060 32.5C60 17.336 47.663 4.999 32.5 4.999zM43.227 51.746c-3.179 1.786-6.826 2.827-10.726 2.827-12.171 0-22.073-9.902-22.073-22.073 0-2.739.524-5.35 1.439-7.771l-4.731-2.851A27.34 27.34 0 005 32.5C5 47.664 17.336 60 32.5 60c5.406 0 10.434-1.584 14.691-4.289l5.758 5.759V45.358H36.838l6.389 6.388z"></path>
</g>
</svg>
);
};

View file

@ -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;
};