Skip to content

Commit 01c5aec

Browse files
Merge pull request #112 from rootstrap/feature/add-terms-and-conditions-webview
feat: add webview to open terms and conditions
2 parents c323aba + 7a21f75 commit 01c5aec

File tree

13 files changed

+141
-55
lines changed

13 files changed

+141
-55
lines changed

.env.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ API_URL=
22
VAR_NUMBER=
33
VAR_BOOL=
44
SECRET_KEY=
5+
WEBSITE_URL=
6+
TERMS_OF_SERVICE_URL=

env.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const LOCAL_BUILD_SCRIPT_PATTERNS = [
3030
'expo export',
3131
];
3232
const isLocalBuild = LOCAL_BUILD_SCRIPT_PATTERNS.some((pattern) =>
33-
process.env.npm_lifecycle_script?.includes(pattern)
33+
process.env.npm_lifecycle_script?.includes(pattern),
3434
);
3535

3636
const EXPO_RUN_COMMANDS = ['expo start', 'expo run'];
@@ -44,13 +44,13 @@ const ENVIRONMENT_DEPENDANT_SCRIPTS = [
4444
];
4545

4646
const scriptIsEnvironmentDependant = ENVIRONMENT_DEPENDANT_SCRIPTS.some(
47-
(script) => process.env.npm_lifecycle_script?.includes(script)
47+
(script) => process.env.npm_lifecycle_script?.includes(script),
4848
);
4949

5050
// Check if the environment file has to be validated for the current running script and build method
5151
const isBuilding = isEASBuild || isLocalBuild;
5252
const isRunning = EXPO_RUN_COMMANDS.some((script) =>
53-
process.env.npm_lifecycle_script?.includes(script)
53+
process.env.npm_lifecycle_script?.includes(script),
5454
);
5555
const shouldValidateEnv =
5656
(isBuilding && scriptIsEnvironmentDependant) || isRunning;
@@ -138,6 +138,8 @@ const clientEnvSchema = z.object({
138138
API_URL: z.string(),
139139
VAR_NUMBER: z.number(),
140140
VAR_BOOL: z.boolean(),
141+
TERMS_OF_SERVICE_URL: z.string(),
142+
WEBSITE_URL: z.string(),
141143
});
142144

