import clsx from "clsx"; import { Suspense, useRef, useState } from "react"; import { useLoaderData, LoaderFunctionArgs, Await, useAsyncError, } from "react-router"; import { PAYSITE_LIST } from "#env/env-vars"; import { ARTISTS_OR_CREATORS_LOWERCASE, AVAILABLE_PAYSITE_LIST, } from "#env/derived-vars"; import { createArtistsPageURL } from "#lib/urls"; import { parseOffset } from "#lib/pagination"; import { PageSkeleton } from "#components/pages"; import { FooterAd, HeaderAd, SliderAd } from "#components/advs"; import { Paginator } from "#components/pagination"; import { CardList, ArtistCard } from "#components/cards"; import { ButtonSubmit, FormRouter, FormSection } from "#components/forms"; import { LoadingIcon } from "#components/loading"; import { getArtists } from "#entities/profiles"; import * as styles from "./profiles.module.scss"; interface IProps { results: ReturnType; query?: string; service?: string; sort_by?: ISortField; order?: "asc" | "desc"; offset?: number; true_count?: number; } const sortFields = [ "favorited", "indexed", "updated", "name", "service", ] as const; type ISortField = (typeof sortFields)[number]; function validateSortField(input: unknown): asserts input is ISortField { if (!sortFields.includes(input as ISortField)) { throw new Error(`Invalid sort field value "${input}".`); } } export function ArtistsPage() { const { results, query, service, sort_by, order, offset } = useLoaderData() as IProps; const title = "Artists"; const heading = "Artists"; return (
}> } resolve={results}> {(resolvedResult: Awaited) => ( { const url = createArtistsPageURL( offset, query, service, sort_by, order ); return String(url); }} /> )}
Loading creators... please wait!

} > }> {(resolvedResult: Awaited) => resolvedResult.artists.length === 0 ? (

No {ARTISTS_OR_CREATORS_LOWERCASE} found for your query.

) : ( resolvedResult.artists.map((artist) => ( )) ) }
}> } resolve={results}> {(resolvedResult: Awaited) => ( { const url = createArtistsPageURL( offset, query, service, sort_by, order ); return String(url); }} /> )}
); } interface ISearchFormProps extends Pick { } function SearchForm({ query, service, sort_by, order }: ISearchFormProps) { const sortRef = useRef(null); const timeoutRef = useRef(null); const [sortDirection, setSortDirection] = useState(order); const onSortChange = (e: React.MouseEvent) => { e.preventDefault(); setSortDirection(sortDirection === "asc" ? "desc" : "asc"); if (sortRef.current) { sortRef.current.value = sortDirection === "asc" ? "desc" : "asc"; sortRef.current.form?.requestSubmit(); } } const onSelectChange = (e: React.ChangeEvent) => e.currentTarget.form?.requestSubmit(); const onInputChange = (e: React.ChangeEvent) => { if (timeoutRef.current) clearTimeout(timeoutRef.current); const target = e.currentTarget as HTMLInputElement; timeoutRef.current = setTimeout(() => { if (target.form) target.form.requestSubmit(); }, 500); }; return ( {(state) => ( <>
)}
); } function CollectionError() { const error = useAsyncError(); console.error(error); return (

Failed to load artists.

Details {/* @ts-expect-error vague type definition */}

{error?.statusText || error?.message}

); } export async function loader({ request, }: LoaderFunctionArgs): Promise { const searchParams = new URL(request.url).searchParams; let offset: IProps["offset"] | undefined = undefined; { const inputOffset = searchParams.get("o")?.trim(); if (inputOffset) { offset = parseOffset(inputOffset); } } let query: IProps["query"] | undefined = searchParams.get("q")?.trim(); let sort_by: IProps["sort_by"] | undefined = undefined; { const inputValue = searchParams.get("sort_by")?.trim(); if (inputValue) { validateSortField(inputValue); sort_by = inputValue; } } let order_by: IProps["order"] | undefined = undefined; { const inputValue = searchParams.get("order")?.trim(); if (inputValue) { if (inputValue !== "asc" && inputValue !== "desc") { throw new Error(`Invalid order by field "${inputValue}".`); } order_by = inputValue; } } let service: IProps["service"] = undefined; { const inputValue = searchParams.get("service")?.trim(); if (inputValue) { if (!PAYSITE_LIST.includes(inputValue)) { throw new Error(`Unknown service "${inputValue}".`); } } service = inputValue; } const results = getArtists({ offset, order: order_by, service, sort_by, query, }); const pageProps = { results, sort_by, order: order_by, offset, service, query, } satisfies IProps; return pageProps; }