authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-07-15 12:48:55+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-15 10:48:55+00:00
logecb35f75839925dd1ac6f854efeef5c9e291d11b
tree147cfa26a60049c8b89f836b3c4fdb474906b6a7
parentd359789ed4ed99b19a0bc6db3c6f6eba4d2b53ce
signature Signed by PGP key B5690EEEBB952194

Fix Legal modal header crash (#4000)

Co-authored-by: codex <codex@users.noreply.github.com>

2 files changed, 22 insertions(+), 21 deletions(-)

apps/mobile/src/Stack.tsx+1-1
...@@ -115,7 +115,7 @@ const LEGAL_DOCUMENT_HEADER_OPTIONS: AppScreenOptions = {...@@ -115,7 +115,7 @@ const LEGAL_DOCUMENT_HEADER_OPTIONS: AppScreenOptions = {
115 ...SHEET_SOLID_HEADER_OPTIONS,115 ...SHEET_SOLID_HEADER_OPTIONS,
116 headerBackVisible: false,116 headerBackVisible: false,
117 headerLeft: SettingsLegalDocumentCloseHeaderButton,117 headerLeft: SettingsLegalDocumentCloseHeaderButton,
118 headerRight: SettingsLegalDocumentExternalHeaderButton,118 headerRight: () => <SettingsLegalDocumentExternalHeaderButton />,
119 presentation: "fullScreenModal",119 presentation: "fullScreenModal",
120};120};
121121
apps/mobile/src/features/settings/components/SettingsLegalDocumentRouteScreen.tsx+21-20
...@@ -1,11 +1,5 @@...@@ -1,11 +1,5 @@
1import {1import { type NavigationProp, type ParamListBase, useNavigation } from "@react-navigation/native";
2 type NavigationProp,2import { useCallback, useLayoutEffect, useState } from "react";
3 type ParamListBase,
4 type RouteProp,
5 useNavigation,
6 useRoute,
7} from "@react-navigation/native";
8import { useCallback, useState } from "react";
9import { ActivityIndicator, Linking, Pressable, View } from "react-native";3import { ActivityIndicator, Linking, Pressable, View } from "react-native";
10import { WebView } from "react-native-webview";4import { WebView } from "react-native-webview";
115
...@@ -15,10 +9,6 @@ import { SymbolView } from "../../../components/AppSymbol";...@@ -15,10 +9,6 @@ import { SymbolView } from "../../../components/AppSymbol";
15import { useThemeColor } from "../../../lib/useThemeColor";9import { useThemeColor } from "../../../lib/useThemeColor";
16import { isLegalDocumentUrl, LEGAL_URL } from "../lib/legal-document-url";10import { isLegalDocumentUrl, LEGAL_URL } from "../lib/legal-document-url";
1711
18type SettingsLegalRouteParams = {
19 SettingsLegal: { readonly externalUrl?: string } | undefined;
20};
21
22export function SettingsLegalDocumentCloseHeaderButton() {12export function SettingsLegalDocumentCloseHeaderButton() {
23 const navigation = useNavigation();13 const navigation = useNavigation();
24 const iconColor = useThemeColor("--color-icon");14 const iconColor = useThemeColor("--color-icon");
...@@ -42,20 +32,20 @@ export function SettingsLegalDocumentCloseHeaderButton() {...@@ -42,20 +32,20 @@ export function SettingsLegalDocumentCloseHeaderButton() {
42 );32 );
43}33}
4434
45export function SettingsLegalDocumentExternalHeaderButton() {35export function SettingsLegalDocumentExternalHeaderButton({
36 externalUrl = LEGAL_URL,
37}: {
38 readonly externalUrl?: string;
39}) {
46 const iconColor = useThemeColor("--color-icon");40 const iconColor = useThemeColor("--color-icon");
47 const route = useRoute<RouteProp<SettingsLegalRouteParams, "SettingsLegal">>();41 const safeExternalUrl = isLegalDocumentUrl(externalUrl) ? externalUrl : LEGAL_URL;
48 const externalUrl =
49 route.params?.externalUrl && isLegalDocumentUrl(route.params.externalUrl)
50 ? route.params.externalUrl
51 : LEGAL_URL;
5242
53 return (43 return (
54 <Pressable44 <Pressable
55 accessibilityLabel="Open legal documents in external browser"45 accessibilityLabel="Open legal documents in external browser"
56 accessibilityRole="button"46 accessibilityRole="button"
57 hitSlop={12}47 hitSlop={12}
58 onPress={() => void Linking.openURL(externalUrl).catch(() => undefined)}48 onPress={() => void Linking.openURL(safeExternalUrl).catch(() => undefined)}
59 className="p-2 active:opacity-60"49 className="p-2 active:opacity-60"
60 >50 >
61 <SymbolView51 <SymbolView
...@@ -83,6 +73,17 @@ export function SettingsLegalDocumentRouteScreen({...@@ -83,6 +73,17 @@ export function SettingsLegalDocumentRouteScreen({
83 const [reloadKey, setReloadKey] = useState(0);73 const [reloadKey, setReloadKey] = useState(0);
84 const [loadProgress, setLoadProgress] = useState(0);74 const [loadProgress, setLoadProgress] = useState(0);
85 const [loadError, setLoadError] = useState<string | null>(null);75 const [loadError, setLoadError] = useState<string | null>(null);
76 const [externalUrl, setExternalUrl] = useState(documentUrl);
77 const renderExternalHeaderButton = useCallback(
78 () => <SettingsLegalDocumentExternalHeaderButton externalUrl={externalUrl} />,
79 [externalUrl],
80 );
81
82 useLayoutEffect(() => {
83 navigation.setOptions({
84 headerRight: renderExternalHeaderButton,
85 });
86 }, [navigation, renderExternalHeaderButton]);
8687
87 const openExternalUrl = useCallback((url: string) => {88 const openExternalUrl = useCallback((url: string) => {
88 void Linking.openURL(url).catch(() => undefined);89 void Linking.openURL(url).catch(() => undefined);
...@@ -160,7 +161,7 @@ export function SettingsLegalDocumentRouteScreen({...@@ -160,7 +161,7 @@ export function SettingsLegalDocumentRouteScreen({
160 }}161 }}
161 onLoadEnd={(event) => {162 onLoadEnd={(event) => {
162 if (isLegalDocumentUrl(event.nativeEvent.url)) {163 if (isLegalDocumentUrl(event.nativeEvent.url)) {
163 navigation.setParams({ externalUrl: event.nativeEvent.url });164 setExternalUrl(event.nativeEvent.url);
164 }165 }
165 setLoadProgress(0);166 setLoadProgress(0);
166 }}167 }}