Skip to content

Commit

Permalink
feat: add visit card components and improve navbar styling
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Patek committed Feb 20, 2025
1 parent 9b8d6d7 commit 85f18e1
Show file tree
Hide file tree
Showing 27 changed files with 452 additions and 208 deletions.
1 change: 1 addition & 0 deletions actions/checkAuth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use server";

import { auth } from "@/auth";
import { User } from "next-auth";

Expand Down
31 changes: 21 additions & 10 deletions actions/favourites/favourites.action.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use server";
import { collection, deleteDoc, doc, getDoc, getDocs, query, serverTimestamp, setDoc, where } from "firebase/firestore";

import { collection, deleteDoc, doc, getDoc, getDocs, query, serverTimestamp, setDoc, where } from "firebase/firestore";
import { checkAuth } from "@/actions/checkAuth";
import { db } from "@/utils/firebase";
import { unstable_cache as cache, revalidateTag } from "next/cache";
import { CacheTag, getCacheTagUserSpecific } from "@/utils/cacheTags";
import { CacheTag, getCacheTagSpecific, getCacheTagUserSpecific } from "@/utils/cacheTags";

export const checkFavourite = async (towerID: string) => {
const user = await checkAuth();
Expand Down Expand Up @@ -33,6 +33,7 @@ export const addToFavourites = async (towerID: string) => {
tower_id: towerID,
});
revalidateTag(getCacheTagUserSpecific(CacheTag.TowerFavourite, user.id, towerID));
revalidateTag(getCacheTagSpecific(CacheTag.UserFavourites, user.id));
return true;
};

Expand All @@ -41,18 +42,28 @@ export const removeFromFavourites = async (towerID: string) => {
if (!user) return false;
await deleteDoc(doc(db, "favourites", `${user.id}_${towerID}`));
revalidateTag(getCacheTagUserSpecific(CacheTag.TowerFavourite, user.id, towerID));
revalidateTag(getCacheTagSpecific(CacheTag.UserFavourites, user.id));
return false;
};

export const getAllUserFavouritesIds = async () => {
//todo add cache
const user = await checkAuth();
if (!user) return [];
const q = query(collection(db, "favourites"), where("user_id", "==", user.id));
const querySnapshot = await getDocs(q);
const favourites = [];
querySnapshot.forEach((doc) => {
favourites.push(doc.data().tower_id);
});
return favourites;

const cachedFn = cache(
async (userID: string) => {
const q = query(collection(db, "favourites"), where("user_id", "==", userID));
const querySnapshot = await getDocs(q);
const favourites = [];
querySnapshot.forEach((doc) => {
favourites.push(doc.data().tower_id);
});
return favourites;
},
[CacheTag.UserFavourites],
{
tags: [getCacheTagSpecific(CacheTag.UserFavourites, user.id)],
}
);
return cachedFn(user.id);
};
2 changes: 1 addition & 1 deletion actions/members/members.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const getAllMembers = async () => {
//get changes made by each user
await Promise.all(
users.map(async (user) => {
const q = query(collection(db, "changes"), where("userID", "==", user.id));
const q = query(collection(db, "changes"), where("user_id", "==", user.id));
const snap = await getCountFromServer(q);
user.changes = snap.data().count;
})
Expand Down
27 changes: 18 additions & 9 deletions actions/ratings/ratings.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,24 @@ export const removeRating = async (towerID: string) => {
};

export const getAllUserRatings = async () => {
//todo add cache
const user = await checkAuth();
if (!user) return [];
const q = query(collection(db, "ratings"), where("user_id", "==", user.id));
const querySnapshot = await getDocs(q);
const ratings: Rating[] = [];
querySnapshot.forEach((doc) => {
const data = doc.data();
ratings.push({ ...data, created: (data.created as Timestamp).toDate().toISOString() } as Rating);
});
return ratings;

const cachedFn = cache(
async (userID: string) => {
const q = query(collection(db, "ratings"), where("user_id", "==", userID));
const querySnapshot = await getDocs(q);
const ratings: Rating[] = [];
querySnapshot.forEach((doc) => {
const data = doc.data();
ratings.push({ ...data, created: (data.created as Timestamp).toDate().toISOString() } as Rating);
});
return ratings;
},
[CacheTag.UserRatings],
{
tags: [CacheTag.UserRatings, getCacheTagSpecific(CacheTag.UserRatings, user.id)],
}
);
return cachedFn(user.id);
};
42 changes: 33 additions & 9 deletions actions/visits/visits.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,41 @@ export const removeVisit = async (towerID: string) => {
};

export const getAllUserVisits = async (): Promise<Visit[]> => {
//todo add cache
const user = await checkAuth();
if (!user) return [];
const visits: Visit[] = [];
const q = await query(collection(db, "visits"), where("user_id", "==", user.id));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
const data = doc.data();
visits.push({ ...data, date: new Date(data.date).toISOString(), created: (data.created as Timestamp).toDate().toISOString() } as Visit);
});
return visits;

const cacheFn = cache(
async (userID: string) => {
const visits: Visit[] = [];
const q = await query(collection(db, "visits"), where("user_id", "==", userID), orderBy("date", "desc"));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
const data = doc.data();
visits.push({
...data,
date: new Date(data.date).toISOString(),
created: (data.created as Timestamp).toDate().toISOString(),
} as Visit);
});
// get photos for each visit
const allPhotoIds = visits.reduce((acc: string[], visit) => {
if (visit.photoIds) {
acc.push(...visit.photoIds);
}
return acc;
}, []);
const photos = await getPhotos(allPhotoIds);
visits.forEach((visit) => {
visit.photos = visit.photoIds ? visit.photoIds.map((id) => photos.find((p) => p.id === id)) : [];
});
return visits;
},
[CacheTag.UserVisits],
{
tags: [getCacheTagSpecific(CacheTag.UserVisits, user.id)],
}
);
return cacheFn(user.id);
};

