diff --git a/back/src/Kyoo.Core/Views/InfoApi.cs b/back/src/Kyoo.Core/Views/InfoApi.cs
index 113e32f2..48cd132d 100644
--- a/back/src/Kyoo.Core/Views/InfoApi.cs
+++ b/back/src/Kyoo.Core/Views/InfoApi.cs
@@ -50,7 +50,7 @@ public class InfoApi(PermissionOption options, MiscRepository info) : Controller
new() { DisplayName = x.Value.DisplayName, LogoUrl = x.Value.LogoUrl, }
))
.ToDictionary(x => x.Key, x => x.Value),
- SetupStatus = await info.GetSetupStep()
+ SetupStatus = await info.GetSetupStep(),
}
);
}
diff --git a/front/apps/web/src/pages/setup/index.tsx b/front/apps/web/src/pages/setup/index.tsx
new file mode 100644
index 00000000..022e242e
--- /dev/null
+++ b/front/apps/web/src/pages/setup/index.tsx
@@ -0,0 +1,24 @@
+/*
+ * Kyoo - A portable and vast media library solution.
+ * Copyright (c) Kyoo.
+ *
+ * See AUTHORS.md and LICENSE file in the project root for full license information.
+ *
+ * Kyoo is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * Kyoo is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Kyoo. If not, see .
+ */
+
+import { SetupPage } from "@kyoo/ui";
+import { withRoute } from "~/router";
+
+export default withRoute(SetupPage);
diff --git a/front/packages/models/src/resources/server-info.ts b/front/packages/models/src/resources/server-info.ts
index 370ba6d2..05fa90e6 100644
--- a/front/packages/models/src/resources/server-info.ts
+++ b/front/packages/models/src/resources/server-info.ts
@@ -33,6 +33,12 @@ export const OidcInfoP = z.object({
logoUrl: z.string().nullable(),
});
+export enum SetupStep {
+ MissingAdminAccount = "MissingAdminAccount",
+ NoVideoFound = "NoVideoFound",
+ Done = "Done",
+}
+
export const ServerInfoP = z
.object({
/*
@@ -51,6 +57,10 @@ export const ServerInfoP = z
* The list of oidc providers configured for this instance of kyoo.
*/
oidc: z.record(z.string(), OidcInfoP),
+ /*
+ * Check if kyoo's setup is finished.
+ */
+ setupStatus: z.nativeEnum(SetupStep),
})
.transform((x) => {
const baseUrl = Platform.OS === "web" ? x.publicUrl : "kyoo://";
diff --git a/front/packages/ui/src/errors/index.tsx b/front/packages/ui/src/errors/index.tsx
index c7a6e21b..19c9c722 100644
--- a/front/packages/ui/src/errors/index.tsx
+++ b/front/packages/ui/src/errors/index.tsx
@@ -21,3 +21,4 @@
export * from "./error";
export * from "./unauthorized";
export * from "./connection";
+export * from "./setup";
diff --git a/front/packages/ui/src/errors/setup.tsx b/front/packages/ui/src/errors/setup.tsx
new file mode 100644
index 00000000..eeb239db
--- /dev/null
+++ b/front/packages/ui/src/errors/setup.tsx
@@ -0,0 +1,31 @@
+import { SetupStep, type QueryPage } from "@kyoo/models";
+import { Button, Icon, Link, P, ts } from "@kyoo/primitives";
+import { useTranslation } from "react-i18next";
+import { Main } from "@expo/html-elements";
+import { useYoshiki } from "yoshiki/native";
+import Register from "@material-symbols/svg-400/rounded/app_registration.svg";
+import { Navbar, NavbarProfile } from "../navbar";
+
+export const SetupPage: QueryPage<{ step: Exclude }> = ({ step }) => {
+ const { css } = useYoshiki();
+ const { t } = useTranslation();
+
+ return (
+ <>
+ } />
+
+
{t(`errors.setup.${step}`)}
+ {step === SetupStep.MissingAdminAccount && (
+ }
+ />
+ )}
+
+ >
+ );
+};
diff --git a/front/packages/ui/src/navbar/index.tsx b/front/packages/ui/src/navbar/index.tsx
index ec001dc4..31ed2a33 100644
--- a/front/packages/ui/src/navbar/index.tsx
+++ b/front/packages/ui/src/navbar/index.tsx
@@ -38,7 +38,7 @@ import Login from "@material-symbols/svg-400/rounded/login.svg";
import Logout from "@material-symbols/svg-400/rounded/logout.svg";
import Search from "@material-symbols/svg-400/rounded/search-fill.svg";
import Settings from "@material-symbols/svg-400/rounded/settings.svg";
-import { forwardRef, useEffect, useRef, useState } from "react";
+import { ReactElement, forwardRef, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { Platform, type TextInput, View, type ViewProps } from "react-native";
import { useRouter } from "solito/router";
@@ -168,7 +168,11 @@ export const NavbarRight = () => {
);
};
-export const Navbar = (props: Stylable) => {
+export const Navbar = ({
+ left,
+ right,
+ ...props
+}: { left?: ReactElement | null; right?: ReactElement | null }) => {
const { css } = useYoshiki();
const { t } = useTranslation();
@@ -197,16 +201,20 @@ export const Navbar = (props: Stylable) => {
>
- theme.contrast,
- })}
- >
- {t("navbar.browse")}
-
+ {left !== undefined ? (
+ left
+ ) : (
+ theme.contrast,
+ })}
+ >
+ {t("navbar.browse")}
+
+ )}
{
marginX: ts(2),
})}
/>
-
+ {right !== undefined ? right : }
);
};
diff --git a/front/translations/en.json b/front/translations/en.json
index d004aed0..89a285bc 100644
--- a/front/translations/en.json
+++ b/front/translations/en.json
@@ -237,7 +237,11 @@
"offline": "You are not connected to internet. Try again later.",
"unauthorized": "You are missing the permissions {{permission}} to access this page.",
"needVerification": "Your account needs to be verified by your server administrator before you can use it.",
- "needAccount": "This page can't be accessed in guest mode. You need to create an account or login."
+ "needAccount": "This page can't be accessed in guest mode. You need to create an account or login.",
+ "setup": {
+ "MissingAdminAccount": "No admin account has been created yet. Please register to create one.",
+ "NoVideoFound": "No video was found yet. Add movies or series inside your library's folder for them to show here!"
+ }
},
"mediainfo": {
"file": "File",