From d3f6c9fe1ef4ec546c1c776e5dd95c45a0d5ede8 Mon Sep 17 00:00:00 2001 From: gmuni001 <you@example.com> Date: Fri, 22 Nov 2024 16:33:07 +0000 Subject: [PATCH] Setting up structure for prototyping --- App.tsx | 30 +--------- README.md | 6 +- components/Account.tsx | 133 ----------------------------------------- components/Auth.tsx | 95 ----------------------------- components/Avatar.tsx | 130 ---------------------------------------- 5 files changed, 5 insertions(+), 389 deletions(-) delete mode 100644 components/Account.tsx delete mode 100644 components/Auth.tsx delete mode 100644 components/Avatar.tsx diff --git a/App.tsx b/App.tsx index e62f089..83d82ac 100644 --- a/App.tsx +++ b/App.tsx @@ -1,38 +1,14 @@ import 'react-native-url-polyfill/auto' -import { useState, useEffect } from 'react' -import { supabase } from './lib/supabase' -import Auth from './components/Auth' -import Account from './components/Account' import { View } from 'react-native' -import { Session } from '@supabase/supabase-js' import GeolocationPhotography from './components/GeolocationPhotography'; // This will be your new component export default function App() { - const [session, setSession] = useState<Session | null>(null) - - useEffect(() => { - supabase.auth.getSession().then(({ data: { session } }) => { - setSession(session) - }) - - supabase.auth.onAuthStateChange((_event, session) => { - setSession(session) - }) - }, []) return ( <View> - {session && session.user ? ( - <> - <GeolocationPhotography /> - </> - ) : ( - <Auth /> - )} - </View> - ) - - + <GeolocationPhotography /> + </View> + ); } \ No newline at end of file diff --git a/README.md b/README.md index 2b2da03..f6bd026 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # PhotographyOnTheMove -## 12/06/2024 - started 16:05pm +## 22/11/2024 - Prototyping App -#### For this ongoing project, I am using React Native to run my applications on. I use this alongside my phone which has the Expo App. The use of the QR code allows me to visualise the project and get an idea of how my project is handled. - -#### I am currently using Supabase for BackEnd and its been good at handling storage (e.g. photos) alongside a table to input user data (usernames and passwords). In future preference, I plan on creating a web server from one of my old computers that will allow me to direct the photos taken to a new directory. I will have to consider how response my server is as its an old computer and hopefully, it will be able to handle my requests. +### I am now working backwards and have removed backend features that related to Supabase. I will attempt to create some features like geofencing and notifications in the case of taking a photo. \ No newline at end of file diff --git a/components/Account.tsx b/components/Account.tsx deleted file mode 100644 index 8cd9104..0000000 --- a/components/Account.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import { useState, useEffect } from 'react' -import { supabase } from '../lib/supabase' -import { StyleSheet, View, Alert } from 'react-native' -import { Button, Input } from 'react-native-elements' -import { Session } from '@supabase/supabase-js' -import Avatar from './Avatar' - -export default function Account({ session }: { session: Session }) { - const [loading, setLoading] = useState(true) - const [username, setUsername] = useState('') - const [website, setWebsite] = useState('') - const [avatarUrl, setAvatarUrl] = useState('') - - useEffect(() => { - if (session) getProfile() - }, [session]) - - async function getProfile() { - try { - setLoading(true) - if (!session?.user) throw new Error('No user on the session!') - - const { data, error, status } = await supabase - .from('profiles') - .select(`username, website, avatar_url`) - .eq('id', session?.user.id) - .single() - if (error && status !== 406) { - throw error - } - - if (data) { - setUsername(data.username) - setWebsite(data.website) - setAvatarUrl(data.avatar_url) - } - } catch (error) { - if (error instanceof Error) { - Alert.alert(error.message) - } - } finally { - setLoading(false) - } - } - - async function updateProfile({ - username, - website, - avatar_url, - }: { - username: string - website: string - avatar_url: string - }) { - try { - setLoading(true) - if (!session?.user) throw new Error('No user on the session!') - - const updates = { - id: session?.user.id, - username, - website, - avatar_url, - updated_at: new Date(), - } - - const { error } = await supabase.from('profiles').upsert(updates) - - if (error) { - throw error - } - } catch (error) { - if (error instanceof Error) { - Alert.alert(error.message) - } - } finally { - setLoading(false) - } - } - - return ( - <View style={styles.container}> - <View style={[styles.verticallySpaced, styles.mt20]}> - <Input label="Email" value={session?.user?.email} disabled /> - </View> - <View style={styles.verticallySpaced}> - <Input label="Username" value={username || ''} onChangeText={(text) => setUsername(text)} /> - </View> - <View style={styles.verticallySpaced}> - <Input label="Website" value={website || ''} onChangeText={(text) => setWebsite(text)} /> - </View> - - <View style={[styles.verticallySpaced, styles.mt20]}> - <Button - title={loading ? 'Loading ...' : 'Update'} - onPress={() => updateProfile({ username, website, avatar_url: avatarUrl })} - disabled={loading} - /> - </View> - - <View> - <Avatar - size={200} - url={avatarUrl} - onUpload={(url: string) => { - setAvatarUrl(url) - updateProfile({ username, website, avatar_url: url }) - }} - /> - </View> - - - <View style={styles.verticallySpaced}> - <Button title="Sign Out" onPress={() => supabase.auth.signOut()} /> - </View> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - marginTop: 40, - padding: 12, - }, - verticallySpaced: { - paddingTop: 4, - paddingBottom: 4, - alignSelf: 'stretch', - }, - mt20: { - marginTop: 20, - }, -}) \ No newline at end of file diff --git a/components/Auth.tsx b/components/Auth.tsx deleted file mode 100644 index 6c42749..0000000 --- a/components/Auth.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import React, { useState } from 'react' -import { Alert, StyleSheet, View, AppState } from 'react-native' -import { supabase } from '../lib/supabase' -import { Button, Input } from 'react-native-elements' - -// Tells Supabase Auth to continuously refresh the session automatically if -// the app is in the foreground. When this is added, you will continue to receive -// `onAuthStateChange` events with the `TOKEN_REFRESHED` or `SIGNED_OUT` event -// if the user's session is terminated. This should only be registered once. -AppState.addEventListener('change', (state) => { - if (state === 'active') { - supabase.auth.startAutoRefresh() - } else { - supabase.auth.stopAutoRefresh() - } -}) - -export default function Auth() { - 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: email, - password: password, - }) - - if (error) Alert.alert(error.message) - setLoading(false) - } - - async function signUpWithEmail() { - setLoading(true) - const { - data: { session }, - error, - } = await supabase.auth.signUp({ - email: email, - password: password, - }) - - if (error) Alert.alert(error.message) - if (!session) Alert.alert('Please check your inbox for email verification!') - setLoading(false) - } - - return ( - <View style={styles.container}> - <View style={[styles.verticallySpaced, styles.mt20]}> - <Input - label="Email" - leftIcon={{ type: 'font-awesome', name: 'envelope' }} - onChangeText={(text) => setEmail(text)} - value={email} - placeholder="email@address.com" - autoCapitalize={'none'} - /> - </View> - <View style={styles.verticallySpaced}> - <Input - label="Password" - leftIcon={{ type: 'font-awesome', name: 'lock' }} - onChangeText={(text) => setPassword(text)} - value={password} - secureTextEntry={true} - placeholder="Password" - autoCapitalize={'none'} - /> - </View> - <View style={[styles.verticallySpaced, styles.mt20]}> - <Button title="Sign in" disabled={loading} onPress={() => signInWithEmail()} /> - </View> - <View style={styles.verticallySpaced}> - <Button title="Sign up" disabled={loading} onPress={() => signUpWithEmail()} /> - </View> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - marginTop: 40, - padding: 12, - }, - verticallySpaced: { - paddingTop: 4, - paddingBottom: 4, - alignSelf: 'stretch', - }, - mt20: { - marginTop: 20, - }, -}) \ No newline at end of file diff --git a/components/Avatar.tsx b/components/Avatar.tsx deleted file mode 100644 index 2474871..0000000 --- a/components/Avatar.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { useState, useEffect } from 'react' -import { supabase } from '../lib/supabase' -import { StyleSheet, View, Alert, Image, Button } from 'react-native' -import * as ImagePicker from 'expo-image-picker' - -interface Props { - size: number - url: string | null - onUpload: (filePath: string) => void -} - -export default function Avatar({ url, size = 150, onUpload }: Props) { - const [uploading, setUploading] = useState(false) - const [avatarUrl, setAvatarUrl] = useState<string | null>(null) - const avatarSize = { height: size, width: size } - - useEffect(() => { - if (url) downloadImage(url) - }, [url]) - - async function downloadImage(path: string) { - try { - const { data, error } = await supabase.storage.from('avatars').download(path) - - if (error) { - throw error - } - - const fr = new FileReader() - fr.readAsDataURL(data) - fr.onload = () => { - setAvatarUrl(fr.result as string) - } - } catch (error) { - if (error instanceof Error) { - console.log('Error downloading image: ', error.message) - } - } - } - - async function uploadAvatar() { - try { - setUploading(true) - - const result = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: ImagePicker.MediaTypeOptions.Images, // Restrict to only images - allowsMultipleSelection: false, // Can only select one image - allowsEditing: true, // Allows the user to crop / rotate their photo before uploading it - quality: 1, - exif: false, // We don't want nor need that data. - }) - - if (result.canceled || !result.assets || result.assets.length === 0) { - console.log('User cancelled image picker.') - return - } - - const image = result.assets[0] - console.log('Got image', image) - - if (!image.uri) { - throw new Error('No image uri!') // Realistically, this should never happen, but just in case... - } - - const arraybuffer = await fetch(image.uri).then((res) => res.arrayBuffer()) - - const fileExt = image.uri?.split('.').pop()?.toLowerCase() ?? 'jpeg' - const path = `${Date.now()}.${fileExt}` - const { data, error: uploadError } = await supabase.storage - .from('avatars') - .upload(path, arraybuffer, { - contentType: image.mimeType ?? 'image/jpeg', - }) - - if (uploadError) { - throw uploadError - } - - onUpload(data.path) - } catch (error) { - if (error instanceof Error) { - Alert.alert(error.message) - } else { - throw error - } - } finally { - setUploading(false) - } - } - - return ( - <View> - {avatarUrl ? ( - <Image - source={{ uri: avatarUrl }} - accessibilityLabel="Avatar" - style={[avatarSize, styles.avatar, styles.image]} - /> - ) : ( - <View style={[avatarSize, styles.avatar, styles.noImage]} /> - )} - <View> - <Button - title={uploading ? 'Uploading ...' : 'Upload'} - onPress={uploadAvatar} - disabled={uploading} - /> - </View> - </View> - ) -} - -const styles = StyleSheet.create({ - avatar: { - borderRadius: 5, - overflow: 'hidden', - maxWidth: '100%', - }, - image: { - objectFit: 'cover', - paddingTop: 0, - }, - noImage: { - backgroundColor: '#333', - borderWidth: 1, - borderStyle: 'solid', - borderColor: 'rgb(200, 200, 200)', - borderRadius: 5, - }, -}) \ No newline at end of file -- GitLab