diff --git a/app/(app)/_layout.tsx b/app/(app)/_layout.tsx index da0f352..a387c11 100644 --- a/app/(app)/_layout.tsx +++ b/app/(app)/_layout.tsx @@ -5,10 +5,9 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { Drawer } from 'expo-router/drawer'; import { Colors } from '../../constants/Colors'; import { MaterialIcons } from '@expo/vector-icons'; -import { useRouter, useLocalSearchParams } from 'expo-router'; +import { useRouter } from 'expo-router'; import { useAuth } from '../../contexts/authCtx'; -import useApi from '@/hooks/useApi'; import { useActiveNameContext } from '../../contexts/activeNameContext'; import { ThemedView } from '@/components/ThemedView'; @@ -16,9 +15,7 @@ export default function AppLayout() { const { user, isLoading } = useAuth(); 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. if (isLoading) { @@ -73,6 +70,26 @@ export default function AppLayout() { ), // Hide from drawer navigation }} /> + ( + router.replace(`/nameContext/${activeNameContext.id}`)} + style={{ marginRight: 10 }} + /> + ), // Hide from drawer navigation + }} + /> addApiError(err)) + .finally(() => setLoading(false)); + } + + function updateNameContext() { + setLoading(true); + api.patch(`/nameContext/${id}`, { + name: nameValue, + description: descriptionValue, + noun: nounValue, + filter: { + gender: genderValue, + maxCharacters, + startsWithLetter: startsWithValue + }, + participants + }).then((resp) => { + activeNameContext.setContext(resp.data); }).catch((err) => { addApiError(err); }).finally(() => { @@ -134,9 +153,14 @@ export default function NameContextDetailsView() { }} style={{ padding: 5, backgroundColor: Colors.core.purple, borderRadius: 5 }}> } - + + {isExistingNameContxt && + router.push(`/nameContext/${id}/favorites`)} style={{ padding: 5, backgroundColor: Colors.core.orange, borderRadius: 5 }}> + + + } {isExistingNameContxt && router.push(`/nameContext/${id}/match`)} style={{ padding: 5, backgroundColor: Colors.core.orange, borderRadius: 5 }}> @@ -148,7 +172,6 @@ export default function NameContextDetailsView() { style={styles.input} placeholder='How will you identify this name context?' maxLength={126} - readOnly={isExistingNameContxt} autoCapitalize='words' value={nameValue} onChangeText={setNameValue} diff --git a/app/(app)/nameContext/[id]/favorites.tsx b/app/(app)/nameContext/[id]/favorites.tsx new file mode 100644 index 0000000..58d620b --- /dev/null +++ b/app/(app)/nameContext/[id]/favorites.tsx @@ -0,0 +1,107 @@ +import { useState } from 'react'; +import { View, Text, StyleSheet, Pressable, ActivityIndicator } from 'react-native'; +import { ThemedView } from '@/components/ThemedView'; +import { Colors } from '@/constants/Colors'; +import { ThemedText } from '@/components/ThemedText'; +import { useRouter } from 'expo-router'; +import { useActiveNameContext, } from '@/contexts/activeNameContext'; +import { MaterialIcons } from '@expo/vector-icons'; +import useApi from '@/hooks/useApi'; +import { useErrorContext } from '@/contexts/errorCtx'; + +function Favorites() { + const router = useRouter(); + const api = useApi(); + const activeNameContext = useActiveNameContext(); + const { addApiError } = useErrorContext(); + + const [loading, setLoading] = useState(false); + + function removeLikedName(name: string) { + setLoading(true); + api.patch(`/nameContext/${activeNameContext.id}/removeNames`, { + names: [name] + }).then((resp) => activeNameContext.setContext(resp.data)) + .catch((err) => addApiError(err)) + .finally(() => setLoading(false)); + } + + function renderContent() { + if (loading) { + return ( + + + + + + ); + } + + const { likedNames } = activeNameContext; + + if (likedNames.length === 0) { + return ( + + No Favorites yet! + router.replace(`/nameContext/${activeNameContext.id}/match`)}> + Start Matching + + + + ) + } + + return ( + + {likedNames.map((name, index) => ( + + + + {index + 1}. {name} + removeLikedName(name)}> + + + + + ))} + + ); + } + + return ( + + + Favorites + {renderContent()} + + + ); +} + +const styles = StyleSheet.create({ + container: { + width: '100%', + padding: 10, + backgroundColor: Colors.core.tanLighter, + borderRadius: 10, + marginTop: 10, + }, + matchBtn: { + backgroundColor: Colors.core.orange, + padding: 10, + borderRadius: 5, + marginTop: 10, + alignItems: 'center', + maxWidth: 300, + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-around' + }, + matchBtnText: { + color: Colors.core.tanLighter, + fontSize: 16, + fontFamily: 'Bricolage-Grotesque' + } +}); + +export default Favorites; \ No newline at end of file diff --git a/app/(app)/nameContext/[id]/match.tsx b/app/(app)/nameContext/[id]/match.tsx index 675a93d..76b9141 100644 --- a/app/(app)/nameContext/[id]/match.tsx +++ b/app/(app)/nameContext/[id]/match.tsx @@ -7,12 +7,16 @@ import { Colors } from '@/constants/Colors'; import useApi from '@/hooks/useApi'; import { useLocalSearchParams, useRouter } from 'expo-router'; import { NamePopularityGraph } from '@/components/NamePopularityGraph'; +import { useErrorContext } from '@/contexts/errorCtx'; +import { useActiveNameContext } from '@/contexts/activeNameContext'; export default function NameContextDetailsMatchs() { const api = useApi(); - const router = useRouter(); + const { id } = useLocalSearchParams<{ id: string }>(); const [isLoading, setLoading] = useState(false); + const { addApiError } = useErrorContext(); + const { setContext } = useActiveNameContext(); const [searchValue, setSearchValue] = useState(''); const [currentName, setCurrentName] = useState<{ name: string; description: string; popularity: {}; gender: 'male' | 'female' }>({ name: '', description: '', popularity: {}, gender: 'male' }); @@ -38,11 +42,17 @@ export default function NameContextDetailsMatchs() { }, []); function handleLikeName() { + setLoading(true); api.patch(`/nameContext/${id}/match`, { name: currentName.name, - }).then(() => { + }).then((resp) => { setSearchValue(''); + setContext(resp.data); fetchNewName(); + }).catch((err) => { + addApiError(err); + }).finally(() => { + setLoading(false); }); } diff --git a/contexts/activeNameContext.tsx b/contexts/activeNameContext.tsx index ddbb68a..cee61ab 100644 --- a/contexts/activeNameContext.tsx +++ b/contexts/activeNameContext.tsx @@ -4,6 +4,7 @@ type ActiveNameContextType = { id: string; name: string; isOwner: boolean; + likedNames: string[]; setContext: (context: Partial) => void; resetContext: () => void; }; @@ -12,15 +13,19 @@ const ActiveNameContext = createContext({ id: '', name: '', isOwner: false, + likedNames: [], setContext: () => {}, resetContext: () => {}, }); export const ActiveNameProvider = ({ children }: PropsWithChildren<{}>) => { - const [context, setContextState] = useState({ + const [context, setContextState] = useState({ id: '', name: '', + likedNames: [], isOwner: false, + setContext: () => {}, + resetContext: () => {}, }); const setContext = (newContext: Partial) => { @@ -31,11 +36,14 @@ export const ActiveNameProvider = ({ children }: PropsWithChildren<{}>) => { }; const resetContext = () => { - setContextState({ + setContextState((prevContext) => ({ id: '', name: '', + likedNames: [], isOwner: false, - }); + setContext: prevContext.setContext, + resetContext: prevContext.resetContext, + })); }; return (