Skip to content

Commit cd60fa8

Browse files
authoredJan 18, 2024
[native] Add footer and basic validation to forms (#707)
* Add placeholder login pages * fix test and update workflows * rename dir * fix entry file * [native] Add footer and basic validation to forms * remove card wrapper * commit new files * update background * test workflow with npm ci * keep KeyboardAvoidingView * update frontend.yml * revert frontend change * Add prettier to lint checks
1 parent 20f1ce7 commit cd60fa8

10 files changed

+149
-39
lines changed
 

‎native/src/components/Footer.tsx

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from "react";
2+
import { View, Text, StyleSheet, Linking } from "react-native";
3+
4+
import Button from "./Button";
5+
import Link from "./Link";
6+
7+
const currentYear = new Date().getFullYear();
8+
9+
export default function Footer({ navigation }) {
10+
const handleHelpPress = () => {
11+
Linking.openURL(`mailto:contact@flaredown.com`);
12+
};
13+
14+
const handleTosPress = () => {
15+
navigation.navigate("ToS");
16+
};
17+
18+
const handlePrivacyPress = () => {
19+
navigation.navigate("PrivacyPolicy");
20+
};
21+
22+
return (
23+
<View style={styles.footer}>
24+
<Button onPress={handleHelpPress} mode="outlined">
25+
Help & Feedback
26+
</Button>
27+
<View style={styles.links}>
28+
<Link onPress={handleTosPress}>Terms of Service</Link>
29+
<Link onPress={handlePrivacyPress}>Privacy Policy</Link>
30+
</View>
31+
<Text>Flaredown © {currentYear}</Text>
32+
</View>
33+
);
34+
}
35+
36+
const styles = StyleSheet.create({
37+
footer: {
38+
marginTop: 10,
39+
gap: 10,
40+
alignItems: "center",
41+
},
42+
links: {
43+
flexDirection: "row",
44+
gap: 10,
45+
display: "flex",
46+
},
47+
});

‎native/src/components/Layout.tsx

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from "react";
2+
import { StyleSheet, KeyboardAvoidingView, View } from "react-native";
3+
4+
import Footer from "./Footer";
5+
import { Theme } from "../Theme";
6+
7+
export default function Background({ navigation, children }) {
8+
return (
9+
<View style={styles.background}>
10+
<KeyboardAvoidingView style={styles.container} behavior="padding">
11+
{children}
12+
<Footer navigation={navigation} />
13+
</KeyboardAvoidingView>
14+
</View>
15+
);
16+
}
17+
18+
const styles = StyleSheet.create({
19+
background: {
20+
flex: 1,
21+
width: "100%",
22+
backgroundColor: Theme.colors.background,
23+
},
24+
container: {
25+
flex: 1,
26+
padding: 20,
27+
width: "100%",
28+
maxWidth: 500,
29+
alignSelf: "center",
30+
alignItems: "center",
31+
justifyContent: "center",
32+
},
33+
});

‎native/src/helpers/emailValidator.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export function emailValidator(email) {
2+
const re = /\S+@\S+\.\S+/;
3+
if (!email) return "Email address is required.";
4+
if (!re.test(email)) return "Please enter a valid email address.";
5+
return "";
6+
}
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export function passwordValidator(password) {
2+
if (!password) return "Password is required.";
3+
if (password.length < 8)
4+
return "Password should contain at least 8 characters.";
5+
return "";
6+
}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export function usernameValidator(name) {
2+
if (!name) return "Username is required.";
3+
return "";
4+
}

‎native/src/screens/CreateAccountScreen.tsx

+21-23
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,50 @@ import React, { useState } from "react";
22
import { View, StyleSheet } from "react-native";
33
import { Text } from "react-native-paper";
44

5-
import { Theme } from "../Theme";
65
import BackButton from "../components/BackButton";
7-
import Background from "../components/Background";
86
import Button from "../components/Button";
97
import Card from "../components/Card";
108
import Header from "../components/Header";
9+
import Layout from "../components/Layout";
1110
import Link from "../components/Link";
1211
import TextInput from "../components/TextInput";
12+
import { emailValidator } from "../helpers/emailValidator";
13+
import { passwordValidator } from "../helpers/passwordValidator";
14+
import { usernameValidator } from "../helpers/usernameValidator";
1315

1416
export default function CreateAccountScreen({ navigation }) {
15-
const [name, setName] = useState({ value: "", error: "" });
17+
const [username, setUsername] = useState({ value: "", error: "" });
1618
const [email, setEmail] = useState({ value: "", error: "" });
1719
const [password, setPassword] = useState({ value: "", error: "" });
1820

1921
const onSignUpPressed = () => {
20-
// const nameError = nameValidator(name.value);
21-
// const emailError = emailValidator(email.value);
22-
// const passwordError = passwordValidator(password.value);
23-
// if (emailError || passwordError || nameError) {
24-
// setName({ ...name, error: nameError });
25-
// setEmail({ ...email, error: emailError });
26-
// setPassword({ ...password, error: passwordError });
27-
// return;
28-
// }
22+
const usernameError = usernameValidator(username.value);
23+
const emailError = emailValidator(email.value);
24+
const passwordError = passwordValidator(password.value);
25+
if (emailError || passwordError || usernameError) {
26+
setUsername({ ...username, error: usernameError });
27+
setEmail({ ...email, error: emailError });
28+
setPassword({ ...password, error: passwordError });
29+
return;
30+
}
2931
navigation.reset({
3032
index: 0,
3133
routes: [{ name: "Dashboard" }],
3234
});
3335
};
3436

3537
return (
36-
<Background>
38+
<Layout navigation={navigation}>
3739
<BackButton goBack={navigation.goBack} />
3840
<Header>Create account</Header>
3941
<Card>
4042
<TextInput
41-
label="Name"
43+
label="Username"
4244
returnKeyType="next"
43-
value={name.value}
44-
onChangeText={(text) => setName({ value: text, error: "" })}
45-
error={!!name.error}
46-
errorText={name.error}
45+
value={username.value}
46+
onChangeText={(text) => setUsername({ value: text, error: "" })}
47+
error={!!username.error}
48+
errorText={username.error}
4749
/>
4850
<TextInput
4951
label="Email"
@@ -78,7 +80,7 @@ export default function CreateAccountScreen({ navigation }) {
7880
<Link onPress={() => navigation.replace("LoginScreen")}>Log in</Link>
7981
</View>
8082
</Card>
81-
</Background>
83+
</Layout>
8284
);
8385
}
8486

@@ -87,8 +89,4 @@ const styles = StyleSheet.create({
8789
flexDirection: "row",
8890
marginTop: 4,
8991
},
90-
link: {
91-
fontWeight: "bold",
92-
color: Theme.colors.primary,
93-
},
9492
});

‎native/src/screens/Dashboard.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
import React from "react";
12
import { View } from "react-native";
23

3-
import Background from "../components/Background";
4+
import Layout from "../components/Layout";
45
import Link from "../components/Link";
56

67
export default function Dashboard({ navigation }) {
78
return (
8-
<Background>
9+
<Layout navigation={navigation}>
910
<View>
1011
<Link onPress={() => navigation.replace("LoginScreen")}>Log out</Link>
1112
</View>
12-
</Background>
13+
</Layout>
1314
);
1415
}

‎native/src/screens/LoginScreen.tsx

+16-4
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,35 @@ import { Text } from "react-native-paper";
44

55
import { Theme } from "../Theme";
66
import BackButton from "../components/BackButton";
7-
import Background from "../components/Background";
87
import Button from "../components/Button";
98
import Card from "../components/Card";
109
import Header from "../components/Header";
10+
import Layout from "../components/Layout";
1111
import Link from "../components/Link";
1212
import TextInput from "../components/TextInput";
13+
import { emailValidator } from "../helpers/emailValidator";
14+
import { passwordValidator } from "../helpers/passwordValidator";
1315

1416
export default function LoginScreen({ navigation }) {
1517
const [email, setEmail] = useState({ value: "", error: "" });
1618
const [password, setPassword] = useState({ value: "", error: "" });
1719

1820
const onLoginPressed = () => {
19-
navigation.navigate("Dashboard");
21+
const emailError = emailValidator(email.value);
22+
const passwordError = passwordValidator(password.value);
23+
if (emailError || passwordError) {
24+
setEmail({ ...email, error: emailError });
25+
setPassword({ ...password, error: passwordError });
26+
return;
27+
}
28+
navigation.reset({
29+
index: 0,
30+
routes: [{ name: "Dashboard" }],
31+
});
2032
};
2133

2234
return (
23-
<Background>
35+
<Layout navigation={navigation}>
2436
<BackButton goBack={navigation.goBack} />
2537
<Header>Welcome to Flaredown</Header>
2638
<Card>
@@ -62,7 +74,7 @@ export default function LoginScreen({ navigation }) {
6274
</Link>
6375
</View>
6476
</Card>
65-
</Background>
77+
</Layout>
6678
);
6779
}
6880

‎native/src/screens/ResetPasswordScreen.tsx

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
import React, { useState } from "react";
22

33
import BackButton from "../components/BackButton";
4-
import Background from "../components/Background";
54
import Button from "../components/Button";
65
import Card from "../components/Card";
76
import Header from "../components/Header";
7+
import Layout from "../components/Layout";
88
import TextInput from "../components/TextInput";
9+
import { emailValidator } from "../helpers/emailValidator";
910

1011
export default function ResetPasswordScreen({ navigation }) {
1112
const [email, setEmail] = useState({ value: "", error: "" });
1213

1314
const sendResetPasswordEmail = () => {
14-
// const emailError = emailValidator(email.value);
15-
// if (emailError) {
16-
// setEmail({ ...email, error: emailError });
17-
// return;
18-
// }
15+
const emailError = emailValidator(email.value);
16+
if (emailError) {
17+
setEmail({ ...email, error: emailError });
18+
return;
19+
}
1920
navigation.navigate("LoginScreen");
2021
};
2122

2223
return (
23-
<Background>
24+
<Layout navigation={navigation}>
2425
<BackButton goBack={navigation.goBack} />
2526
<Header>Reset password</Header>
2627
<Card>
@@ -45,6 +46,6 @@ export default function ResetPasswordScreen({ navigation }) {
4546
Continue
4647
</Button>
4748
</Card>
48-
</Background>
49+
</Layout>
4950
);
5051
}

‎native/tsconfig.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{
2-
"compilerOptions": {},
2+
"compilerOptions": {
3+
"jsx": "react"
4+
},
35
"extends": "expo/tsconfig.base"
46
}

0 commit comments

Comments
 (0)
Please sign in to comment.