110 lines
3.8 KiB
TypeScript
110 lines
3.8 KiB
TypeScript
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>
|
||
);
|
||
}
|