Skip to content

Commit

Permalink
Finished Consent Screen
Browse files Browse the repository at this point in the history
Placeholder version of consent copy text has been uploaded to production
Firestore as well as emulator db. Consent screen is finished (apart from
any styling we want to change and of course the copy text itself). Admin
screen currently just has a text input and a save button to update the
text stored in Firestore. Will finalize admin screen once PR #193
(export test data) is merged into dev.
  • Loading branch information
shashjar committed Jul 2, 2022
1 parent b804c3e commit 1410274
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 62 deletions.
6 changes: 3 additions & 3 deletions db/firebase-export-metadata.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"version": "10.1.4",
"version": "10.9.2",
"firestore": {
"version": "1.13.1",
"version": "1.14.3",
"path": "firestore_export",
"metadata_file": "firestore_export/firestore_export.overall_export_metadata"
},
"auth": {
"version": "10.1.4",
"version": "10.9.2",
"path": "auth_export"
}
}
Binary file not shown.
Binary file modified db/firestore_export/all_namespaces/all_kinds/output-0
Binary file not shown.
Binary file modified db/firestore_export/firestore_export.overall_export_metadata
Binary file not shown.
43 changes: 43 additions & 0 deletions frontend/src/firebase/firebaseInteractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export default class FirebaseInteractor {
gameType: getRandomGameType(),
testDate: Timestamp.fromDate(getTestDate()),
role: Role.PARTICIPANT,
hasGivenConsent: false,
hasFinishedTutorial: false,
testScore: null,
testSessionId: null,
Expand Down Expand Up @@ -166,6 +167,7 @@ export default class FirebaseInteractor {
numPairs: docData.numPairs,
gameType: docData.gameType,
role: docData.role as Role ?? Role.PARTICIPANT,
hasGivenConsent: docData.hasGivenConsent,
hasFinishedTutorial: docData.hasFinishedTutorial,
testScore: docData.testScore,
testSessionId: docData.testSessionId,
Expand Down Expand Up @@ -378,6 +380,47 @@ export default class FirebaseInteractor {
return allWords.slice(0, num)
}

// Updates the state of hasGivenConsent for this user to be true
async updateHasGivenConsent() {
const user = this.auth.currentUser;

if (user === null) {
throw new Error("No actual user");
}

const docData = (await getDoc(doc(this.db, "users", user.uid))).data();
const userDoc = doc(this.db, "users", user.uid)

if (docData === undefined) {
throw new Error("No data found")
}

await updateDoc(userDoc, {
hasGivenConsent: true,
});
}

// Get the consent text that is listed in Firestore
async getConsentText(): Promise<string> {
const copyTextRef = collection(this.db, "copyText");
const docData = (await getDoc(doc(copyTextRef, "consentText"))).data();
return docData?.text;
}

// Set the consent text that is listed in Firestore
async setConsentText(consentText: string) {
const docData = (await getDoc(doc(this.db, "copyText", "consentText"))).data();
const consentTextDoc = doc(this.db, "copyText", "consentText")

if (docData === undefined) {
throw new Error("No data found")
}

await updateDoc(consentTextDoc, {
text: consentText,
});
}

// Updates the state of hasFinishedTutorial for this user to be true
async updateHasFinishedTutorial() {
const user = this.auth.currentUser;
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/models/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export interface User {
testDate: Date;
numPairs: NumPairs;
gameType: GameType;
role: Role
role: Role;
hasGivenConsent: boolean;
hasFinishedTutorial: boolean;
testScore: number | null;
testSessionId: string | null;
Expand Down
13 changes: 9 additions & 4 deletions frontend/src/screens/Login/signInFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@ export default function SignInFlow() {

const userSignedIn = () => {
if (fi.auth.currentUser?.emailVerified) {
navigation.navigate("HomeScreen")
fi.getUser().then((user) => {
if (user.hasGivenConsent) {
navigation.navigate("HomeScreen")
}
else {
navigation.navigate("ConsentScreen")
}
})
} else {
// TODO: navigate to consent screen only if the user is a participant
// if they are an admin, go to email verification
// navigation.navigate("ConsentScreen")
navigation.navigate("EmailVerification")
}
};

Expand Down
28 changes: 11 additions & 17 deletions frontend/src/screens/Login/signUp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ interface SignUpPageProps {
}

export default function SignUpPage({ goToSignIn, goToAccountSettings }: SignUpPageProps) {
const navigation = useNavigation();
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [confirmPassword, setConfirmPassword] = useState("")
Expand All @@ -38,22 +37,17 @@ export default function SignUpPage({ goToSignIn, goToAccountSettings }: SignUpPa
} else if (password !== confirmPassword) {
setError("Passwords do not match.")
} else {
setEmail("");
setPassword("");
setConfirmPassword("");
goToSignIn();
navigation.navigate("ConsentScreen", { email: email, password: password })
// interactor.createAccount(email, password)
// .then(() => {
// setEmail("");
// setPassword("");
// setConfirmPassword("");
// goToSignIn();
// })
// .catch(e => {
// console.log(e.message);
// setError(mapErrorCodeToMessage(e.code))
// })
interactor.createAccount(email, password)
.then(() => {
setEmail("");
setPassword("");
setConfirmPassword("");
goToSignIn();
})
.catch(e => {
console.log(e.message);
setError(mapErrorCodeToMessage(e.code))
})
}
}} style={styles.signUpButton}>
<Text style={styles.signUpText}>Sign Up</Text>
Expand Down
49 changes: 39 additions & 10 deletions frontend/src/screens/adminScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { LoadingScreen } from "../components/LoadingScreen";
import PrimaryButton from "../components/Button/PrimaryButton";
import { collection } from "firebase/firestore";
import { generateRoundsCSV, promptExportEmail, testJson } from "../firebase/csvExporter";
import CustomTextInput from "../components/TextInput/CustomTextInput";

const fi = new FirebaseInteractor();

Expand All @@ -20,21 +21,49 @@ export interface AdminScreenProps {

export default function AdminScreen(props: AdminScreenProps) {

const [consentText, setConsentText] = useState("");

useEffect(() => {
fi.getConsentText().then((text) => {
setConsentText(text);
})
}, [])

const saveConsentText = () => {
fi.setConsentText(consentText);
}

return (
<DraxProvider>
<Text>This is admin placeholder hooray</Text>
<PrimaryButton onPress={async () => {
await promptExportEmail(await generateRoundsCSV());
}} disabled={false} text="create csv" />
<View style={styles.container}>
<CustomTextInput
placeholderText="consent text"
value={consentText}
setValue={setConsentText}
secureText={false} />
<TouchableOpacity style={styles.saveButton} onPress={saveConsentText}>
<Text style={{ color: "#FFF", fontSize: 22 }}>Save</Text>
</TouchableOpacity>
</View>
</DraxProvider>
)
}


const defaultStyle = StyleSheet.create({

});

const styles = StyleSheet.create({

container: {
flexDirection: "column",
flex: 1,
alignItems: "center",
width: "100%",
height: "100%",
paddingTop: "5%"
},
saveButton: {
backgroundColor: "#5FBFF8",
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
height: "7.5%",
width: "75%"
}
})
90 changes: 64 additions & 26 deletions frontend/src/screens/consentScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useState } from "react";
import { View, Text, Image, StyleSheet, TouchableOpacity } from "react-native";
import React, { useState, useEffect } from "react";
import { View, Text, Image, StyleSheet, TouchableOpacity, ScrollView } from "react-native";
import FirebaseInteractor from "../firebase/firebaseInteractor";
import { useNavigation } from "@react-navigation/core";
import { mapErrorCodeToMessage } from "../utils/utils";

const CONSENT_HEADER_OPTIONS = {
headerTitle: () => { return <Image style={styles.mainImage} source={require('../assets/flow-icon-light.png')} /> },
Expand All @@ -23,44 +22,55 @@ const fi = new FirebaseInteractor();

export interface ConsentScreenProps {
route: any;
email: string;
password: string;
}

export default function ConsentScreen(props: ConsentScreenProps) {

const navigation = useNavigation();
const [error, setError] = useState("")
const [copyScrollPos, setCopyScrollPos] = useState(0);
const [consentText, setConsentText] = useState("");

React.useLayoutEffect(() => {
navigation.setOptions(CONSENT_HEADER_OPTIONS);
}, [navigation]);

useEffect(() => {
fi.getConsentText().then((text) => {
setConsentText(text);
})
}, [])

const consentGiven = () => {
console.log("email", props.email)
console.log("password", props.password)
fi.createAccount(props.email, props.password)
fi.updateHasGivenConsent()
.then(() => {
navigation.navigate("EmailVerification")
})
.catch(e => {
console.log(e.message);
setError(mapErrorCodeToMessage(e.code))
navigation.navigate("Onboarding", { route: "HomeScreen" })
})

}

return (
<View style={styles.container}>
<Text style={{ color: "#FFF", fontSize: 20 }}>
consent text here blah blah blah more text here
</Text>
<TouchableOpacity style={styles.startButton} onPress={consentGiven}>
<Text style={{ color: "#FFF", fontSize: 22 }}>I consent</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.startButton} onPress={() => navigation.navigate("EmailVerification")}>
<Text style={{ color: "#FFF", fontSize: 22 }}>I do not consent</Text>
</TouchableOpacity>
<View style={styles.textContainer}>
<ScrollView
style={styles.scrollView}
onScroll={(event) => { setCopyScrollPos(event.nativeEvent.contentOffset.y) }}>
<Text style={{ color: "#FFF", fontSize: 20 }}>
{/* Lorem ipsum dolor sit amet. Est tempore nostrum sed porro minima ab assumenda error et voluptatibus nihil et enim eius. Et nobis sequi qui vitae eligendi eos magnam temporibus ea veritatis officia? In quasi adipisci facere quasi sed iusto autem. Id laboriosam earum id sint nisi et corporis suscipit ut sunt cupiditate. Est voluptas dicta et facilis assumenda et voluptatem quisquam et voluptas voluptates qui fuga facilis ut sequi voluptas At Quis deserunt. Sed accusamus nihil rem quia itaque sit maiores quia aut rerum modi ea perspiciatis nostrum aut dolorem dignissimos aut aspernatur distinctio! Et nisi facere qui totam eligendi aut omnis ratione quo labore laborum eum accusantium rerum. Et quia quae in voluptate velit ad animi dolore et earum voluptas ab aliquid iste ea voluptatibus suscipit et corporis consequatur. Aut numquam harum non deleniti placeat et alias autem vel ipsum molestias est voluptatem delectus qui fuga labore. Sit incidunt dignissimos et sint quisquam aut magni accusantium a nemo sint. Ad eligendi expedita et iusto assumenda est quis magnam sed inventore inventore quo suscipit minima est obcaecati saepe. */}
{consentText}
</Text>
</ScrollView>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity style={styles.consentButton} onPress={consentGiven}>
<Text style={{ color: "#FFF", fontSize: 22 }}>I consent</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {
fi.logout().then(() => {
navigation.navigate("SignInFlow");
});
}} style={styles.noConsentButton}>
<Text style={{ color: "#FFF", fontSize: 22 }}>I do not consent</Text>
</TouchableOpacity>
</View>
</View>
)
}
Expand All @@ -81,14 +91,42 @@ const styles = StyleSheet.create({
height: "100%",
paddingTop: "5%"
},
startButton: {
textContainer: {
width: "95%",
height: "65%",
marginTop: "12.5%",
flexDirection: "column"
},
scrollView: {
marginHorizontal: 20,
},
buttonContainer: {
width: "100%",
height: "50%",
flexDirection: "column",
alignItems: "center",
justifyContent: "flex-end",
},
consentButton: {
backgroundColor: "#5FBFF8",
borderColor: "#5FBFF8",
borderWidth: 2,
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
height: '12.5%',
width: '75%',
marginBottom: "5%"
},
noConsentButton: {
backgroundColor: "#5FBFF8",
borderColor: "#5FBFF8",
borderWidth: 2,
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
height: '7.5%',
height: '12.5%',
width: '75%',
marginBottom: "27.5%"
}
})
2 changes: 1 addition & 1 deletion frontend/src/screens/emailVerificationScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function EmailVerificationScreen() {
<TouchableOpacity style={styles.verifiedButton} onPress={() => {
fi.checkIfVerified().then(emailVerified => {
if (emailVerified) {
navigation.navigate("Onboarding", { route: "HomeScreen" })
navigation.navigate("ConsentScreen")
} else {
setErrorMessage("Email has not been verified. Please check your email.")
}
Expand Down

0 comments on commit 1410274

Please sign in to comment.