Upgrade to React Router 7 (#2681)

This commit is contained in:
Kalle 2025-12-29 19:21:11 +02:00 committed by GitHub
parent 6992fecdac
commit 81483de0db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
349 changed files with 3069 additions and 8112 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@ node_modules
/.cache* /.cache*
/build /build
/public/build /public/build
.react-router/
.env .env
translation-progress.md translation-progress.md

View File

@ -1,6 +1,6 @@
import { Link } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import type { GearType, Tables, UserWithPlusTier } from "~/db/tables"; import type { GearType, Tables, UserWithPlusTier } from "~/db/tables";
import { useUser } from "~/features/auth/core/user"; import { useUser } from "~/features/auth/core/user";
import type { BuildWeaponWithTop500Info } from "~/features/builds/builds-types"; import type { BuildWeaponWithTop500Info } from "~/features/builds/builds-types";

View File

@ -1,9 +1,9 @@
import * as React from "react";
import { import {
isRouteErrorResponse, isRouteErrorResponse,
useRevalidator, useRevalidator,
useRouteError, useRouteError,
} from "@remix-run/react"; } from "react-router";
import * as React from "react";
import { useLocation } from "react-use"; import { useLocation } from "react-use";
import { useUser } from "~/features/auth/core/user"; import { useUser } from "~/features/auth/core/user";
import { import {

View File

@ -1,5 +1,5 @@
import { useActionData } from "@remix-run/react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useActionData } from "react-router";
import type { Namespace } from "~/modules/i18n/resources.server"; import type { Namespace } from "~/modules/i18n/resources.server";
export function FormErrors({ namespace }: { namespace: Namespace }) { export function FormErrors({ namespace }: { namespace: Namespace }) {

View File

@ -1,7 +1,7 @@
import { type FetcherWithComponents, useFetcher } from "@remix-run/react";
import * as React from "react"; import * as React from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { type FetcherWithComponents, useFetcher } from "react-router";
import type { SendouButtonProps } from "~/components/elements/Button"; import type { SendouButtonProps } from "~/components/elements/Button";
import { SendouDialog } from "~/components/elements/Dialog"; import { SendouDialog } from "~/components/elements/Dialog";
import { useIsMounted } from "~/hooks/useIsMounted"; import { useIsMounted } from "~/hooks/useIsMounted";

View File

@ -1,7 +1,7 @@
import { useFetcher } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useFetcher } from "react-router";
import { Input } from "~/components/Input"; import { Input } from "~/components/Input";
import { Label } from "~/components/Label"; import { Label } from "~/components/Label";
import { SubmitButton } from "~/components/SubmitButton"; import { SubmitButton } from "~/components/SubmitButton";

View File

@ -1,6 +1,6 @@
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import type * as React from "react"; import type * as React from "react";
import { isRouteErrorResponse, useRouteError } from "react-router";
import { useHasRole } from "~/modules/permissions/hooks"; import { useHasRole } from "~/modules/permissions/hooks";
export const Main = ({ export const Main = ({

View File

@ -1,5 +1,5 @@
import { useNavigate } from "@remix-run/react";
import * as React from "react"; import * as React from "react";
import { useNavigate } from "react-router";
export function Redirect({ to }: { to: string }) { export function Redirect({ to }: { to: string }) {
const navigate = useNavigate(); const navigate = useNavigate();

View File

@ -1,7 +1,7 @@
import type { LinkProps } from "@remix-run/react";
import { NavLink } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import type * as React from "react"; import type * as React from "react";
import type { LinkProps } from "react-router";
import { NavLink } from "react-router";
export function SubNav({ export function SubNav({
children, children,

View File

@ -1,4 +1,4 @@
import { type FetcherWithComponents, useNavigation } from "@remix-run/react"; import { type FetcherWithComponents, useNavigation } from "react-router";
import { SendouButton, type SendouButtonProps } from "./elements/Button"; import { SendouButton, type SendouButtonProps } from "./elements/Button";
interface SubmitButtonProps extends SendouButtonProps { interface SubmitButtonProps extends SendouButtonProps {

View File

@ -1,10 +1,10 @@
import { Link, type LinkProps } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { import {
Button as ReactAriaButton, Button as ReactAriaButton,
type ButtonProps as ReactAriaButtonProps, type ButtonProps as ReactAriaButtonProps,
} from "react-aria-components"; } from "react-aria-components";
import { Link, type LinkProps } from "react-router";
import { assertUnreachable } from "~/utils/types"; import { assertUnreachable } from "~/utils/types";
import styles from "./Button.module.css"; import styles from "./Button.module.css";

View File

@ -1,4 +1,3 @@
import { useNavigate } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import type { ModalOverlayProps } from "react-aria-components"; import type { ModalOverlayProps } from "react-aria-components";
import { import {
@ -8,6 +7,7 @@ import {
Modal, Modal,
ModalOverlay, ModalOverlay,
} from "react-aria-components"; } from "react-aria-components";
import { useNavigate } from "react-router";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";
import { CrossIcon } from "~/components/icons/Cross"; import { CrossIcon } from "~/components/icons/Cross";
import styles from "./Dialog.module.css"; import styles from "./Dialog.module.css";

View File

@ -1,4 +1,3 @@
import { useFetcher } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import { format, sub } from "date-fns"; import { format, sub } from "date-fns";
import * as React from "react"; import * as React from "react";
@ -16,6 +15,7 @@ import {
SelectValue, SelectValue,
} from "react-aria-components"; } from "react-aria-components";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useFetcher } from "react-router";
import { useDebounce } from "react-use"; import { useDebounce } from "react-use";
import { SendouBottomTexts } from "~/components/elements/BottomTexts"; import { SendouBottomTexts } from "~/components/elements/BottomTexts";
import { SendouLabel } from "~/components/elements/Label"; import { SendouLabel } from "~/components/elements/Label";

View File

@ -1,4 +1,3 @@
import { useFetcher } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { import {
@ -15,6 +14,7 @@ import {
SelectValue, SelectValue,
} from "react-aria-components"; } from "react-aria-components";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useFetcher } from "react-router";
import { useDebounce } from "react-use"; import { useDebounce } from "react-use";
import { SendouBottomTexts } from "~/components/elements/BottomTexts"; import { SendouBottomTexts } from "~/components/elements/BottomTexts";
import { SendouLabel } from "~/components/elements/Label"; import { SendouLabel } from "~/components/elements/Label";

View File

@ -1,8 +1,8 @@
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver } from "@hookform/resolvers/standard-schema";
import { useFetcher } from "@remix-run/react";
import * as React from "react"; import * as React from "react";
import { type DefaultValues, FormProvider, useForm } from "react-hook-form"; import { type DefaultValues, FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useFetcher } from "react-router";
import type { z } from "zod/v4"; import type { z } from "zod/v4";
import { logger } from "~/utils/logger"; import { logger } from "~/utils/logger";
import type { ActionError } from "~/utils/remix.server"; import type { ActionError } from "~/utils/remix.server";

View File

@ -1,5 +1,5 @@
import { Link } from "@remix-run/react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import { usePatrons } from "~/hooks/swr"; import { usePatrons } from "~/hooks/swr";
import { import {
API_PAGE, API_PAGE,

View File

@ -1,6 +1,6 @@
import { useSearchParams } from "@remix-run/react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useSearchParams } from "react-router";
import { SendouDialog } from "~/components/elements/Dialog"; import { SendouDialog } from "~/components/elements/Dialog";
import { useIsMounted } from "~/hooks/useIsMounted"; import { useIsMounted } from "~/hooks/useIsMounted";
import { LOG_IN_URL, SENDOU_INK_DISCORD_URL } from "~/utils/urls"; import { LOG_IN_URL, SENDOU_INK_DISCORD_URL } from "~/utils/urls";

View File

@ -1,5 +1,5 @@
import { Link } from "@remix-run/react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import { SendouDialog } from "~/components/elements/Dialog"; import { SendouDialog } from "~/components/elements/Dialog";
import { navItems } from "~/components/layout/nav-items"; import { navItems } from "~/components/layout/nav-items";
import { useUser } from "~/features/auth/core/user"; import { useUser } from "~/features/auth/core/user";

View File

@ -1,8 +1,8 @@
import { useLocation, useMatches, useRevalidator } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { Button } from "react-aria-components"; import { Button } from "react-aria-components";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useLocation, useMatches, useRevalidator } from "react-router";
import { import {
NotificationItem, NotificationItem,
NotificationItemDivider, NotificationItemDivider,

View File

@ -1,5 +1,5 @@
import { Link } from "@remix-run/react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import { useUser } from "~/features/auth/core/user"; import { useUser } from "~/features/auth/core/user";
import { userPage } from "~/utils/urls"; import { userPage } from "~/utils/urls";
import { Avatar } from "../Avatar"; import { Avatar } from "../Avatar";

View File

@ -1,7 +1,7 @@
import { Link, useLocation, useMatches } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useLocation, useMatches } from "react-router";
import type { RootLoaderData } from "~/root"; import type { RootLoaderData } from "~/root";
import type { Breadcrumb, SendouRouteHandle } from "~/utils/remix.server"; import type { Breadcrumb, SendouRouteHandle } from "~/utils/remix.server";
import { SendouButton } from "../elements/Button"; import { SendouButton } from "../elements/Button";

View File

@ -1,5 +1,5 @@
import { useLocation } from "@remix-run/react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useLocation } from "react-router";
import { logger } from "../../utils/logger"; import { logger } from "../../utils/logger";
declare global { declare global {

View File

@ -1,7 +1,7 @@
import { RemixBrowser } from "@remix-run/react";
import i18next from "i18next"; import i18next from "i18next";
import { hydrateRoot } from "react-dom/client"; import { hydrateRoot } from "react-dom/client";
import { I18nextProvider } from "react-i18next"; import { I18nextProvider } from "react-i18next";
import { HydratedRouter } from "react-router/dom";
import { i18nLoader } from "./modules/i18n/loader"; import { i18nLoader } from "./modules/i18n/loader";
import { logger } from "./utils/logger"; import { logger } from "./utils/logger";
@ -17,7 +17,7 @@ i18nLoader()
hydrateRoot( hydrateRoot(
document, document,
<I18nextProvider i18n={i18next}> <I18nextProvider i18n={i18next}>
<RemixBrowser /> <HydratedRouter />
</I18nextProvider>, </I18nextProvider>,
), ),
) )

View File

@ -1,14 +1,11 @@
import { PassThrough } from "node:stream"; import { PassThrough } from "node:stream";
import { import { createReadableStreamFromReadable } from "@react-router/node";
createReadableStreamFromReadable,
type EntryContext,
} from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import { createInstance } from "i18next"; import { createInstance } from "i18next";
import { isbot } from "isbot"; import { isbot } from "isbot";
import cron from "node-cron"; import cron from "node-cron";
import { renderToPipeableStream } from "react-dom/server"; import { renderToPipeableStream } from "react-dom/server";
import { I18nextProvider, initReactI18next } from "react-i18next"; import { I18nextProvider, initReactI18next } from "react-i18next";
import { type EntryContext, ServerRouter } from "react-router";
import { config } from "~/modules/i18n/config"; // your i18n configuration file import { config } from "~/modules/i18n/config"; // your i18n configuration file
import { i18next } from "~/modules/i18n/i18next.server"; import { i18next } from "~/modules/i18n/i18next.server";
import { resources } from "./modules/i18n/resources.server"; import { resources } from "./modules/i18n/resources.server";
@ -22,7 +19,7 @@ export default async function handleRequest(
request: Request, request: Request,
responseStatusCode: number, responseStatusCode: number,
responseHeaders: Headers, responseHeaders: Headers,
remixContext: EntryContext, reactRouterContext: EntryContext,
) { ) {
const callbackName = isbot(request.headers.get("user-agent")) const callbackName = isbot(request.headers.get("user-agent"))
? "onAllReady" ? "onAllReady"
@ -30,7 +27,7 @@ export default async function handleRequest(
const instance = createInstance(); const instance = createInstance();
const lng = await i18next.getLocale(request); const lng = await i18next.getLocale(request);
const ns = i18next.getRouteNamespaces(remixContext); const ns = i18next.getRouteNamespaces(reactRouterContext);
await instance await instance
.use(initReactI18next) // Tell our instance to use react-i18next .use(initReactI18next) // Tell our instance to use react-i18next
@ -46,7 +43,7 @@ export default async function handleRequest(
const { pipe, abort } = renderToPipeableStream( const { pipe, abort } = renderToPipeableStream(
<I18nextProvider i18n={instance}> <I18nextProvider i18n={instance}>
<RemixServer context={remixContext} url={request.url} /> <ServerRouter context={reactRouterContext} url={request.url} />
</I18nextProvider>, </I18nextProvider>,
{ {
[callbackName]: () => { [callbackName]: () => {

View File

@ -1,4 +1,4 @@
import type { ActionFunctionArgs } from "@remix-run/node"; import type { ActionFunctionArgs } from "react-router";
import { z } from "zod/v4"; import { z } from "zod/v4";
import * as AdminRepository from "~/features/admin/AdminRepository.server"; import * as AdminRepository from "~/features/admin/AdminRepository.server";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { isImpersonating, requireUser } from "~/features/auth/core/user.server"; import { isImpersonating, requireUser } from "~/features/auth/core/user.server";
import * as UserRepository from "~/features/user-page/UserRepository.server"; import * as UserRepository from "~/features/user-page/UserRepository.server";
import { requireRole } from "~/modules/permissions/guards.server"; import { requireRole } from "~/modules/permissions/guards.server";

View File

@ -1,4 +1,5 @@
import type { MetaFunction } from "@remix-run/node"; import * as React from "react";
import type { MetaFunction } from "react-router";
import { import {
Form, Form,
Link, Link,
@ -6,8 +7,7 @@ import {
useLoaderData, useLoaderData,
useNavigation, useNavigation,
useSearchParams, useSearchParams,
} from "@remix-run/react"; } from "react-router";
import * as React from "react";
import { Avatar } from "~/components/Avatar"; import { Avatar } from "~/components/Avatar";
import { Catcher } from "~/components/Catcher"; import { Catcher } from "~/components/Catcher";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";

View File

@ -1,4 +1,4 @@
import type { ActionFunction, LoaderFunctionArgs } from "@remix-run/node"; import type { ActionFunction, LoaderFunctionArgs } from "react-router";
import * as UserRepository from "~/features/user-page/UserRepository.server"; import * as UserRepository from "~/features/user-page/UserRepository.server";
import { updatePatreonData } from "~/modules/patreon"; import { updatePatreonData } from "~/modules/patreon";
import { import {

View File

@ -1,4 +1,4 @@
import type { ActionFunction } from "@remix-run/node"; import type { ActionFunction } from "react-router";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { seed } from "~/db/seed"; import { seed } from "~/db/seed";
import { DANGEROUS_CAN_ACCESS_DEV_CONTROLS } from "~/features/admin/core/dev-controls"; import { DANGEROUS_CAN_ACCESS_DEV_CONTROLS } from "~/features/admin/core/dev-controls";

View File

@ -1,4 +1,4 @@
import type { ActionFunction } from "@remix-run/node"; import type { ActionFunction } from "react-router";
import * as UserRepository from "~/features/user-page/UserRepository.server"; import * as UserRepository from "~/features/user-page/UserRepository.server";
import { canAccessLohiEndpoint } from "~/utils/remix.server"; import { canAccessLohiEndpoint } from "~/utils/remix.server";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { db } from "~/db/sql"; import { db } from "~/db/sql";

View File

@ -1,5 +1,5 @@
import type { LoaderFunctionArgs } from "@remix-run/node";
import { jsonArrayFrom } from "kysely/helpers/sqlite"; import { jsonArrayFrom } from "kysely/helpers/sqlite";
import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { db } from "~/db/sql"; import { db } from "~/db/sql";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { SendouQ } from "~/features/sendouq/core/SendouQ.server"; import { SendouQ } from "~/features/sendouq/core/SendouQ.server";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import * as SQMatchRepository from "~/features/sendouq-match/SQMatchRepository.server"; import * as SQMatchRepository from "~/features/sendouq-match/SQMatchRepository.server";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { db } from "~/db/sql"; import { db } from "~/db/sql";

View File

@ -1,5 +1,5 @@
import type { LoaderFunctionArgs } from "@remix-run/node";
import { jsonArrayFrom } from "kysely/helpers/sqlite"; import { jsonArrayFrom } from "kysely/helpers/sqlite";
import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { db } from "~/db/sql"; import { db } from "~/db/sql";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { tournamentFromDB } from "~/features/tournament-bracket/core/Tournament.server"; import { tournamentFromDB } from "~/features/tournament-bracket/core/Tournament.server";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import type { Bracket } from "~/features/tournament-bracket/core/Bracket"; import type { Bracket } from "~/features/tournament-bracket/core/Bracket";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { db } from "~/db/sql"; import { db } from "~/db/sql";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import * as TournamentMatchRepository from "~/features/tournament-bracket/TournamentMatchRepository.server"; import * as TournamentMatchRepository from "~/features/tournament-bracket/TournamentMatchRepository.server";

View File

@ -1,5 +1,5 @@
import type { LoaderFunctionArgs } from "@remix-run/node";
import { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite"; import { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { db } from "~/db/sql"; import { db } from "~/db/sql";

View File

@ -1,5 +1,5 @@
import type { LoaderFunctionArgs } from "@remix-run/node";
import { jsonArrayFrom } from "kysely/helpers/sqlite"; import { jsonArrayFrom } from "kysely/helpers/sqlite";
import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { db } from "~/db/sql"; import { db } from "~/db/sql";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { identifierToUserIdQuery } from "~/features/user-page/UserRepository.server"; import { identifierToUserIdQuery } from "~/features/user-page/UserRepository.server";

View File

@ -1,5 +1,5 @@
import type { LoaderFunctionArgs } from "@remix-run/node";
import { jsonArrayFrom } from "kysely/helpers/sqlite"; import { jsonArrayFrom } from "kysely/helpers/sqlite";
import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors"; import { cors } from "remix-utils/cors";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { db } from "~/db/sql"; import { db } from "~/db/sql";

View File

@ -1,4 +1,4 @@
import type { ActionFunctionArgs } from "@remix-run/node"; import type { ActionFunctionArgs } from "react-router";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { refreshApiTokensCache } from "~/features/api-public/api-public-utils.server"; import { refreshApiTokensCache } from "~/features/api-public/api-public-utils.server";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";
import * as ApiRepository from "../ApiRepository.server"; import * as ApiRepository from "../ApiRepository.server";
import { checkUserHasApiAccess } from "../core/perms"; import { checkUserHasApiAccess } from "../core/perms";

View File

@ -1,6 +1,6 @@
import type { MetaFunction } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { useLoaderData } from "react-router";
import { CopyToClipboardPopover } from "~/components/CopyToClipboardPopover"; import { CopyToClipboardPopover } from "~/components/CopyToClipboardPopover";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";
import { FormMessage } from "~/components/FormMessage"; import { FormMessage } from "~/components/FormMessage";

View File

@ -1,14 +1,11 @@
import type { ActionFunction } from "@remix-run/node"; import type { FileUpload } from "@remix-run/form-data-parser";
import { import { parseFormData as parseMultipartFormData } from "@remix-run/form-data-parser";
unstable_composeUploadHandlers as composeUploadHandlers,
unstable_createMemoryUploadHandler as createMemoryUploadHandler,
unstable_parseMultipartFormData as parseMultipartFormData,
redirect,
} from "@remix-run/node";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import type { ActionFunction } from "react-router";
import { redirect } from "react-router";
import * as ArtRepository from "~/features/art/ArtRepository.server"; import * as ArtRepository from "~/features/art/ArtRepository.server";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";
import { s3UploadHandler } from "~/features/img-upload/s3.server"; import { uploadStreamToS3 } from "~/features/img-upload/s3.server";
import { notify } from "~/features/notifications/core/notify.server"; import { notify } from "~/features/notifications/core/notify.server";
import { requireRole } from "~/modules/permissions/guards.server"; import { requireRole } from "~/modules/permissions/guards.server";
import { dateToDatabaseTimestamp } from "~/utils/dates"; import { dateToDatabaseTimestamp } from "~/utils/dates";
@ -69,10 +66,26 @@ export const action: ActionFunction = async ({ request }) => {
}, },
}); });
} else { } else {
const uploadHandler = composeUploadHandlers( const preDecidedFilename = `art-${nanoid()}-${Date.now()}`;
s3UploadHandler(`art-${nanoid()}-${Date.now()}`),
createMemoryUploadHandler(), const uploadHandler = async (fileUpload: FileUpload) => {
); if (
fileUpload.fieldName === "img" ||
fileUpload.fieldName === "smallImg"
) {
const [, ending] = fileUpload.name.split(".");
invariant(ending);
const newFilename = `${preDecidedFilename}${fileUpload.fieldName === "smallImg" ? "-small" : ""}.${ending}`;
const uploadedFileLocation = await uploadStreamToS3(
fileUpload.stream(),
newFilename,
);
return uploadedFileLocation;
}
return null;
};
const formData = await parseMultipartFormData(request, uploadHandler); const formData = await parseMultipartFormData(request, uploadHandler);
const imgSrc = formData.get("img") as string | null; const imgSrc = formData.get("img") as string | null;
invariant(imgSrc); invariant(imgSrc);

View File

@ -1,7 +1,7 @@
import { Link } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import { Avatar } from "~/components/Avatar"; import { Avatar } from "~/components/Avatar";
import { LinkButton, SendouButton } from "~/components/elements/Button"; import { LinkButton, SendouButton } from "~/components/elements/Button";
import { SendouDialog } from "~/components/elements/Dialog"; import { SendouDialog } from "~/components/elements/Dialog";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";
import * as ArtRepository from "../ArtRepository.server"; import * as ArtRepository from "../ArtRepository.server";
import { NEW_ART_EXISTING_SEARCH_PARAM_KEY } from "../art-constants"; import { NEW_ART_EXISTING_SEARCH_PARAM_KEY } from "../art-constants";

View File

@ -1,5 +1,5 @@
import cachified from "@epic-web/cachified"; import cachified from "@epic-web/cachified";
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { cache, IN_MILLISECONDS, ttl } from "~/utils/cache.server"; import { cache, IN_MILLISECONDS, ttl } from "~/utils/cache.server";
import * as ArtRepository from "../ArtRepository.server"; import * as ArtRepository from "../ArtRepository.server";
import { FILTERED_TAG_KEY_SEARCH_PARAM_KEY } from "../art-constants"; import { FILTERED_TAG_KEY_SEARCH_PARAM_KEY } from "../art-constants";

View File

@ -1,9 +1,9 @@
import type { MetaFunction } from "@remix-run/node";
import { Form, useFetcher, useLoaderData } from "@remix-run/react";
import Compressor from "compressorjs"; import Compressor from "compressorjs";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { Form, useFetcher, useLoaderData } from "react-router";
import { Alert } from "~/components/Alert"; import { Alert } from "~/components/Alert";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";
import { SendouSwitch } from "~/components/elements/Switch"; import { SendouSwitch } from "~/components/elements/Switch";

View File

@ -1,9 +1,8 @@
import type { MetaFunction, SerializeFrom } from "@remix-run/node";
import type { ShouldRevalidateFunction } from "@remix-run/react";
import { useLoaderData, useSearchParams } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction, ShouldRevalidateFunction } from "react-router";
import { useLoaderData, useSearchParams } from "react-router";
import { AddNewButton } from "~/components/AddNewButton"; import { AddNewButton } from "~/components/AddNewButton";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";
import { SendouSwitch } from "~/components/elements/Switch"; import { SendouSwitch } from "~/components/elements/Switch";
@ -18,7 +17,7 @@ import { Label } from "~/components/Label";
import { Main } from "~/components/Main"; import { Main } from "~/components/Main";
import type { SendouRouteHandle } from "~/utils/remix.server"; import type { SendouRouteHandle } from "~/utils/remix.server";
import { artPage, navIconUrl, newArtPage } from "~/utils/urls"; import { artPage, navIconUrl, newArtPage } from "~/utils/urls";
import { metaTags } from "../../../utils/remix"; import { metaTags, type SerializeFrom } from "../../../utils/remix";
import { FILTERED_TAG_KEY_SEARCH_PARAM_KEY } from "../art-constants"; import { FILTERED_TAG_KEY_SEARCH_PARAM_KEY } from "../art-constants";
import { ArtGrid } from "../components/ArtGrid"; import { ArtGrid } from "../components/ArtGrid";
import { TagSelect } from "../components/TagSelect"; import { TagSelect } from "../components/TagSelect";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import invariant from "~/utils/invariant"; import invariant from "~/utils/invariant";
import { notFoundIfFalsy } from "~/utils/remix.server"; import { notFoundIfFalsy } from "~/utils/remix.server";
import { articleBySlug } from "../core/bySlug.server"; import { articleBySlug } from "../core/bySlug.server";

View File

@ -1,7 +1,7 @@
import type { MetaFunction, SerializeFrom } from "@remix-run/node";
import { Link, useLoaderData } from "@remix-run/react";
import Markdown from "markdown-to-jsx"; import Markdown from "markdown-to-jsx";
import * as React from "react"; import * as React from "react";
import type { MetaFunction } from "react-router";
import { Link, useLoaderData } from "react-router";
import { Main } from "~/components/Main"; import { Main } from "~/components/Main";
import invariant from "~/utils/invariant"; import invariant from "~/utils/invariant";
import type { SendouRouteHandle } from "~/utils/remix.server"; import type { SendouRouteHandle } from "~/utils/remix.server";
@ -11,7 +11,7 @@ import {
articlePreviewUrl, articlePreviewUrl,
navIconUrl, navIconUrl,
} from "~/utils/urls"; } from "~/utils/urls";
import { metaTags } from "../../../utils/remix"; import { metaTags, type SerializeFrom } from "../../../utils/remix";
import { loader } from "../loaders/a.$slug.server"; import { loader } from "../loaders/a.$slug.server";
export { loader }; export { loader };

View File

@ -1,6 +1,6 @@
import type { MetaFunction } from "@remix-run/node";
import { Link, useLoaderData } from "@remix-run/react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { Link, useLoaderData } from "react-router";
import { Main } from "~/components/Main"; import { Main } from "~/components/Main";
import type { SendouRouteHandle } from "~/utils/remix.server"; import type { SendouRouteHandle } from "~/utils/remix.server";
import { ARTICLES_MAIN_PAGE, articlePage, navIconUrl } from "~/utils/urls"; import { ARTICLES_MAIN_PAGE, articlePage, navIconUrl } from "~/utils/urls";

View File

@ -1,4 +1,4 @@
import { type ActionFunctionArgs, redirect } from "@remix-run/node"; import { type ActionFunctionArgs, redirect } from "react-router";
import { ASSOCIATION } from "~/features/associations/associations-constants"; import { ASSOCIATION } from "~/features/associations/associations-constants";
import { createNewAssociationSchema } from "~/features/associations/associations-schemas"; import { createNewAssociationSchema } from "~/features/associations/associations-schemas";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";

View File

@ -1,4 +1,4 @@
import type { ActionFunctionArgs } from "@remix-run/node"; import type { ActionFunctionArgs } from "react-router";
import { ASSOCIATION } from "~/features/associations/associations-constants"; import { ASSOCIATION } from "~/features/associations/associations-constants";
import { associationsPageActionSchema } from "~/features/associations/associations-schemas"; import { associationsPageActionSchema } from "~/features/associations/associations-schemas";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { requireUserId } from "~/features/auth/core/user.server"; import { requireUserId } from "~/features/auth/core/user.server";
import type { SerializeFrom } from "~/utils/remix"; import type { SerializeFrom } from "~/utils/remix";
import { parseSafeSearchParams } from "~/utils/remix.server"; import { parseSafeSearchParams } from "~/utils/remix.server";

View File

@ -1,6 +1,6 @@
import { Link, Outlet, useFetcher, useLoaderData } from "@remix-run/react";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, Outlet, useFetcher, useLoaderData } from "react-router";
import { useCopyToClipboard } from "react-use"; import { useCopyToClipboard } from "react-use";
import { AddNewButton } from "~/components/AddNewButton"; import { AddNewButton } from "~/components/AddNewButton";
import { Avatar } from "~/components/Avatar"; import { Avatar } from "~/components/Avatar";

View File

@ -1,6 +1,6 @@
import type { ActionFunction, LoaderFunction } from "@remix-run/node";
import { redirect } from "@remix-run/node";
import { isbot } from "isbot"; import { isbot } from "isbot";
import type { ActionFunction, LoaderFunction } from "react-router";
import { redirect } from "react-router";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { DANGEROUS_CAN_ACCESS_DEV_CONTROLS } from "~/features/admin/core/dev-controls"; import { DANGEROUS_CAN_ACCESS_DEV_CONTROLS } from "~/features/admin/core/dev-controls";
import * as UserRepository from "~/features/user-page/UserRepository.server"; import * as UserRepository from "~/features/user-page/UserRepository.server";

View File

@ -1,4 +1,4 @@
import { createCookieSessionStorage } from "@remix-run/node"; import { createCookieSessionStorage } from "react-router";
import { IS_E2E_TEST_RUN } from "~/utils/e2e"; import { IS_E2E_TEST_RUN } from "~/utils/e2e";
import invariant from "~/utils/invariant"; import invariant from "~/utils/invariant";

View File

@ -1,4 +1,4 @@
import { redirect } from "@remix-run/node"; import { redirect } from "react-router";
import type { Tables } from "~/db/tables"; import type { Tables } from "~/db/tables";
import { userIsBanned } from "~/features/ban/core/banned.server"; import { userIsBanned } from "~/features/ban/core/banned.server";
import * as UserRepository from "~/features/user-page/UserRepository.server"; import * as UserRepository from "~/features/user-page/UserRepository.server";

View File

@ -1,4 +1,4 @@
import { useMatches } from "@remix-run/react"; import { useMatches } from "react-router";
import type { RootLoaderData } from "~/root"; import type { RootLoaderData } from "~/root";
export function useUser() { export function useUser() {

View File

@ -1,5 +1,5 @@
import type { ActionFunction } from "@remix-run/node"; import type { ActionFunction } from "react-router";
import { redirect } from "@remix-run/node"; import { redirect } from "react-router";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";
import { notify } from "~/features/notifications/core/notify.server"; import { notify } from "~/features/notifications/core/notify.server";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import type { SerializeFrom } from "~/utils/remix"; import type { SerializeFrom } from "~/utils/remix";
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server"; import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
import { idObject } from "~/utils/zod"; import { idObject } from "~/utils/zod";

View File

@ -1,4 +1,4 @@
import type { SerializeFrom } from "@remix-run/node"; import type { SerializeFrom } from "~/utils/remix";
import * as BadgeRepository from "../BadgeRepository.server"; import * as BadgeRepository from "../BadgeRepository.server";
export type BadgesLoaderData = SerializeFrom<typeof loader>; export type BadgesLoaderData = SerializeFrom<typeof loader>;

View File

@ -1,5 +1,5 @@
import { Form, useMatches, useOutletContext } from "@remix-run/react";
import * as React from "react"; import * as React from "react";
import { Form, useMatches, useOutletContext } from "react-router";
import { Divider } from "~/components/Divider"; import { Divider } from "~/components/Divider";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";
import { SendouDialog } from "~/components/elements/Dialog"; import { SendouDialog } from "~/components/elements/Dialog";

View File

@ -1,6 +1,6 @@
import { Link, Outlet, useLoaderData } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { Link, Outlet, useLoaderData } from "react-router";
import { Badge } from "~/components/Badge"; import { Badge } from "~/components/Badge";
import { LinkButton } from "~/components/elements/Button"; import { LinkButton } from "~/components/elements/Button";
import { useHasPermission, useHasRole } from "~/modules/permissions/hooks"; import { useHasPermission, useHasRole } from "~/modules/permissions/hooks";

View File

@ -1,7 +1,7 @@
import type { MetaFunction } from "@remix-run/node";
import { NavLink, Outlet, useLoaderData } from "@remix-run/react";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { NavLink, Outlet, useLoaderData } from "react-router";
import { Badge } from "~/components/Badge"; import { Badge } from "~/components/Badge";
import { Divider } from "~/components/Divider"; import { Divider } from "~/components/Divider";
import { Input } from "~/components/Input"; import { Input } from "~/components/Input";

View File

@ -1,4 +1,4 @@
import { type LoaderFunctionArgs, redirect } from "@remix-run/node"; import { type LoaderFunctionArgs, redirect } from "react-router";
import * as AdminRepository from "~/features/admin/AdminRepository.server"; import * as AdminRepository from "~/features/admin/AdminRepository.server";
import { import {
IMPERSONATED_SESSION_KEY, IMPERSONATED_SESSION_KEY,

View File

@ -1,4 +1,4 @@
import { useLoaderData } from "@remix-run/react"; import { useLoaderData } from "react-router";
import { Main } from "~/components/Main"; import { Main } from "~/components/Main";
import { useTimeFormat } from "~/hooks/useTimeFormat"; import { useTimeFormat } from "~/hooks/useTimeFormat";
import { databaseTimestampToDate } from "~/utils/dates"; import { databaseTimestampToDate } from "~/utils/dates";

View File

@ -1,4 +1,4 @@
import { useSearchParams } from "@remix-run/react"; import { useSearchParams } from "react-router";
import { abilities } from "~/modules/in-game-lists/abilities"; import { abilities } from "~/modules/in-game-lists/abilities";
import type { import type {
Ability, Ability,

View File

@ -1,9 +1,8 @@
import type { MetaFunction } from "@remix-run/node";
import type { ShouldRevalidateFunction } from "@remix-run/react";
import { Link } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction, ShouldRevalidateFunction } from "react-router";
import { Link } from "react-router";
import { AbilitiesSelector } from "~/components/AbilitiesSelector"; import { AbilitiesSelector } from "~/components/AbilitiesSelector";
import { Ability } from "~/components/Ability"; import { Ability } from "~/components/Ability";
import Chart from "~/components/Chart"; import Chart from "~/components/Chart";

View File

@ -1,5 +1,5 @@
import { cachified } from "@epic-web/cachified"; import { cachified } from "@epic-web/cachified";
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import * as BuildRepository from "~/features/builds/BuildRepository.server"; import * as BuildRepository from "~/features/builds/BuildRepository.server";
import { i18next } from "~/modules/i18n/i18next.server"; import { i18next } from "~/modules/i18n/i18next.server";
import { cache, IN_MILLISECONDS, ttl } from "~/utils/cache.server"; import { cache, IN_MILLISECONDS, ttl } from "~/utils/cache.server";

View File

@ -1,5 +1,5 @@
import { cachified } from "@epic-web/cachified"; import { cachified } from "@epic-web/cachified";
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import * as BuildRepository from "~/features/builds/BuildRepository.server"; import * as BuildRepository from "~/features/builds/BuildRepository.server";
import { i18next } from "~/modules/i18n/i18next.server"; import { i18next } from "~/modules/i18n/i18next.server";
import { cache } from "~/utils/cache.server"; import { cache } from "~/utils/cache.server";

View File

@ -1,7 +1,7 @@
import type { MetaFunction, SerializeFrom } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { useLoaderData } from "react-router";
import { Ability } from "~/components/Ability"; import { Ability } from "~/components/Ability";
import { Main } from "~/components/Main"; import { Main } from "~/components/Main";
import type { SendouRouteHandle } from "~/utils/remix.server"; import type { SendouRouteHandle } from "~/utils/remix.server";
@ -11,7 +11,7 @@ import {
outlinedMainWeaponImageUrl, outlinedMainWeaponImageUrl,
weaponBuildPage, weaponBuildPage,
} from "~/utils/urls"; } from "~/utils/urls";
import { metaTags } from "../../../utils/remix"; import { metaTags, type SerializeFrom } from "../../../utils/remix";
import { loader } from "../loaders/builds.$slug.popular.server"; import { loader } from "../loaders/builds.$slug.popular.server";
export { loader }; export { loader };

View File

@ -1,6 +1,6 @@
import type { MetaFunction, SerializeFrom } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { useLoaderData } from "react-router";
import { Ability } from "~/components/Ability"; import { Ability } from "~/components/Ability";
import { WeaponImage } from "~/components/Image"; import { WeaponImage } from "~/components/Image";
import { Main } from "~/components/Main"; import { Main } from "~/components/Main";
@ -11,7 +11,7 @@ import {
outlinedMainWeaponImageUrl, outlinedMainWeaponImageUrl,
weaponBuildPage, weaponBuildPage,
} from "~/utils/urls"; } from "~/utils/urls";
import { metaTags } from "../../../utils/remix"; import { metaTags, type SerializeFrom } from "../../../utils/remix";
import { loader } from "../loaders/builds.$slug.stats.server"; import { loader } from "../loaders/builds.$slug.stats.server";
export { loader }; export { loader };

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { getUser } from "~/features/auth/core/user.server"; import { getUser } from "~/features/auth/core/user.server";
import { i18next } from "~/modules/i18n/i18next.server"; import { i18next } from "~/modules/i18n/i18next.server";
import { weaponIdToType } from "~/modules/in-game-lists/weapon-ids"; import { weaponIdToType } from "~/modules/in-game-lists/weapon-ids";

View File

@ -1,12 +1,12 @@
import type { MetaFunction, SerializeFrom } from "@remix-run/node"; import { nanoid } from "nanoid";
import * as React from "react";
import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { import {
type ShouldRevalidateFunction, type ShouldRevalidateFunction,
useLoaderData, useLoaderData,
useSearchParams, useSearchParams,
} from "@remix-run/react"; } from "react-router";
import { nanoid } from "nanoid";
import * as React from "react";
import { useTranslation } from "react-i18next";
import * as R from "remeda"; import * as R from "remeda";
import { BuildCard } from "~/components/BuildCard"; import { BuildCard } from "~/components/BuildCard";
import { LinkButton, SendouButton } from "~/components/elements/Button"; import { LinkButton, SendouButton } from "~/components/elements/Button";
@ -19,7 +19,7 @@ import { FireIcon } from "~/components/icons/Fire";
import { MapIcon } from "~/components/icons/Map"; import { MapIcon } from "~/components/icons/Map";
import { Main } from "~/components/Main"; import { Main } from "~/components/Main";
import { safeJSONParse } from "~/utils/json"; import { safeJSONParse } from "~/utils/json";
import { isRevalidation, metaTags } from "~/utils/remix"; import { isRevalidation, metaTags, type SerializeFrom } from "~/utils/remix";
import type { SendouRouteHandle } from "~/utils/remix.server"; import type { SendouRouteHandle } from "~/utils/remix.server";
import type { Unpacked } from "~/utils/types"; import type { Unpacked } from "~/utils/types";
import { import {

View File

@ -1,7 +1,7 @@
import type { MetaFunction } from "@remix-run/node";
import { Link } from "@remix-run/react";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { Link } from "react-router";
import { AddNewButton } from "~/components/AddNewButton"; import { AddNewButton } from "~/components/AddNewButton";
import { Image } from "~/components/Image"; import { Image } from "~/components/Image";
import { Main } from "~/components/Main"; import { Main } from "~/components/Main";

View File

@ -1,5 +1,5 @@
import type { ActionFunction } from "@remix-run/node"; import type { ActionFunction } from "react-router";
import { redirect } from "@remix-run/node"; import { redirect } from "react-router";
import { requireUserId } from "~/features/auth/core/user.server"; import { requireUserId } from "~/features/auth/core/user.server";
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server"; import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
import { import {

View File

@ -1,5 +1,5 @@
import type { ActionFunction } from "@remix-run/node"; import type { ActionFunction } from "react-router";
import { redirect } from "@remix-run/node"; import { redirect } from "react-router";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { requireUserId } from "~/features/auth/core/user.server"; import { requireUserId } from "~/features/auth/core/user.server";
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server"; import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";

View File

@ -1,5 +1,5 @@
import type { ActionFunction } from "@remix-run/node"; import type { ActionFunction } from "react-router";
import { redirect } from "@remix-run/node"; import { redirect } from "react-router";
import type { CalendarEventTag } from "~/db/tables"; import type { CalendarEventTag } from "~/db/tables";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";
import * as BadgeRepository from "~/features/badges/BadgeRepository.server"; import * as BadgeRepository from "~/features/badges/BadgeRepository.server";

View File

@ -1,4 +1,4 @@
import { type ActionFunctionArgs, redirect } from "@remix-run/node"; import { type ActionFunctionArgs, redirect } from "react-router";
import { requireUserId } from "~/features/auth/core/user.server"; import { requireUserId } from "~/features/auth/core/user.server";
import { calendarFiltersSearchParamsSchema } from "~/features/calendar/calendar-schemas"; import { calendarFiltersSearchParamsSchema } from "~/features/calendar/calendar-schemas";
import * as UserRepository from "~/features/user-page/UserRepository.server"; import * as UserRepository from "~/features/user-page/UserRepository.server";

View File

@ -1,8 +1,8 @@
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver } from "@hookform/resolvers/standard-schema";
import { useFetcher, useSearchParams } from "@remix-run/react";
import * as React from "react"; import * as React from "react";
import { FormProvider, useForm } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useFetcher, useSearchParams } from "react-router";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";
import { SendouDialog } from "~/components/elements/Dialog"; import { SendouDialog } from "~/components/elements/Dialog";
import { InputFormField } from "~/components/form/InputFormField"; import { InputFormField } from "~/components/form/InputFormField";

View File

@ -1,6 +1,6 @@
import { Link } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";
import { SendouPopover } from "~/components/elements/Popover"; import { SendouPopover } from "~/components/elements/Popover";
import { Flag } from "~/components/Flag"; import { Flag } from "~/components/Flag";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { requireUserId } from "~/features/auth/core/user.server"; import { requireUserId } from "~/features/auth/core/user.server";
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server"; import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
import { import {

View File

@ -1,5 +1,5 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { redirect } from "@remix-run/node"; import { redirect } from "react-router";
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server"; import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server"; import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
import { tournamentPage } from "~/utils/urls"; import { tournamentPage } from "~/utils/urls";

View File

@ -1,5 +1,5 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { redirect } from "@remix-run/node"; import { redirect } from "react-router";
import * as R from "remeda"; import * as R from "remeda";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";
import * as BadgeRepository from "~/features/badges/BadgeRepository.server"; import * as BadgeRepository from "~/features/badges/BadgeRepository.server";

View File

@ -1,5 +1,5 @@
import type { LoaderFunctionArgs } from "@remix-run/node";
import { add, sub } from "date-fns"; import { add, sub } from "date-fns";
import type { LoaderFunctionArgs } from "react-router";
import type { UserPreferences } from "~/db/tables"; import type { UserPreferences } from "~/db/tables";
import { getUser } from "~/features/auth/core/user.server"; import { getUser } from "~/features/auth/core/user.server";
import { DAYS_SHOWN_AT_A_TIME } from "~/features/calendar/calendar-constants"; import { DAYS_SHOWN_AT_A_TIME } from "~/features/calendar/calendar-constants";

View File

@ -1,4 +1,4 @@
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import { parseSearchParams } from "~/utils/remix.server"; import { parseSearchParams } from "~/utils/remix.server";
import * as CalendarRepository from "../CalendarRepository.server"; import * as CalendarRepository from "../CalendarRepository.server";
import { calendarFiltersSearchParamsObject } from "../calendar-schemas"; import { calendarFiltersSearchParamsObject } from "../calendar-schemas";

View File

@ -1,14 +1,14 @@
import type { SerializeFrom } from "@remix-run/node";
import { Form, useLoaderData } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Form, useLoaderData } from "react-router";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";
import { UserSearch } from "~/components/elements/UserSearch"; import { UserSearch } from "~/components/elements/UserSearch";
import { FormErrors } from "~/components/FormErrors"; import { FormErrors } from "~/components/FormErrors";
import { FormMessage } from "~/components/FormMessage"; import { FormMessage } from "~/components/FormMessage";
import { Label } from "~/components/Label"; import { Label } from "~/components/Label";
import { Main } from "~/components/Main"; import { Main } from "~/components/Main";
import type { SerializeFrom } from "~/utils/remix";
import type { SendouRouteHandle } from "~/utils/remix.server"; import type { SendouRouteHandle } from "~/utils/remix.server";
import type { Unpacked } from "~/utils/types"; import type { Unpacked } from "~/utils/types";
import { action } from "../actions/calendar.$id.report-winners.server"; import { action } from "../actions/calendar.$id.report-winners.server";

View File

@ -1,9 +1,8 @@
import type { MetaFunction, SerializeFrom } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { Link } from "@remix-run/react/dist/components";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { Link, useLoaderData } from "react-router";
import { Avatar } from "~/components/Avatar"; import { Avatar } from "~/components/Avatar";
import { LinkButton, SendouButton } from "~/components/elements/Button"; import { LinkButton, SendouButton } from "~/components/elements/Button";
import { FormWithConfirm } from "~/components/FormWithConfirm"; import { FormWithConfirm } from "~/components/FormWithConfirm";
@ -29,7 +28,7 @@ import {
resolveBaseUrl, resolveBaseUrl,
userPage, userPage,
} from "~/utils/urls"; } from "~/utils/urls";
import { metaTags } from "../../../utils/remix"; import { metaTags, type SerializeFrom } from "../../../utils/remix";
import { action } from "../actions/calendar.$id.server"; import { action } from "../actions/calendar.$id.server";
import { import {
canDeleteCalendarEvent, canDeleteCalendarEvent,

View File

@ -1,9 +1,9 @@
import type { MetaFunction } from "@remix-run/node";
import { Form, Link, useFetcher, useLoaderData } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import Compressor from "compressorjs"; import Compressor from "compressorjs";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { Form, Link, useFetcher, useLoaderData } from "react-router";
import type { AlertVariation } from "~/components/Alert"; import type { AlertVariation } from "~/components/Alert";
import { Alert } from "~/components/Alert"; import { Alert } from "~/components/Alert";
import { Badge } from "~/components/Badge"; import { Badge } from "~/components/Badge";

View File

@ -1,9 +1,9 @@
import type { MetaFunction } from "@remix-run/node";
import { Link, useLoaderData, useNavigate } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import type * as React from "react"; import type * as React from "react";
import type { DateValue } from "react-aria-components"; import type { DateValue } from "react-aria-components";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { Link, useLoaderData, useNavigate } from "react-router";
import { AddNewButton } from "~/components/AddNewButton"; import { AddNewButton } from "~/components/AddNewButton";
import { CopyToClipboardPopover } from "~/components/CopyToClipboardPopover"; import { CopyToClipboardPopover } from "~/components/CopyToClipboardPopover";
import { import {

View File

@ -1,7 +1,7 @@
import { useRevalidator } from "@remix-run/react";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { WebSocket } from "partysocket"; import { WebSocket } from "partysocket";
import React from "react"; import React from "react";
import { useRevalidator } from "react-router";
import invariant from "~/utils/invariant"; import invariant from "~/utils/invariant";
import { logger } from "~/utils/logger"; import { logger } from "~/utils/logger";
import { soundPath } from "~/utils/urls"; import { soundPath } from "~/utils/urls";

View File

@ -1,5 +1,5 @@
import cachified from "@epic-web/cachified"; import cachified from "@epic-web/cachified";
import type { LoaderFunctionArgs } from "@remix-run/node"; import type { LoaderFunctionArgs } from "react-router";
import type { Tables } from "~/db/tables"; import type { Tables } from "~/db/tables";
import { getUserId } from "~/features/auth/core/user.server"; import { getUserId } from "~/features/auth/core/user.server";
import * as Changelog from "~/features/front-page/core/Changelog.server"; import * as Changelog from "~/features/front-page/core/Changelog.server";

View File

@ -1,7 +1,7 @@
import { Link, useLoaderData } from "@remix-run/react";
import clsx from "clsx"; import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useLoaderData } from "react-router";
import { Avatar } from "~/components/Avatar"; import { Avatar } from "~/components/Avatar";
import { Divider } from "~/components/Divider"; import { Divider } from "~/components/Divider";
import { SendouButton } from "~/components/elements/Button"; import { SendouButton } from "~/components/elements/Button";

View File

@ -1,4 +1,4 @@
import type { ActionFunction } from "@remix-run/node"; import type { ActionFunction } from "react-router";
import { requireUser } from "~/features/auth/core/user.server"; import { requireUser } from "~/features/auth/core/user.server";
import { clearTournamentDataCache } from "~/features/tournament-bracket/core/Tournament.server"; import { clearTournamentDataCache } from "~/features/tournament-bracket/core/Tournament.server";
import { requireRole } from "~/modules/permissions/guards.server"; import { requireRole } from "~/modules/permissions/guards.server";

Some files were not shown because too many files have changed in this diff Show More