Skip to content

Commit

Permalink
Add error feedback for username or full name (#45)
Browse files Browse the repository at this point in the history
* Added error feedback when choosing invalid username

* Added error feedback when choosing invalid name
  • Loading branch information
notforrest authored Aug 19, 2024
1 parent f4a97c0 commit 8d133d2
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 45 deletions.
69 changes: 47 additions & 22 deletions app/(tabs)/account/choose-full-name.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,14 @@ import { StyleSheet, Text, TextInput, View } from "react-native";
import { Theme, useTheme } from "../../../utils/ThemeProvider";
import { supabase } from "../../../utils/supabase";
import { TouchableOpacity } from "react-native-gesture-handler";
import { ERROR_MESSAGES } from "../../../utils/ErrorMessages";

export default function ChooseFullName() {
const styles = getStyles(useTheme());
const [fullName, setFullName] = useState("");
const { userId } = useLocalSearchParams();

const handleSubmitFullName = async () => {
try {
const { error } = await supabase.from("profiles").upsert([
{
id: userId,
updated_at: new Date(),
full_name: fullName,
},
]);
if (error) {
throw error;
} else {
router.replace("/account/profile");
router.setParams({ userId: userId });
}
} catch (error) {
console.error("Error saving: ", error);
}
};
const [fullName, setFullName] = useState("");
const [errorMessage, setErrorMessage] = useState(" ");

return (
<View style={styles.container}>
Expand All @@ -41,9 +24,10 @@ export default function ChooseFullName() {
style={styles.input}
value={fullName}
/>
<Text style={styles.errorText}>{errorMessage}</Text>
<TouchableOpacity
disabled={!fullName}
onPress={handleSubmitFullName}
onPress={() => handleSubmitFullName(userId, fullName, setErrorMessage)}
style={styles.button}
>
<Text style={fullName ? styles.buttonText : styles.buttonDisabled}>
Expand All @@ -54,6 +38,42 @@ export default function ChooseFullName() {
);
}

const handleSubmitFullName = async (
userId: string | string[],
fullName: string,
setErrorMessage: (message: string) => void,
) => {
try {
if (!isValidName(fullName)) {
setErrorMessage(ERROR_MESSAGES[90001]);
return;
}

const { error } = await supabase.from("profiles").upsert([
{
id: userId,
updated_at: new Date(),
full_name: fullName,
},
]);
if (error) {
throw error;
} else {
router.replace("/account/profile");
router.setParams({ userId: userId });
}
} catch (error) {
const typedError = error as { code: number };
setErrorMessage(ERROR_MESSAGES[typedError.code] || "Error saving");
}
};

// Validate full name with regex pattern
const isValidName = (username: string) => {
const regex = /^(?!\s|-)[a-zA-Z\s-]{3,19}[a-zA-Z]$/;
return regex.test(username);
};

const getStyles = (theme: Theme) =>
StyleSheet.create({
container: {
Expand All @@ -73,7 +93,6 @@ const getStyles = (theme: Theme) =>
button: {
alignItems: "center",
borderRadius: 10,
marginTop: "20%",
padding: 10,
},
buttonDisabled: {
Expand All @@ -86,4 +105,10 @@ const getStyles = (theme: Theme) =>
color: theme.secondary,
fontSize: 24,
},
errorText: {
color: theme.error,
fontSize: 16,
marginTop: "5%",
minHeight: "15%",
},
});
69 changes: 47 additions & 22 deletions app/(tabs)/account/choose-username.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,14 @@ import { StyleSheet, Text, TextInput, View } from "react-native";
import { Theme, useTheme } from "../../../utils/ThemeProvider";
import { supabase } from "../../../utils/supabase";
import { TouchableOpacity } from "react-native-gesture-handler";
import { ERROR_MESSAGES } from "../../../utils/ErrorMessages";

export default function ChooseUsername() {
const styles = getStyles(useTheme());
const [username, setUsername] = useState("");
const { userId } = useLocalSearchParams();

const handleSubmitUsername = async () => {
try {
const { error } = await supabase.from("profiles").upsert([
{
id: userId,
updated_at: new Date(),
username: username,
},
]);
if (error) {
throw error;
} else {
router.push("/account/choose-full-name");
router.setParams({ userId: userId });
}
} catch (error) {
console.error("Error saving: ", error);
}
};
const [username, setUsername] = useState("");
const [errorMessage, setErrorMessage] = useState(" ");

return (
<View style={styles.container}>
Expand All @@ -41,9 +24,10 @@ export default function ChooseUsername() {
style={styles.input}
value={username}
/>
<Text style={styles.errorText}>{errorMessage}</Text>
<TouchableOpacity
disabled={!username}
onPress={handleSubmitUsername}
onPress={() => handleSubmitUsername(userId, username, setErrorMessage)}
style={styles.button}
>
<Text style={username ? styles.buttonText : styles.buttonDisabled}>
Expand All @@ -54,6 +38,42 @@ export default function ChooseUsername() {
);
}

const handleSubmitUsername = async (
userId: string | string[],
username: string,
setErrorMessage: (message: string) => void,
) => {
try {
if (!isValidUsername(username)) {
setErrorMessage(ERROR_MESSAGES[90000]);
return;
}

const { error } = await supabase.from("profiles").upsert([
{
id: userId,
updated_at: new Date(),
username: username,
},
]);
if (error) {
throw error;
} else {
router.push("/account/choose-full-name");
router.setParams({ userId: userId });
}
} catch (error) {
const typedError = error as { code: number };
setErrorMessage(ERROR_MESSAGES[typedError.code] || "Error saving");
}
};

// Validate username with regex pattern
const isValidUsername = (username: string) => {
const regex = /^(?!_)\w{3,15}$/;
return regex.test(username);
};

const getStyles = (theme: Theme) =>
StyleSheet.create({
container: {
Expand All @@ -73,7 +93,6 @@ const getStyles = (theme: Theme) =>
button: {
alignItems: "center",
borderRadius: 10,
marginTop: "20%",
padding: 10,
},
buttonDisabled: {
Expand All @@ -86,4 +105,10 @@ const getStyles = (theme: Theme) =>
color: theme.secondary,
fontSize: 24,
},
errorText: {
color: theme.error,
fontSize: 16,
marginTop: "5%",
minHeight: "15%",
},
});
11 changes: 11 additions & 0 deletions utils/ErrorMessages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const ERROR_MESSAGES: { [key: number]: string } = {
23505: "Username taken",
90000:
"Must be between 3 and 15 characters\n" +
"Must only contain letters, numbers, or underscores\n" +
"Cannot start with an underscore",
90001:
"Must be between 3 and 20 characters\n" +
"Must only contain letters, numbers, spaces, or hyphens\n" +
"Cannot start or end with a space or hyphen",
};
2 changes: 1 addition & 1 deletion utils/ThemeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
secondary: "#006D77",
secondarylight: "#00838F",
background: "#83C5BE",
error: "#E29578",
error: "#B94E27",
white: "#EDF6F9",
black: "#000",
darkgray: "#333333",
Expand Down

0 comments on commit 8d133d2

Please sign in to comment.