Files
homarr/packages/onboarding/src/onboarding-studio.tsx
T
+12 fcd7c979df feat!: release v2 (#6545)
Co-authored-by: Artur <145776561+arturict@users.noreply.github.com>
Co-authored-by: arturict <arturict@users.noreply.github.com>
Co-authored-by: Thomas <thomas@ajnart.fr>
Co-authored-by: Afonso Jorge Ramos <afonsojorgeramos@gmail.com>
Co-authored-by: Danura30082 <danura30082+github@gmail.com>
Co-authored-by: Kushie <122986913+kushiemoon-dev@users.noreply.github.com>
Co-authored-by: ajnart <thomas@ajnart.fr>
Co-authored-by: ajnart <thomas@ajnart.dev>
Co-authored-by: chenjun <chenjun@foxmail.com>
Co-authored-by: Wikibear <wikibear@users.noreply.github.com>
Co-authored-by: Bergasha <bergasha@gmail.com>
Co-authored-by: leafyelin <43306196+leafyelin@users.noreply.github.com>
Co-authored-by: Lucas Araujo <lucas.lra@gmail.com>
Co-authored-by: GreenMonito <86085570+GreenMonito@users.noreply.github.com>
Co-authored-by: Nerdy-Technician <roffo@nerdy-technician.social>
Co-authored-by: Jun <34545896+jcstrong@users.noreply.github.com>
Co-authored-by: Edmond Abraham <54119952+gitedmond@users.noreply.github.com>
Co-authored-by: thrawnx <tight.bulb9384@fastmail.com>
Co-authored-by: Chris <58918656+nordada@users.noreply.github.com>
Co-authored-by: yi111 <153097222+Yi-111-a@users.noreply.github.com>
Co-authored-by: Yanis <naamaneyanis@gmail.com>
Co-authored-by: Wikibear <me@sej.de>
Co-authored-by: alessiottavo <93441886+alessiottavo@users.noreply.github.com>
2026-10-02 21:00:14 +02:00

129 lines
3.9 KiB
TypeScript

"use client";
import type { ReactNode } from "react";
import { useEffect, useState } from "react";
import { Alert, Button, Center, Paper, Stack, Text, Title } from "@mantine/core";
import { useI18n } from "@homarr/translation/client";
import { Link } from "@homarr/ui";
import type { OnboardingStudioProps } from "./types";
import { AccountSetup } from "./account";
import { getOnboardingAccessState } from "./claim-state";
import { Finish } from "./finish";
import { SetupStudio } from "./setup-studio";
import { Welcome } from "./welcome";
type ClaimState = "checking" | "ready" | "locked" | "signIn" | "error";
const getInitialClaimState = (accessState: ReturnType<typeof getOnboardingAccessState>): ClaimState => {
if (accessState === "claim") return "checking";
return accessState;
};
export const OnboardingStudio = (props: OnboardingStudioProps) => {
const t = useI18n("init.studio.claim");
const tCommon = useI18n("common.action");
const accessState = getOnboardingAccessState(props.environment);
const [claimState, setClaimState] = useState<ClaimState>(() => getInitialClaimState(accessState));
const [claimError, setClaimError] = useState<string | null>(null);
useEffect(() => {
if (accessState !== "claim") {
setClaimState(accessState);
return;
}
const controller = new AbortController();
void fetch("/api/onboarding/claim", { method: "POST", signal: controller.signal })
.then(async (response) => {
if (response.ok) {
setClaimState("ready");
return;
}
const body = (await response.json().catch(() => null)) as { code?: unknown } | null;
if (body?.code === "locked") {
setClaimState("locked");
return;
}
if (body?.code === "administrator_required") {
setClaimState("signIn");
return;
}
setClaimError(t("errorDescription"));
setClaimState("error");
})
.catch(() => {
if (controller.signal.aborted) return;
setClaimError(t("errorDescription"));
setClaimState("error");
});
return () => controller.abort();
}, [accessState, t]);
if (claimState !== "ready") {
let title = t("errorTitle");
let description = claimError ?? t("errorDescription");
let action: ReactNode = (
<Stack align="center">
<Alert color="red" role="alert">
{description}
</Alert>
<Button onClick={() => window.location.reload()}>{tCommon("tryAgain")}</Button>
</Stack>
);
switch (claimState) {
case "checking":
title = t("checkingTitle");
description = t("checking");
action = null;
break;
case "signIn":
title = t("signInTitle");
description = t("signInDescription");
action = (
<Button component={Link} href="/auth/login?callbackUrl=%2Finit">
{t("signIn")}
</Button>
);
break;
case "locked":
title = t("lockedTitle");
description = t("lockedDescription");
action = <Button onClick={() => window.location.reload()}>{tCommon("tryAgain")}</Button>;
break;
case "error":
break;
}
return (
<Center mih="100dvh" p="md">
<Paper withBorder radius="lg" p="xl" maw="32rem" w="100%">
<Stack align="center">
<Title order={1} size="h2" ta="center">
{title}
</Title>
<Text c="dimmed" ta="center">
{description}
</Text>
{action}
</Stack>
</Paper>
</Center>
);
}
switch (props.environment.currentStep) {
case "start":
return <Welcome {...props} />;
case "user":
case "group":
return <AccountSetup {...props} />;
case "setup":
return <SetupStudio {...props} />;
case "finish":
return <Finish {...props} />;
}
};