@@ -38,10 +43,14 @@ export const NavBar: React.FC = () => {
const NavUserInfo: React.FC<{ user: User }> = ({ user }) => {
return (
-
+
{user.displayName}
{user.photo && (
-

+

)}
);
diff --git a/frontend/src/components/RecentListens.tsx b/frontend/src/components/RecentListens.tsx
new file mode 100644
index 0000000..5246350
--- /dev/null
+++ b/frontend/src/components/RecentListens.tsx
@@ -0,0 +1,93 @@
+import React, { useState, useEffect } from "react";
+import { useAuth } from "../hooks/use-auth";
+import { Listen } from "../api/entities/listen";
+import { getRecentListens } from "../api/api";
+import { Redirect } from "react-router-dom";
+import { formatDistanceToNow } from "date-fns";
+
+const LISTENS_PER_PAGE = 15;
+
+export const RecentListens: React.FC = () => {
+ const { user } = useAuth();
+
+ const [page, setPage] = useState(1);
+ const [totalPages, setTotalPages] = useState(1);
+ const [listens, setListens] = useState
([]);
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ (async () => {
+ setIsLoading(true);
+
+ 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);
+ }
+ })();
+ }, [user, page, totalPages]);
+
+ if (!user) {
+ return ;
+ }
+
+ if (isLoading) {
+ return (
+
+ Loading Listens
+
+ );
+ }
+
+ return (
+
+
Recent listens
+
+ {listens.length === 0 && (
+
+
Could not find any listens!
+
+ )}
+ {listens.map((listen) => (
+
+ ))}
+
+
+
Page: {page}
+ {page !== 1 && (
+
+
+
+ )}
+ {page !== totalPages && (
+
+
+
+ )}
+
+
+ );
+};
+
+const ListenItem: React.FC<{ listen: Listen }> = ({ listen }) => {
+ const trackName = listen.track.name;
+ const artists = listen.track.artists.map((artist) => artist.name).join(", ");
+ const timeAgo = formatDistanceToNow(new Date(listen.playedAt), {
+ addSuffix: true,
+ });
+ return (
+
+ {trackName} - {artists} - {timeAgo}
+
+ );
+};
diff --git a/frontend/src/hooks/use-auth.tsx b/frontend/src/hooks/use-auth.tsx
index 8d926d7..8499c37 100644
--- a/frontend/src/hooks/use-auth.tsx
+++ b/frontend/src/hooks/use-auth.tsx
@@ -1,6 +1,6 @@
import React, { createContext, useContext, useEffect, useState } from "react";
import { getUsersMe, UnauthenticatedError } from "../api/api";
-import { User } from "../api/user";
+import { User } from "../api/entities/user";
const authContext = createContext(
(undefined as any) as AuthContext
diff --git a/frontend/src/logo.svg b/frontend/src/logo.svg
deleted file mode 100644
index 6b60c10..0000000
--- a/frontend/src/logo.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-