diff --git a/.env b/.env new file mode 100644 index 0000000..f762f06 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +EXPO_PUBLIC_SUPABASE_URL="https://hnmqvjnnscdkcbxcbvyu.supabase.co" +EXPO_PUBLIC_SUPABASE_ANON_KEY= "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhubXF2am5uc2Nka2NieGNidnl1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTEyOTgxMjMsImV4cCI6MjAyNjg3NDEyM30.xjzSaG22KLkzskY4U3NaohE_RLTLTkeTW_2qD5RFPUc" \ No newline at end of file diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..4a97dc5 --- /dev/null +++ b/.env.sample @@ -0,0 +1,2 @@ +EXPO_PUBLIC_SUPABASE_URL= +EXPO_PUBLIC_SUPABASE_ANON_KEY= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0b37b6e..e349375 100644 --- a/.gitignore +++ b/.gitignore @@ -34,8 +34,43 @@ yarn-error.* # typescript *.tsbuildinfo -# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb +# @generated expo-cli sync-b5df6a44d8735348b729920a7406b633cfb74d4c # The following patterns were generated by expo-cli -expo-env.d.ts +# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files + +# dependencies +node_modules/ + +# Expo +.expo/ +dist/ +web-build/ + +# Native +*.orig.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision + +# Metro +.metro-health-check* + +# debug +npm-debug.* +yarn-debug.* +yarn-error.* + +# macOS +.DS_Store +*.pem + +# local env files +.env*.local + +# typescript +*.tsbuildinfo + # @end expo-cli \ No newline at end of file diff --git a/app.d.ts b/app.d.ts new file mode 100644 index 0000000..a13e313 --- /dev/null +++ b/app.d.ts @@ -0,0 +1 @@ +/// diff --git a/app.json b/app.json index 326aaf5..9ed5c89 100644 --- a/app.json +++ b/app.json @@ -31,7 +31,7 @@ }, "plugins": ["expo-router"], "experiments": { - "typedRoutes": false + "typedRoutes": true }, "extra": { "router": { @@ -45,7 +45,7 @@ "policy": "appVersion" }, "updates": { - "url": "https://u.expo.dev/a85a4ec3-52c3-42a4-9158-fa4c62823448" + "url": "https://u.expo.dev/c60ed383-fb7e-4a56-a589-acae0e73b49f" }, "owner": "cheetah-works" } diff --git a/app/(auth)/_layout.tsx b/app/(auth)/_layout.tsx new file mode 100644 index 0000000..093d6b7 --- /dev/null +++ b/app/(auth)/_layout.tsx @@ -0,0 +1,6 @@ +import { Slot } from "expo-router"; +import React from "react"; + +export default function AuthLayout() { + return ; +} diff --git a/app/(auth)/login.tsx b/app/(auth)/login.tsx new file mode 100644 index 0000000..2a15db5 --- /dev/null +++ b/app/(auth)/login.tsx @@ -0,0 +1,120 @@ +import { Stack } from "expo-router"; +import React, { useState } from "react"; +import { Alert, StyleSheet, TextInput, View, Text } from "react-native"; +import { TouchableOpacity } from "react-native-gesture-handler"; + +import { supabase } from "../lib/supabase-client"; + +export default function AuthPage() { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [loading, setLoading] = useState(false); + + async function signInWithEmail() { + setLoading(true); + const { error } = await supabase.auth.signInWithPassword({ + email, + password, + }); + + if (error) Alert.alert("Sign In Error", error.message); + setLoading(false); + } + + async function signUpWithEmail() { + setLoading(true); + const { error } = await supabase.auth.signUp({ + email, + password, + }); + + if (error) Alert.alert("Sign Up Error", error.message); + setLoading(false); + } + + return ( + + + + setEmail(text)} + value={email} + placeholder="email@address.com" + autoCapitalize="none" + /> + + + setPassword(text)} + value={password} + secureTextEntry + placeholder="Password" + autoCapitalize="none" + /> + + + signInWithEmail()} + style={styles.buttonContainer} + > + SIGN IN + + + + signUpWithEmail()} + style={styles.buttonContainer} + > + SIGN UP + + + + ); +} +const styles = StyleSheet.create({ + container: { + flex: 1, + flexDirection: "column", + alignItems: "center", + justifyContent: "center", + backgroundColor: "powderblue", + paddingHorizontal: 20, + }, + verticallySpaced: { + paddingTop: 8, + paddingBottom: 8, + alignSelf: "stretch", + }, + mt20: { + marginTop: 20, + }, + buttonContainer: { + backgroundColor: "#0052cc", + borderRadius: 10, + paddingVertical: 12, + paddingHorizontal: 16, + margin: 8, + elevation: 4, // Add elevation for a raised effect + }, + buttonText: { + fontSize: 18, + color: "#fff", + fontWeight: "bold", + alignSelf: "center", + textTransform: "uppercase", + }, + textInput: { + backgroundColor: "#f0f0f0", // Light background color for input field + borderColor: "#ccc", + borderRadius: 8, + borderWidth: 1, + paddingVertical: 12, + paddingHorizontal: 16, + margin: 8, + width: "100%", + }, +}); diff --git a/app/(settings)/index.tsx b/app/(settings)/index.tsx new file mode 100644 index 0000000..53443ba --- /dev/null +++ b/app/(settings)/index.tsx @@ -0,0 +1,83 @@ +import { Stack } from "expo-router"; +import React, { useEffect, useState } from "react"; +import { + SafeAreaView, + Text, + View, + TouchableOpacity, + StyleSheet, + Alert, +} from "react-native"; + +import { supabase } from "@/app/lib/supabase-client"; + +export default function SettingsPage() { + const [user, setUser] = useState(null); + useEffect(() => { + supabase.auth + .getUser() + .then(({ data: { user } }: { data: { user: any } }) => { + if (user) { + setUser(user); + } else { + Alert.alert("Error Accessing User"); + } + }); + }, []); + + const doLogout = async () => { + const { error } = await supabase.auth.signOut(); + if (error) { + Alert.alert("Error Signing Out User", error.message); + } + }; + + return ( + + + + {JSON.stringify(user, null, 2)} + + LOGOUT + + + + ); +} + +const styles = StyleSheet.create({ + container: { + marginTop: 40, + padding: 12, + }, + verticallySpaced: { + paddingTop: 4, + paddingBottom: 4, + alignSelf: "stretch", + }, + mt20: { + marginTop: 20, + }, + buttonContainer: { + backgroundColor: "#000968", + borderRadius: 10, + paddingVertical: 10, + paddingHorizontal: 12, + margin: 8, + }, + buttonText: { + fontSize: 18, + color: "#fff", + fontWeight: "bold", + alignSelf: "center", + textTransform: "uppercase", + }, + textInput: { + borderColor: "#000968", + borderRadius: 4, + borderStyle: "solid", + borderWidth: 1, + padding: 12, + margin: 8, + }, +}); diff --git a/app/(tabs)/account.tsx b/app/(tabs)/account.tsx index 77fa627..4fba210 100644 --- a/app/(tabs)/account.tsx +++ b/app/(tabs)/account.tsx @@ -1,15 +1,18 @@ import { BottomSheetModal, useBottomSheetModal } from "@gorhom/bottom-sheet"; -import React, { useRef } from "react"; +import React, { useEffect, useState, useRef } from "react"; import { Text, TouchableOpacity, - ScrollView, StyleSheet, + Alert, + ScrollView, Button, } from "react-native"; import AccountSheet from "../../components/bottomSheet"; +import { supabase } from "@/app/lib/supabase-client"; + //TODO: add a notification icon //TODO: add a profile icon //TODO: details grids of profile picture, name, email, phone number, address, and edit button @@ -22,12 +25,31 @@ const Account = () => { const { dismiss } = useBottomSheetModal(); const handleOpenPress = () => bottomSheetRef.current?.present(); + const [user, setUser] = useState(null); + useEffect(() => { + supabase.auth + .getUser() + .then(({ data: { user } }: { data: { user: any } }) => { + if (user) { + setUser(user); + } else { + Alert.alert("Error Accessing User"); + } + }); + }, []); + + const doLogout = async () => { + const { error } = await supabase.auth.signOut(); + if (error) { + Alert.alert("Error Signing Out User", error.message); + } + }; + return ( Personal Details - Transactions @@ -43,10 +65,9 @@ const Account = () => { Calendar - - {/* - Edit Access - */} + + LOGOUT +