sendou.ink/app/features/badges/routes/badges.tsx
Kalle 7f9c9f25fb
Homemade badges (#1894)
* Initial

* Author info

* Add docs
2024-09-29 13:49:27 +03:00

124 lines
3.3 KiB
TypeScript

import type { SerializeFrom } from "@remix-run/node";
import { Link, NavLink, Outlet, useLoaderData } from "@remix-run/react";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { Badge } from "~/components/Badge";
import { Divider } from "~/components/Divider";
import { Input } from "~/components/Input";
import { Main } from "~/components/Main";
import { SearchIcon } from "~/components/icons/Search";
import { useUser } from "~/features/auth/core/user";
import type { SendouRouteHandle } from "~/utils/remix";
import { BADGES_PAGE, FAQ_PAGE, navIconUrl } from "~/utils/urls";
import * as BadgeRepository from "../BadgeRepository.server";
import "~/styles/badges.css";
export const handle: SendouRouteHandle = {
i18n: "badges",
breadcrumb: () => ({
imgPath: navIconUrl("badges"),
href: BADGES_PAGE,
type: "IMAGE",
}),
};
export type BadgesLoaderData = SerializeFrom<typeof loader>;
export const loader = async () => {
return { badges: await BadgeRepository.all() };
};
export default function BadgesPageLayout() {
const { t } = useTranslation(["badges"]);
const data = useLoaderData<typeof loader>();
const user = useUser();
const [inputValue, setInputValue] = React.useState("");
const { ownBadges: allOwnBadges, otherBadges: allOtherBadges } = splitBadges(
data.badges,
user,
);
const inputValueNormalized = inputValue.toLowerCase();
const ownBadges = allOwnBadges.filter(
(b) =>
!inputValueNormalized ||
b.displayName.toLowerCase().includes(inputValueNormalized),
);
const otherBadges = allOtherBadges.filter(
(b) =>
!inputValueNormalized ||
b.displayName.toLowerCase().includes(inputValueNormalized),
);
return (
<Main>
<div className="badges__container">
<Outlet />
<Input
className="badges-search__input"
icon={<SearchIcon className="badges-search__icon" />}
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
{ownBadges.length > 0 ? (
<div className="w-full">
<Divider smallText>{t("badges:own.divider")}</Divider>
<div className="badges__small-badges">
{ownBadges.map((badge) => (
<NavLink
className="badges__nav-link"
key={badge.id}
to={String(badge.id)}
>
<Badge badge={badge} size={64} isAnimated={false} />
</NavLink>
))}
</div>
</div>
) : null}
<div className="w-full">
<div className="badges__small-badges">
{ownBadges.length > 0 ? (
<Divider smallText>{t("badges:other.divider")}</Divider>
) : null}
{otherBadges.map((badge) => (
<NavLink
className="badges__nav-link"
key={badge.id}
to={String(badge.id)}
>
<Badge badge={badge} size={64} isAnimated={false} />
</NavLink>
))}
</div>
</div>
</div>
<div className="badges__general-info-texts">
<p>
<Link to={FAQ_PAGE}>{t("forYourEvent")}</Link>
</p>
</div>
</Main>
);
}
function splitBadges(
badges: BadgesLoaderData["badges"],
user: ReturnType<typeof useUser>,
) {
const ownBadges: BadgesLoaderData["badges"] = [];
const otherBadges: BadgesLoaderData["badges"] = [];
for (const badge of badges) {
if (user && badge.managers.includes(user?.id)) {
ownBadges.push(badge);
} else {
otherBadges.push(badge);
}
}
return { ownBadges, otherBadges };
}