diff --git a/front/apps/mobile/app/(public)/login/index.tsx b/front/apps/mobile/app/(public)/login/index.tsx index fbb64ab9..43bc741c 100644 --- a/front/apps/mobile/app/(public)/login/index.tsx +++ b/front/apps/mobile/app/(public)/login/index.tsx @@ -19,5 +19,6 @@ */ import { LoginPage } from "@kyoo/ui"; +import { withRoute } from "../../utils"; -export default LoginPage; +export default withRoute(LoginPage); diff --git a/front/apps/mobile/app/(public)/register/index.tsx b/front/apps/mobile/app/(public)/register/index.tsx index 36338a73..a44e4006 100644 --- a/front/apps/mobile/app/(public)/register/index.tsx +++ b/front/apps/mobile/app/(public)/register/index.tsx @@ -19,5 +19,6 @@ */ import { RegisterPage } from "@kyoo/ui"; +import { withRoute } from "../../utils"; -export default RegisterPage; +export default withRoute(RegisterPage); diff --git a/front/packages/models/src/query.tsx b/front/packages/models/src/query.tsx index 1a9acb1e..43dc5484 100644 --- a/front/packages/models/src/query.tsx +++ b/front/packages/models/src/query.tsx @@ -49,16 +49,17 @@ export const queryFn = async ( type?: Parser, token?: string | null, ): Promise> => { - const url = context.apiUrl ?? getCurrentApiUrl(); + const url = context.apiUrl ? null : getCurrentApiUrl(); if (token === undefined && context.authenticated !== false) token = await getToken(); const path = [url] .concat( "path" in context - ? (context.path.filter((x) => x) as string[]) + ? (context.path as string[]) : "pageParam" in context && context.pageParam ? [context.pageParam as string] - : (context.queryKey.filter((x) => x) as string[]), + : (context.queryKey as string[]), ) + .filter((x) => x) .join("/") .replace("/?", "?"); let resp; @@ -182,19 +183,19 @@ export type QueryPage = ComponentType< export const toQueryKey = (query: { path: (string | undefined)[]; params?: { [query: string]: boolean | number | string | string[] | undefined }; + options?: { apiUrl?: string }; }) => { - if (query.params) { - return [ - ...query.path, - "?" + + return [ + query.options?.apiUrl, + ...query.path, + query.params + ? "?" + Object.entries(query.params) .filter(([_, v]) => v !== undefined) .map(([k, v]) => `${k}=${Array.isArray(v) ? v.join(",") : v}`) - .join("&"), - ]; - } else { - return query.path; - } + .join("&") + : null, + ]; }; export const useFetch = (query: QueryIdentifier) => { diff --git a/front/packages/primitives/src/button.tsx b/front/packages/primitives/src/button.tsx index c061564e..32c5e48a 100644 --- a/front/packages/primitives/src/button.tsx +++ b/front/packages/primitives/src/button.tsx @@ -18,28 +18,37 @@ * along with Kyoo. If not, see . */ -import { ComponentProps, ReactElement, forwardRef } from "react"; +import { ComponentType, ForwardedRef, ReactElement, forwardRef } from "react"; import { Theme, useYoshiki } from "yoshiki/native"; import { PressableFeedback } from "./links"; import { P } from "./text"; import { ts } from "./utils"; -import { Falsy, View } from "react-native"; +import { Falsy, PressableProps, View } from "react-native"; -export const Button = forwardRef< - View, +export const Button = forwardRef(function Button( { + children, + text, + icon, + licon, + as, + ...props + }: { children?: ReactElement | Falsy; text?: string; licon?: ReactElement | Falsy; icon?: ReactElement | Falsy; - } & ComponentProps ->(function Button({ children, text, icon, licon, ...props }, ref) { + as?: ComponentType; + } & AsProps, + ref: ForwardedRef, +) { const { css } = useYoshiki("button"); + const Container = as ?? PressableFeedback; return ( - theme.accent, + borderColor: (theme: Theme) => theme.accent, borderWidth: ts(0.5), fover: { self: { bg: (theme: Theme) => theme.accent }, @@ -56,7 +65,7 @@ export const Button = forwardRef< }, }, props as any, - )} + ) as AsProps)} > {(licon || text || icon) != null && ( )} {children} - + ); }); diff --git a/front/packages/ui/src/login/form.tsx b/front/packages/ui/src/login/form.tsx index 8a95baaf..b5e4f216 100644 --- a/front/packages/ui/src/login/form.tsx +++ b/front/packages/ui/src/login/form.tsx @@ -40,10 +40,14 @@ const SvgBlob = (props: SvgProps) => { ); }; -export const FormPage = ({ children, ...props }: { children: ReactNode } & Stylable) => { +export const FormPage = ({ + children, + apiUrl, + ...props +}: { children: ReactNode; apiUrl?: string } & Stylable) => { const { css } = useYoshiki(); - const src = imageFn("/items/random/thumbnail"); + const src = apiUrl ? `${apiUrl}/items/random/thumbnail` : imageFn("/items/random/thumbnail"); const nativeProps = Platform.select>({ web: { defaultSource: { uri: src }, diff --git a/front/packages/ui/src/login/login.tsx b/front/packages/ui/src/login/login.tsx index d26bc029..6bcfa4d6 100644 --- a/front/packages/ui/src/login/login.tsx +++ b/front/packages/ui/src/login/login.tsx @@ -44,6 +44,7 @@ export const LoginPage: QueryPage<{ apiUrl?: string; error?: string }> = ({ const { css } = useYoshiki(); useEffect(() => { + console.log("login", apiUrl); if (!apiUrl && Platform.OS !== "web") router.replace("/server-url", undefined, { experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false }, @@ -51,7 +52,7 @@ export const LoginPage: QueryPage<{ apiUrl?: string; error?: string }> = ({ }, [apiUrl, router]); return ( - +

{t("login.login")}

{t("login.username")}

diff --git a/front/packages/ui/src/login/oidc.tsx b/front/packages/ui/src/login/oidc.tsx index e9e08cae..3362bcbb 100644 --- a/front/packages/ui/src/login/oidc.tsx +++ b/front/packages/ui/src/login/oidc.tsx @@ -104,7 +104,7 @@ export const OidcCallbackPage: QueryPage<{ hasRun.current = true; function onError(error: string) { - router.replace(`/login?error=${error}${apiUrl ? `&apiUrl=${apiUrl}` : ""}`, undefined, { + router.replace({pathname: "/login", query: { error, apiUrl }}, undefined, { experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false }, }); } diff --git a/front/packages/ui/src/login/register.tsx b/front/packages/ui/src/login/register.tsx index 71a751e1..606cd3b7 100644 --- a/front/packages/ui/src/login/register.tsx +++ b/front/packages/ui/src/login/register.tsx @@ -50,7 +50,7 @@ export const RegisterPage: QueryPage<{ apiUrl?: string }> = ({ apiUrl }) => { }, [apiUrl, router]); return ( - +

{t("login.register")}

{t("login.username")}

diff --git a/front/packages/ui/src/login/server-url.tsx b/front/packages/ui/src/login/server-url.tsx index 0a932fd2..91a52d54 100644 --- a/front/packages/ui/src/login/server-url.tsx +++ b/front/packages/ui/src/login/server-url.tsx @@ -19,7 +19,7 @@ */ import { QueryIdentifier, QueryPage, ServerInfo, ServerInfoP, useFetch } from "@kyoo/models"; -import { Button, P, Input, ts, H1, HR } from "@kyoo/primitives"; +import { Button, P, Input, ts, H1, HR, Link } from "@kyoo/primitives"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { Platform, View } from "react-native"; @@ -40,8 +40,9 @@ const query: QueryIdentifier = { }; export const ServerUrlPage: QueryPage = () => { - const [apiUrl, setApiUrl] = useState(""); - const { data, error } = useFetch(query); + const [_apiUrl, setApiUrl] = useState(""); + const apiUrl = cleanApiUrl(_apiUrl); + const { data, error } = useFetch({ ...query, options: { apiUrl: apiUrl } }); const router = useRouter(); const { t } = useTranslation(); const { css } = useYoshiki(); @@ -57,11 +58,9 @@ export const ServerUrlPage: QueryPage = () => {

{t("login.server")}

- {error && ( -

theme.colors.red, alignSelf: "center" })}> - {error.errors[0]} -

- )} +

theme.colors.red, alignSelf: "center" })}> + {error?.errors[0] ?? " "} +