export const getTowerVisits = async (towerID: string): Promise<Visit[]> => {
Expand Down
44 changes: 0 additions & 44 deletions app/(with-navbar)/(authenticated)/profil/TabsAndContent.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { getAllUserFavouritesIds } from "@/actions/favourites/favourites.action";
import { getAllUserRatings } from "@/actions/ratings/ratings.action";
import { getTowersByIDs } from "@/actions/towers/towers.action";
import { getAllUserVisits } from "@/actions/visits/visits.action";
import ProfileVisits from "@/components/profile/ProfileVisits";
import VisitsStats from "@/components/profile/visit-card/VisitsStats";
import { Metadata } from "next";

export const metadata: Metadata = {
title: "Navštívené rozhledny",
};

const VisitedTowersPage = async () => {
const promises = [getAllUserFavouritesIds(), getAllUserVisits(), getAllUserRatings()];
const [favouritesIds, visits, ratings] = await Promise.all(promises);
const towerIds = [...favouritesIds, ...visits.map((visit) => visit.tower_id), ...ratings.map((rating) => rating.tower_id)];
const uniqueTowerIds = Array.from(new Set(towerIds));
const towers = await getTowersByIDs(uniqueTowerIds);

return (
<div className="flex flex-col my-8 gap-5 max-w-[calc(min(99dvw,80rem))] px-3 xl:px-0 m-auto">
<article className="prose max-w-max px-3">
<h1 className="text-2xl sm:text-3xl lg:text-4xl">Moje navštívené rozhledny</h1>
<p className="text-sm sm:text-base lg:text-lg">
Zde najdete seznam všech rozhleden, které jste navštívili. Pokud jste nějakou rozhlednu navštívili, ale není zde uvedena, můžete
si návštěvu přidat na stránce dané rozhledny.
</p>
</article>
<VisitsStats visits={visits} towers={towers} />
<ProfileVisits visits={visits} towers={towers} ratings={ratings} />
</div>
);
};

export default VisitedTowersPage;
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import ProfileBox from "./ProfileBox";
import TabsAndContent from "./TabsAndContent";
import { getAllUserFavouritesIds } from "@/actions/favourites/favourites.action";
import { getAllUserVisits } from "@/actions/visits/visits.action";
import { getAllUserRatings } from "@/actions/ratings/ratings.action";
import { getTowersByIDs } from "@/actions/towers/towers.action";
import ProfileMapFixed from "@/components/shared/map/ProfileMapFixed";
import { Metadata } from "next";

export const metadata: Metadata = {
title: "Profil",
};

async function ProfilePage() {
const promises = [getAllUserFavouritesIds(), getAllUserVisits(), getAllUserRatings()];
Expand All @@ -14,14 +18,13 @@ async function ProfilePage() {
const towers = await getTowersByIDs(uniqueTowerIds);

return (
<div className="flex flex-col items-center gap-3 mt-3">
<div className="flex max-w-[calc(min(99vw,80rem))] w-full items-center sm:items-start justify-center flex-col sm:flex-row sm:h-[687px] gap-3">
<div className="flex flex-col items-center gap-3 mt-3 max-w-[calc(min(99vw,80rem))] m-auto">
<div className="flex w-full items-center sm:items-start justify-center flex-col sm:flex-row sm:h-[687px] gap-3">
<ProfileBox score={visits.length} changes={0} favs={favouritesIds.length} ratings={ratings.length} visits={visits.length} />
<div className="flex h-[250px] w-[97vw] flex-grow sm:h-full">
<ProfileMapFixed towers={towers} visits={visits} favourites={favouritesIds} />
</div>
</div>
<TabsAndContent visits={visits} favs={favouritesIds} towers={towers} ratings={ratings} />
</div>
);
}
Expand Down
5 changes: 5 additions & 0 deletions app/(with-navbar)/(with-footer)/rozhledny/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import Results from "@/components/towers/Results";
import ResultsSkeleton from "@/components/towers/ResultsSkeleton";
import { TowersSearchParams } from "@/types/TowersSearchParams";
import { TowersFilter } from "@/utils/TowersFilter";
import { Metadata } from "next";
import { Suspense } from "react";

export const metadata: Metadata = {
title: "Rozhledny",
};

const PER_PAGE = 20;

async function TowersPage(props: { searchParams?: Promise<TowersSearchParams> }) {
Expand Down
6 changes: 4 additions & 2 deletions app/(with-navbar)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ export default async function RootLayout({ children }: { children: React.ReactNo
return (
<>
<NavbarDrawer>
<Navbar />
{children}
<div className="flex flex-col min-h-[100dvh]">
<Navbar />
{children}
</div>
</NavbarDrawer>
</>
);
Expand Down
2 changes: 1 addition & 1 deletion components/footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import UserVisitLevels from "../shared/UserVisitLevels";

function Footer() {
return (
<footer className="footer flex justify-center p-10 bg-neutral text-neutral-content">
<footer className="footer flex justify-center p-10 bg-neutral text-neutral-content ">
<div className="flex justify-between flex-col md:flex-row gap-3 max-w-7xl w-full">
<div className="flex flex-col gap-3">
<div className="flex gap-2">
Expand Down
17 changes: 12 additions & 5 deletions components/navbar/NavbarDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,18 @@ const NavbarDrawer = async ({ children }: { children: React.ReactNode }) => {
<NavbarSideLink href="/mapa">Mapa</NavbarSideLink>
</li>
{session?.user && (
<li>
<NavbarSideLink href="/profil">Můj profil</NavbarSideLink>
</li>
<>
<li>
<NavbarSideLink href={"/navstivene"}>Navštívené rozhledny</NavbarSideLink>
</li>
<li>
<NavbarSideLink href="/profil">Můj profil</NavbarSideLink>
</li>
</>
)}

<ThemeChangerPhone />

{session?.user ? (
<li>
<form
Expand All @@ -35,7 +43,7 @@ const NavbarDrawer = async ({ children }: { children: React.ReactNode }) => {
}}
className="block"
>
<NavbarSideButton type="submit" className="w-full text-left">
<NavbarSideButton type="submit" className="w-full text-left text-xl">
Odhlásit se
</NavbarSideButton>
</form>
Expand All @@ -55,7 +63,6 @@ const NavbarDrawer = async ({ children }: { children: React.ReactNode }) => {
</form>
</li>
)}
<ThemeChangerPhone />
</ul>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion components/navbar/NavbarSideLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface NavbarSideLinkProps extends LinkProps {

const NavbarSideLink = ({ href, children }: NavbarSideLinkProps) => {
return (
<Link onClick={closeDrawer} href={href}>
<Link onClick={closeDrawer} href={href} className="text-xl">
{children}
</Link>
);
Expand Down
3 changes: 3 additions & 0 deletions components/navbar/ProfileIconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const ProfileIconButton = async () => {
)}

<ul tabIndex={0} className="menu dropdown-content p-2 shadow bg-base-100 rounded-box w-52 mt-4">
<li>
<Link href={"/navstivene"}>Navštívené rozhledny</Link>
</li>
<li>
<Link href={"/profil"}>Můj profil</Link>
</li>
Expand Down
2 changes: 1 addition & 1 deletion components/navbar/ThemeChangerPhone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function ThemeChangerPhone() {
closeDrawer();
}}
>
{currentTheme === LIGHT_MODE ? <div>Tmavý režim</div> : <div>Světlý režim</div>}
<div className="text-xl">{currentTheme === LIGHT_MODE ? "Tmavý režim" : "Světlý režim"}</div>
</li>
);
}
Expand Down
Loading

0 comments on commit 85f18e1

Please sign in to comment.