47 lines
1.2 KiB
TypeScript
47 lines
1.2 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { getJSON, type Resource } from "../api";
|
|
import { ResourceCard } from "../components/ResourceCard";
|
|
import { readFavorites } from "../favorites";
|
|
import { useI18n } from "../i18n";
|
|
|
|
export function FavoritesPage() {
|
|
const { t, lang } = useI18n();
|
|
const [items, setItems] = useState<Resource[]>([]);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
(async () => {
|
|
const ids = readFavorites();
|
|
const out: Resource[] = [];
|
|
for (const id of ids) {
|
|
try {
|
|
const r = await getJSON<Resource>(
|
|
`/api/resources/${id}?lang=${encodeURIComponent(lang)}`,
|
|
);
|
|
out.push(r);
|
|
} catch {
|
|
// ignore missing
|
|
}
|
|
}
|
|
if (!cancelled) setItems(out);
|
|
})();
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [lang]);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<h1 className="text-2xl font-bold">{t("favorites")}</h1>
|
|
{items.length === 0 ? (
|
|
<p className="text-neutral-400">{t("favoritesEmpty")}</p>
|
|
) : null}
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
{items.map((r) => (
|
|
<ResourceCard key={r.id} r={r} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|