diff --git a/.env b/.env index 8738948..d976e46 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -EXPO_PUBLIC_NAME_FLAME_ENDPOINT=https://name-flame-server-1090437595615.us-central1.run.app \ No newline at end of file +EXPO_PUBLIC_NAME_FLAME_ENDPOINT=http://localhost:5000 \ No newline at end of file diff --git a/app/(app)/_layout.tsx b/app/(app)/_layout.tsx index dd57ee9..49b76b1 100644 --- a/app/(app)/_layout.tsx +++ b/app/(app)/_layout.tsx @@ -8,12 +8,16 @@ import { MaterialIcons } from '@expo/vector-icons'; import { useRouter, useLocalSearchParams } from 'expo-router'; import { useToken } from '../../contexts/authCtx'; +import useApi from '@/hooks/useApi'; +import { useActiveNameContext } from '../../contexts/activeNameContext'; import { ThemedView } from '@/components/ThemedView'; export default function AppLayout() { const { token, isLoading } = useToken(); const router = useRouter(); + const api = useApi(); + const activeNameContext = useActiveNameContext(); const { id } = useLocalSearchParams<{ id: string }>(); // You can keep the splash screen open, or render a loading screen like we do here. @@ -50,10 +54,23 @@ export default function AppLayout() { }} /> ( + router.replace(`/nameContext/${activeNameContext.id}`)} + style={{ marginRight: 10 }} + /> + ), // Hide from drawer navigation }} /> ( + headerRight: () => ( router.back()} - style={{ marginLeft: 10 }} + onPress={router.back} + style={{ marginRight: 10 }} /> ), - headerRight: () => ( - id === 'new' - ? null - : ( - alert('Delete')} - style={{ marginRight: 10 }} - />) - ), }} /> (); + const router = useRouter(); + const activeNameContext = useActiveNameContext(); const api = useApi(); const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); // form values const [nameValue, setNameValue] = useState(''); const [descriptionValue, setDescriptionValue] = useState(''); @@ -37,6 +42,7 @@ export default function NameContextDetailsView() { } else { resetForm(); + activeNameContext.resetContext(); setLoading(false); } }, [id]); @@ -49,11 +55,18 @@ export default function NameContextDetailsView() { setNameValue(data.name); setDescriptionValue(data.description); setNounValue(data.noun); - setMaxCharacters(data.filter.maxCharacters); + setMaxCharacters(''); setGenderValue(data.gender); setLoading(false); + + activeNameContext.setContext({ + id: data.id, + name: data.name, + isOwner: data.isOwner + }) + }).catch((err) => { - alert(err); + setError(err); setLoading(false); }); } @@ -71,12 +84,25 @@ export default function NameContextDetailsView() { participants }).then(() => { alert('Name context created'); + router.push('/nameContext'); }).catch((err) => { console.log(err); alert('Failed to create name context'); }); } + function handleDelete() { + if (confirm('Are you sure you want to delete this name context?')) { + api.delete(`/nameContext/${id}`).then(() => { + alert('Name context deleted'); + router.push('/nameContext'); + }).catch((err) => { + console.log(err); + alert('Failed to delete name context'); + }); + } + } + if (loading) { return @@ -86,8 +112,19 @@ export default function NameContextDetailsView() { return ( - Basic Information - + + Basic Information + {isExistingNameContxt && + + + } + + + + router.push(`/nameContext/${id}/match`)} style={{ padding: 5, backgroundColor: Colors.core.orange, borderRadius: 5 }}> + + + Name - - Save - ); } diff --git a/app/(app)/nameContext/[id]/match.tsx b/app/(app)/nameContext/[id]/match.tsx new file mode 100644 index 0000000..03a928a --- /dev/null +++ b/app/(app)/nameContext/[id]/match.tsx @@ -0,0 +1,145 @@ +import {useState, useEffect } from 'react'; +import { View, ScrollView, TouchableOpacity, StyleSheet, TextInput } from 'react-native'; +import { ThemedView } from '@/components/ThemedView'; +import { ThemedText } from '@/components/ThemedText'; +import { MaterialIcons } from '@expo/vector-icons'; +import { Colors } from '@/constants/Colors'; +import useApi from '@/hooks/useApi'; +import { useLocalSearchParams, useRouter } from 'expo-router'; +import { NamePopularityGraph } from '@/components/NamePopularityGraph'; + +export default function NameContextDetailsMatchs() { + const api = useApi(); + const router = useRouter(); + const { id } = useLocalSearchParams<{ id: string }>(); + const [isLoading, setLoading] = useState(false); + + const [searchValue, setSearchValue] = useState(''); + const [currentName, setCurrentName] = useState<{ name: string; description: string; popularity: {}; gender: 'male' | 'female' }>({ name: '', description: '', popularity: {}, gender: 'male' }); + + function searchForName(name: string) { + setLoading(true); + api.get(`/name/${name}`).then((resp) => { + setCurrentName(resp.data); + }).catch((err) => { + console.log(err); + }); + setLoading(false); + } + + function fetchNewName() { + api.get('/name/random').then((resp) => { + setCurrentName(resp.data); + }).catch((err) => { + alert(err); + }); + } + + useEffect(() => { + fetchNewName(); + }, []); + + function handleLikeName() { + api.patch(`/nameContext/${id}/match`, { + name: currentName.name, + }).then(() => { + setSearchValue(''); + fetchNewName(); + } + ).catch((err) => { + alert(err); + }); + } + + const disableDislike = searchValue.length > 0; + + return ( + + + + searchForName(searchValue)} + > + + + + + + {currentName.name} + + + + + Description: + Here is where some info about the name will go + + + + Primary Gender: + {currentName.gender} + + + + Popularity: + + + + + + { !disableDislike && + + } + + + + + + ); +} + +const styles = StyleSheet.create({ + buttonContainer: { + flexDirection: 'row', + justifyContent: 'space-around', + width: '100%', + }, + rowDivider: { + height: 2, + backgroundColor: Colors.core.tan, + borderRadius: 2, + marginVertical: 10, + }, + buttons: { + flex: 1, + padding: 10, + borderRadius: 5, + marginTop: 10, + alignItems: 'center', + marginHorizontal: 5, // Add some horizontal margin to create space between buttons + } +}); \ No newline at end of file diff --git a/app/(app)/nameContext/[id]/matches.tsx b/app/(app)/nameContext/[id]/matches.tsx deleted file mode 100644 index 0c0215b..0000000 --- a/app/(app)/nameContext/[id]/matches.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Text, View } from 'react-native'; - -export default function NameContextDetailsMatchs() { - return ( - - Hello from Name Context Details Match view - - ); -} \ No newline at end of file diff --git a/app/(app)/nameContext/index.tsx b/app/(app)/nameContext/index.tsx index a3c3a9e..4886a75 100644 --- a/app/(app)/nameContext/index.tsx +++ b/app/(app)/nameContext/index.tsx @@ -1,8 +1,10 @@ import React from 'react'; import { ScrollView, RefreshControl, ActivityIndicator } from 'react-native'; import { ThemedView } from '@/components/ThemedView'; +import { ThemedText } from '@/components/ThemedText'; import { NameContextListItem } from '@/components/NameContextListItem'; import { Colors } from '@/constants/Colors'; +import { useFocusEffect } from '@react-navigation/native'; import { NameContext } from '@/types/NameContext'; @@ -25,11 +27,13 @@ export default function NameContextListView() { setRefreshing(false); alert(err); }) - } + }; - React.useEffect(() => { - fetchNameContexts(); - }, []) + useFocusEffect( + React.useCallback(() => { + fetchNameContexts(); + }, []) + ); if (refreshing) { return @@ -37,20 +41,31 @@ export default function NameContextListView() { } + function renderNameContextData() { + if (nameContexts.length === 0) { + return + No Name Contexts found. Add one to begin! + + } + + return nameContexts.map(nameContext => { + return + }) + } + return ( }> - {nameContexts.map(nameContext => { - return - })} + {renderNameContextData()} ); diff --git a/app/_layout.tsx b/app/_layout.tsx index edd6728..765328b 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,11 +1,14 @@ import { Slot } from 'expo-router'; import { TokenProvider } from '../contexts/authCtx'; +import { ActiveNameProvider } from '../contexts/activeNameContext'; export default function Root() { // Set up the auth context and render our layout inside of it. return ( - + + + ); } diff --git a/app/sign-in.tsx b/app/sign-in.tsx index e1691f7..1e366c2 100644 --- a/app/sign-in.tsx +++ b/app/sign-in.tsx @@ -6,6 +6,7 @@ import { ThemedText } from "@/components/ThemedText"; import { useToken } from '../contexts/authCtx'; import { Colors } from "@/constants/Colors"; +import { MaterialIcons } from "@expo/vector-icons"; export default function SignIn() { const { signIn } = useToken(); @@ -22,7 +23,10 @@ export default function SignIn() { return ( - Sign In + + + Sign In + @@ -61,6 +65,7 @@ const styles = StyleSheet.create({ marginBottom: 10, backgroundColor: Colors.core.tanLighter, borderRadius: 5, + fontFamily: 'Bricolage-Grotesque', }, buttons: { backgroundColor: Colors.core.purple, @@ -72,5 +77,6 @@ const styles = StyleSheet.create({ buttonText: { color: Colors.core.white, fontSize: 16, + fontFamily: 'Bricolage-Grotesque', }, }); diff --git a/components/NameContextListItem.tsx b/components/NameContextListItem.tsx index c1099e4..ddd5c86 100644 --- a/components/NameContextListItem.tsx +++ b/components/NameContextListItem.tsx @@ -1,11 +1,19 @@ import { Colors } from '@/constants/Colors'; import { View, Text, StyleSheet, Button } from 'react-native'; import { useRouter } from 'expo-router'; +import { NameContextMatch, NameContextUser } from '@/types/NameContext'; -type NameContextListItemProps = { id: string, name: string, matches: number, participants: number } +type NameContextListItemProps = { + id: string; + name: string; + matches: NameContextMatch[]; + participants: NameContextUser[]; + updatedAt: string; +} -export function NameContextListItem({ id, name, matches, participants }: NameContextListItemProps ) { +export function NameContextListItem({ id, name, matches, participants, updatedAt }: NameContextListItemProps) { const router = useRouter(); + const updatedAtLocalString = new Date(updatedAt).toLocaleString(); return ( @@ -14,11 +22,15 @@ export function NameContextListItem({ id, name, matches, participants }: NameCon Matches: - {matches} + {matches.length} Participants: - {participants} + {participants.length} + + + Updated: + {updatedAtLocalString}