143145
const buildTimeEnvSchema = z.object({
@@ -162,6 +164,8 @@ const _clientEnv = {
162164
API_URL: parseString(process.env.API_URL),
163165
VAR_NUMBER: parseNumber(process.env.VAR_NUMBER),
164166
VAR_BOOL: parseBoolean(process.env.VAR_BOOL),
167+
WEBSITE_URL: parseString(process.env.WEBSITE_URL),
168+
TERMS_OF_SERVICE_URL: parseString(process.env.TERMS_OF_SERVICE_URL),
165169
};
166170

167171
/**
@@ -212,19 +216,19 @@ if (shouldValidateEnv) {
212216

213217
if (isLocalBuild) {
214218
messages.push(
215-
`\n💡 Tip: If you recently updated the \x1b[1m\x1b[4m\x1b[31m${envFile}\x1b[0m file and the error still persists, try restarting the server with the -cc flag to clear the cache.`
219+
`\n💡 Tip: If you recently updated the \x1b[1m\x1b[4m\x1b[31m${envFile}\x1b[0m file and the error still persists, try restarting the server with the -cc flag to clear the cache.`,
216220
);
217221
}
218222

219223
if (isEASBuild) {
220224
messages.push(
221-
`\n☁️ For \x1b[1m\x1b[32mEAS Build\x1b[0m deployments, ensure the secret\x1b[1m\x1b[4m\x1b[31m${environmentFiles[APP_ENV]} \x1b[0m is defined in Project Secrets and has the proper environment file attached.`
225+
`\n☁️ For \x1b[1m\x1b[32mEAS Build\x1b[0m deployments, ensure the secret\x1b[1m\x1b[4m\x1b[31m${environmentFiles[APP_ENV]} \x1b[0m is defined in Project Secrets and has the proper environment file attached.`,
222226
);
223227
}
224228

225229
console.error(...messages);
226230
throw new Error(
227-
'Invalid environment variables, Check terminal for more details '
231+
'Invalid environment variables, Check terminal for more details ',
228232
);
229233
}
230234

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
"react-native-screens": "~3.31.1",
104104
"react-native-svg": "~15.2.0",
105105
"react-native-web": "~0.19.12",
106+
"react-native-webview": "13.8.6",
106107
"react-query-kit": "^3.3.0",
107108
"tailwind-variants": "^0.2.1",
108109
"zod": "^3.23.8",

pnpm-lock.yaml

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/(app)/settings.tsx

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { Env } from '@env';
2+
import { Link } from 'expo-router';
23
import { useColorScheme } from 'nativewind';
4+
import React from 'react';
35

46
import { Item } from '@/components/settings/item';
57
import { ItemsContainer } from '@/components/settings/items-container';
68
import { LanguageItem } from '@/components/settings/language-item';
79
import { ThemeItem } from '@/components/settings/theme-item';
810
import { translate, useAuth } from '@/core';
911
import { colors, FocusAwareStatusBar, ScrollView, Text, View } from '@/ui';
10-
import { Github, Rate, Share, Support, Website } from '@/ui/icons';
12+
import { Website } from '@/ui/icons';
1113

1214
export default function Settings() {
1315
const signOut = useAuth.use.signOut();
@@ -29,42 +31,38 @@ export default function Settings() {
2931
<ThemeItem />
3032
</ItemsContainer>
3133

32-
<ItemsContainer title="settings.about">
33-
<Item text="settings.app_name" value={Env.NAME} />
34-
<Item text="settings.version" value={Env.VERSION} />
35-
</ItemsContainer>
36-
37-
<ItemsContainer title="settings.support_us">
38-
<Item
39-
text="settings.share"
40-
icon={<Share color={iconColor} />}
41-
onPress={() => {}}
42-
/>
43-
<Item
44-
text="settings.rate"
45-
icon={<Rate color={iconColor} />}
46-
onPress={() => {}}
47-
/>
48-
<Item
49-
text="settings.support"
50-
icon={<Support color={iconColor} />}
51-
onPress={() => {}}
52-
/>
34+
<ItemsContainer title="settings.links">
35+
<Link
36+
asChild
37+
href={{
38+
pathname: '/www',
39+
params: {
40+
url: Env.TERMS_OF_SERVICE_URL,
41+
title: translate('settings.terms'),
42+
},
43+
}}
44+
>
45+
<Item text="settings.terms" />
46+
</Link>
47+
<Link
48+
asChild
49+
href={{
50+
pathname: '/www',
51+
params: {
52+
url: Env.WEBSITE_URL,
53+
title: translate('settings.website'),
54+
},
55+
}}
56+
>
57+
<Item
58+
text="settings.website"
59+
icon={<Website color={iconColor} />}
60+
/>
61+
</Link>
5362
</ItemsContainer>
5463

55-
<ItemsContainer title="settings.links">
56-
<Item text="settings.privacy" onPress={() => {}} />
57-
<Item text="settings.terms" onPress={() => {}} />
58-
<Item
59-
text="settings.github"
60-
icon={<Github color={iconColor} />}
61-
onPress={() => {}}
62-
/>
63-
<Item
64-
text="settings.website"
65-
icon={<Website color={iconColor} />}
66-
onPress={() => {}}
67-
/>
64+
<ItemsContainer title="settings.about">
65+
<Item text="settings.version" value={Env.VERSION} />
6866
</ItemsContainer>
6967

7068
<View className="my-8">

src/app/(app)/style.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import React from 'react';
2+
13
import { Buttons } from '@/components/buttons';
24
import { Colors } from '@/components/colors';
35
import { Inputs } from '@/components/inputs';

src/app/_layout.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ export default function RootLayout() {
3535
<Stack.Screen name="onboarding" options={{ headerShown: false }} />
3636
<Stack.Screen name="forgot-password" />
3737
<Stack.Screen name="sign-in" options={{ headerShown: false }} />
38+
<Stack.Screen
39+
name="www"
40+
options={{
41+
presentation: 'modal',
42+
title: '', // Title will be overridden by the screen itself
43+
}}
44+
/>
3845
</Stack>
3946
</Providers>
4047
);

src/app/onboarding.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,44 @@
11
import { useRouter } from 'expo-router';
22

33
import { Cover } from '@/components/cover';
4+
import { translate } from '@/core';
45
import { useIsFirstTime } from '@/core/hooks';
56
import { Button, FocusAwareStatusBar, SafeAreaView, Text, View } from '@/ui';
7+
68
export default function Onboarding() {
79
const [, setIsFirstTime] = useIsFirstTime();
810
const router = useRouter();
11+
912
return (
10-
<View className="flex h-full items-center justify-center">
13+
<View className="flex h-full items-center justify-center">
1114
<FocusAwareStatusBar />
1215
<View className="w-full flex-1">
1316
<Cover />
1417
</View>
15-
<View className="justify-end ">
18+
<View className="justify-end">
1619
<Text className="my-3 text-center text-5xl font-bold">
17-
React Native Template
20+
{translate('onboarding.title')}
1821
</Text>
1922
<Text className="mb-2 text-center text-lg text-gray-600">
20-
The right way to build your mobile app
23+
{translate('onboarding.subtitle')}
2124
</Text>
2225

2326
<Text className="my-1 pt-6 text-left text-lg">
24-
🚀 Production-ready{' '}
27+
{translate('onboarding.features.production_ready')}
2528
</Text>
2629
<Text className="my-1 text-left text-lg">
27-
🥷 Developer experience + Productivity
30+
{translate('onboarding.features.developer_experience')}
2831
</Text>
2932
<Text className="my-1 text-left text-lg">
30-
🧩 Minimal code and dependencies
33+
{translate('onboarding.features.minimal_code')}
3134
</Text>
3235
<Text className="my-1 text-left text-lg">
33-
💪 well maintained third-party libraries
36+
{translate('onboarding.features.well_maintained_libraries')}
3437
</Text>
3538
</View>
3639
<SafeAreaView className="mt-6">
3740
<Button
38-
label="Let's Get Started "
41+
label={translate('onboarding.button_label')}
3942
onPress={() => {
4043
setIsFirstTime(false);
4144
router.replace('/sign-in');

src/app/sign-in.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useRouter } from 'expo-router';
2+
import React from 'react';
23
import { showMessage } from 'react-native-flash-message';
34

45
import { useLogin } from '@/api/auth/use-login';

src/app/www.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { useLocalSearchParams, useNavigation, useRouter } from 'expo-router';
2+
import React, { useEffect } from 'react';
3+
import { View } from 'react-native';
4+
import { WebView } from 'react-native-webview';
5+
6+
import { translate } from '@/core';
7+
import { Text } from '@/ui';
8+
9+
export default function WWW() {
10+
const router = useRouter();
11+
const { url, title } = useLocalSearchParams();
12+
const navigation = useNavigation();
13+
14+
useEffect(() => {
15+
if (title) {
16+
navigation.setOptions({
17+
title,
18+
});
19+
}
20+
}, [navigation, title]);
21+
22+
if (!url || typeof url !== 'string') {
23+
return (
24+
<View className="flex-1 items-center justify-center bg-white">
25+
<Text className="text-lg text-red-500">
26+
{translate('www.invalidUrl')}
27+
</Text>
28+
</View>
29+
);
30+
}
31+
32+
return (
33+
<View className="flex-1 bg-white">
34+
<WebView
35+
source={{ uri: url }}
36+
className="flex-1"
37+
onError={() => router.back()}
38+
/>
39+
</View>
40+
);
41+
}

0 commit comments

Comments
 (0)