Files
Cibello-app/apps/mobile/src/app/(auth)/register.tsx
T
2026-08-05 19:21:11 +07:00

110 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from "react";
import { Text, View } from "react-native";
import { Link, router } from "expo-router";
import { api } from "@/lib/api";
import { persistLanguageTag, useAuth, type AuthUser } from "@/lib/auth";
import { detectDeviceLanguageTag, t } from "@/lib/i18n";
import { localeDefaultsForRegion } from "@app/shared-types";
import { Body, Button, Input, Screen, Small, Spacer, Title } from "@/components/ui";
import { colors, spacing } from "@/lib/theme";
interface RegisterResponse {
user: AuthUser;
accessToken: string;
refreshToken: string;
}
export default function RegisterScreen() {
const setSession = useAuth((s) => s.setSession);
const setOnboardingCompleted = useAuth((s) => s.setOnboardingCompleted);
const [displayName, setDisplayName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);
const [busy, setBusy] = useState(false);
const submit = async () => {
setBusy(true);
setError(null);
try {
const result = await api<RegisterResponse>("/v1/auth/register", {
method: "POST",
body: {
displayName,
email,
password,
// D-031: enhetens språk backend skapar locale-preferenser före välkomstmejlet.
locale: detectDeviceLanguageTag() ?? "sv-SE",
},
});
await setSession(
{ accessToken: result.accessToken, refreshToken: result.refreshToken },
result.user,
);
// D-031: enhetens språk/region synkas till backend direkt så att mejl,
// notiser och innehåll kommer på rätt språk från första stund.
const deviceTag = detectDeviceLanguageTag();
if (deviceTag) {
const region = deviceTag.split("-")[1]?.toUpperCase();
const defaults = region ? localeDefaultsForRegion(region) : null;
await api("/v1/me/locale-preferences", {
method: "PATCH",
body: {
languageTag: deviceTag,
...(defaults
? {
regionCode: defaults.regionCode,
timeZone: defaults.timeZone,
measurementSystem: defaults.measurementSystem,
temperatureUnit: defaults.temperatureUnit,
currencyCode: defaults.currencyCode,
}
: {}),
},
}).catch(() => {});
await persistLanguageTag(deviceTag);
}
setOnboardingCompleted(false);
router.replace("/onboarding");
} catch (err) {
setError(err instanceof Error ? err.message : t("common.error"));
} finally {
setBusy(false);
}
};
return (
<Screen scroll={false} style={{ justifyContent: "center", gap: spacing.md }}>
<View style={{ alignItems: "center", marginBottom: spacing.lg }}>
<Title>{t("auth.register")}</Title>
<Small>{t("auth.trialNote")}</Small>
</View>
<Input
placeholder={t("auth.displayName")}
value={displayName}
onChangeText={setDisplayName}
/>
<Input
placeholder={t("auth.email")}
autoCapitalize="none"
keyboardType="email-address"
value={email}
onChangeText={setEmail}
/>
<Input
placeholder={`${t("auth.password")} (minst 10 tecken)`}
secureTextEntry
value={password}
onChangeText={setPassword}
/>
{error && <Text style={{ color: colors.danger }}>{error}</Text>}
<Button label={t("auth.register")} onPress={() => void submit()} loading={busy} />
<Spacer size={spacing.sm} />
<Link href="/(auth)/login" style={{ textAlign: "center", color: colors.primaryDark }}>
{t("auth.hasAccount")}
</Link>
<Body muted>{t("onboarding.notMedical")}</Body>
</Screen>
);
}