kemono2/client/src/pages/profile/announcements.tsx
2024-11-26 00:11:49 +01:00

109 lines
3.2 KiB
TypeScript

import { LoaderFunctionArgs, useLoaderData } from "react-router-dom";
import { Helmet } from "react-helmet-async";
import { ICONS_PREPEND, KEMONO_SITE, SITE_NAME } from "#env/env-vars";
import { fetchAnnouncements } from "#api/posts";
import { fetchArtistProfile } from "#api/profiles";
import { PageSkeleton } from "#components/pages";
import { CardList, DMCard } from "#components/cards";
import { ProfileHeader, Tabs, IArtistDetails } from "#entities/profiles";
import { paysites, validatePaysite } from "#entities/paysites";
import { IAnnouncement } from "#entities/posts";
interface IProps {
service: string;
profile: IArtistDetails;
announcements: IAnnouncement[];
}
export function AnnouncementsPage() {
const { service, profile, announcements } = useLoaderData() as IProps;
const paysite = paysites[service];
const title = `Announcements of "${profile.name}" from ${paysite.title}`;
const heading = "Announcements";
return (
<PageSkeleton name="user" title={title} heading={heading}>
<Helmet>
<meta name="id" content={profile.id} />
<meta name="service" content={service} />
<meta name="artist_name" content={profile.name} />
{/* <link rel="canonical" href="{{ g.canonical_url }}" /> */}
<meta property="og:title" content={title} />
<meta property="og:type" content="website" />
<meta property="og:site_name" content={SITE_NAME} />
<meta
property="og:image"
content={`${ICONS_PREPEND ?? KEMONO_SITE}/icons/${service}/${
profile.id
}`}
/>
{/* <meta property="og:url" content="{{ g.canonical_url }}" /> */}
</Helmet>
<ProfileHeader
service={service}
profileID={profile.id}
profileName={profile.name}
/>
<div className="paginator" id="paginator-top">
<Tabs
currentPage="announcements"
service={service}
artistID={profile.id}
/>
</div>
<CardList layout="phone">
{!announcements.length ? (
<div className="no-results">
<h2 className="site-section__subheading">
Nobody here but us chickens!
</h2>
<p className="subtitle">
There are no Announcements for your query.
</p>
</div>
) : (
announcements.map((announcement) => (
<DMCard
key={announcement.hash}
// @ts-expect-error The original template used it like this
// TODO: proper announcement card component
dm={announcement}
/>
))
)}
</CardList>
</PageSkeleton>
);
}
export async function loader({ params }: LoaderFunctionArgs): Promise<IProps> {
const service = params.service?.trim();
{
if (!service) {
throw new Error("Service name is required.");
}
validatePaysite(service);
}
const profileID = params.creator_id?.trim();
{
if (!profileID) {
throw new Error("Artist ID is required.");
}
}
const profile = await fetchArtistProfile(service, profileID);
const announcements = await fetchAnnouncements(service, profileID);
return {
service,
profile,
announcements,
};
}