diff --git a/app/Screens/AdminHubPage.jsx b/app/Screens/AdminHubPage.jsx index 7f2e776..c087de5 100644 --- a/app/Screens/AdminHubPage.jsx +++ b/app/Screens/AdminHubPage.jsx @@ -3,6 +3,7 @@ import { View, Text, Pressable, StyleSheet } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import AdminFooterNavbar from '../components/AdminFooterNavbar'; import useAdminViewModel from '../ViewModel/useAdminViewModel'; +import ScreenHeader from '../components/ScreenHeader'; const AdminHubPage = () => { const navigation = useNavigation(); @@ -20,8 +21,8 @@ const AdminHubPage = () => { return ( + - Admin Hub Create a Game @@ -48,12 +49,6 @@ const styles = StyleSheet.create({ padding: 20, gap: 12, }, - title: { - fontSize: 26, - fontWeight: '700', - color: '#111827', - marginBottom: 8, - }, button: { backgroundColor: '#2563eb', borderRadius: 8, diff --git a/app/Screens/GameLobbyPage.jsx b/app/Screens/GameLobbyPage.jsx index da90dbb..1d78c94 100644 --- a/app/Screens/GameLobbyPage.jsx +++ b/app/Screens/GameLobbyPage.jsx @@ -3,6 +3,7 @@ import { View, Text, Pressable, TextInput, StyleSheet } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import MemberFooterNavbar from '../components/MemberFooterNavbar'; import useLobbyViewModel from '../ViewModel/useLobbyViewModel'; +import ScreenHeader from '../components/ScreenHeader'; const GameLobbyPage = () => { const navigation = useNavigation(); @@ -31,8 +32,8 @@ const GameLobbyPage = () => { return ( + - Game Lobby { const navigation = useNavigation(); @@ -20,30 +21,29 @@ const GameTypePage = () => { }; return ( - - Select Game Type - {gameTypes.map((label) => ( - navigateByType(label)}> - {label} - - ))} + + + + {gameTypes.map((label) => ( + navigateByType(label)}> + {label} + + ))} + ); }; const styles = StyleSheet.create({ + wrapper: { + flex: 1, + backgroundColor: '#ffffff', + }, container: { flex: 1, justifyContent: 'center', padding: 20, gap: 12, - backgroundColor: '#ffffff', - }, - title: { - fontSize: 26, - fontWeight: '700', - color: '#111827', - marginBottom: 8, }, button: { backgroundColor: '#2563eb', diff --git a/app/Screens/JoinPrivateGamePage.jsx b/app/Screens/JoinPrivateGamePage.jsx index 9972305..4525005 100644 --- a/app/Screens/JoinPrivateGamePage.jsx +++ b/app/Screens/JoinPrivateGamePage.jsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { View, Text, TextInput, Pressable, StyleSheet } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import usePrivateGameViewModel from '../ViewModel/usePrivateGameViewModel'; +import ScreenHeader from '../components/ScreenHeader'; const JoinPrivateGamePage = () => { const navigation = useNavigation(); @@ -19,37 +20,36 @@ const JoinPrivateGamePage = () => { }; return ( - - Join Private Game - - - {submitting ? 'Joining...' : 'Join Game'} - - {!!error && {error}} + + + + + + {submitting ? 'Joining...' : 'Join Game'} + + {!!error && {error}} + ); }; const styles = StyleSheet.create({ + wrapper: { + flex: 1, + backgroundColor: '#ffffff', + }, container: { flex: 1, justifyContent: 'center', padding: 20, gap: 12, - backgroundColor: '#ffffff', - }, - title: { - fontSize: 26, - fontWeight: '700', - color: '#111827', - marginBottom: 8, }, input: { borderWidth: 1, diff --git a/app/Screens/LoginPage.jsx b/app/Screens/LoginPage.jsx index 18e96a1..12ecf67 100644 --- a/app/Screens/LoginPage.jsx +++ b/app/Screens/LoginPage.jsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { View, Text, TextInput, Pressable, StyleSheet } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import useAuthViewModel from '../ViewModel/useAuthViewModel'; +import ScreenHeader from '../components/ScreenHeader'; const LoginPage = () => { const navigation = useNavigation(); @@ -30,49 +31,48 @@ const LoginPage = () => { }; return ( - - Login - - - - navigation.navigate('(routes)/register')}> - Register - - - {submitting ? 'Logging in...' : 'Login'} - + + + + + + + navigation.navigate('(routes)/register')}> + Register + + + {submitting ? 'Logging in...' : 'Login'} + + + {!!error && {error}} - {!!error && {error}} ); }; const styles = StyleSheet.create({ + wrapper: { + flex: 1, + backgroundColor: '#ffffff', + }, container: { flex: 1, padding: 20, justifyContent: 'center', gap: 12, - backgroundColor: '#ffffff', - }, - title: { - fontSize: 28, - fontWeight: '700', - marginBottom: 8, - color: '#111827', }, input: { borderWidth: 1, diff --git a/app/Screens/ManagePrivateSubtaskPage.jsx b/app/Screens/ManagePrivateSubtaskPage.jsx index 2b5847f..4869054 100644 --- a/app/Screens/ManagePrivateSubtaskPage.jsx +++ b/app/Screens/ManagePrivateSubtaskPage.jsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { View, Text, TextInput, Pressable, StyleSheet } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import useManagePrivateSubtaskViewModel from '../ViewModel/useManagePrivateSubtaskViewModel'; +import ScreenHeader from '../components/ScreenHeader'; const ManagePrivateSubtaskPage = () => { const navigation = useNavigation(); @@ -35,38 +36,48 @@ const ManagePrivateSubtaskPage = () => { }; return ( - - Manage Private Game - - - {submitting ? 'Please wait...' : 'Create New Private Game'} - - - Join as Admin for Private Game - - {!!error && {error}} + + + + + {submitting ? 'Please wait...' : 'Create New Private Game'} + + + Business/School Name is only required for admin join. + + + Join as Admin for Private Game + + + {!!error && {error}} + ); }; const styles = StyleSheet.create({ + wrapper: { + flex: 1, + backgroundColor: '#ffffff', + }, container: { flex: 1, justifyContent: 'center', gap: 12, padding: 20, - backgroundColor: '#ffffff', }, - title: { - fontSize: 26, - fontWeight: '700', - color: '#111827', - marginBottom: 8, + adminJoinSection: { + marginTop: 14, + gap: 12, + }, + helperText: { + color: '#4b5563', + fontSize: 13, }, input: { borderWidth: 1, diff --git a/app/Screens/ManageSubgroupsPage.jsx b/app/Screens/ManageSubgroupsPage.jsx index 7bb389b..e2ab794 100644 --- a/app/Screens/ManageSubgroupsPage.jsx +++ b/app/Screens/ManageSubgroupsPage.jsx @@ -2,6 +2,7 @@ import React from 'react'; import { View, Text, TextInput, Pressable, StyleSheet } from 'react-native'; import useSubgroupAdminViewModel from '../ViewModel/useSubgroupAdminViewModel'; import AdminFooterNavbar from '../components/AdminFooterNavbar'; +import ScreenHeader from '../components/ScreenHeader'; const ManageSubgroupsPage = () => { const { @@ -17,8 +18,8 @@ const ManageSubgroupsPage = () => { return ( + - Manage Subgroups {subgroups.map((subgroup) => ( @@ -65,11 +66,6 @@ const styles = StyleSheet.create({ gap: 10, padding: 20, }, - title: { - fontSize: 24, - fontWeight: '700', - color: '#111827', - }, row: { borderWidth: 1, borderColor: '#d1d5db', diff --git a/app/Screens/MapPage.jsx b/app/Screens/MapPage.jsx index fe16f9f..cbc6e56 100644 --- a/app/Screens/MapPage.jsx +++ b/app/Screens/MapPage.jsx @@ -2,14 +2,15 @@ import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import MemberFooterNavbar from '../components/MemberFooterNavbar'; import useMapViewModel from '../ViewModel/useMapViewModel'; +import ScreenHeader from '../components/ScreenHeader'; const MapPage = () => { const { points } = useMapViewModel(); return ( + - Map Page Map and hunt markers appear here. Points loaded: {points.length} @@ -30,11 +31,6 @@ const styles = StyleSheet.create({ padding: 20, gap: 6, }, - title: { - fontSize: 26, - fontWeight: '700', - color: '#111827', - }, body: { color: '#4b5563', }, diff --git a/app/Screens/RegisterPage.jsx b/app/Screens/RegisterPage.jsx index d4b3bbe..cfc95cb 100644 --- a/app/Screens/RegisterPage.jsx +++ b/app/Screens/RegisterPage.jsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { View, Text, TextInput, Pressable, StyleSheet } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import useAuthViewModel from '../ViewModel/useAuthViewModel'; +import ScreenHeader from '../components/ScreenHeader'; const RegisterPage = () => { const navigation = useNavigation(); @@ -32,63 +33,64 @@ const RegisterPage = () => { }; return ( - - Register - - - - - - setAccountType('Individual')} - > - Individual + + + + + + + + + setAccountType('Individual')} + > + Individual + + setAccountType('Business/School')} + > + Business/School + + + + {submitting ? 'Creating...' : 'Create Account'} - setAccountType('Business/School')} - > - Business/School + + {error || ' '} + + navigation.navigate('(routes)/login')}> + Back to Login - - {submitting ? 'Creating...' : 'Create Account'} - - navigation.navigate('(routes)/login')}> - Back to Login - - {!!error && {error}} ); }; const styles = StyleSheet.create({ + wrapper: { + flex: 1, + backgroundColor: '#ffffff', + }, container: { flex: 1, padding: 20, justifyContent: 'center', gap: 12, - backgroundColor: '#ffffff', - }, - title: { - fontSize: 28, - fontWeight: '700', - color: '#111827', - marginBottom: 8, }, input: { borderWidth: 1, @@ -135,10 +137,17 @@ const styles = StyleSheet.create({ color: '#2563eb', fontWeight: '600', }, + errorSlot: { + minHeight: 20, + justifyContent: 'center', + }, errorText: { textAlign: 'center', color: '#dc2626', }, + errorHidden: { + opacity: 0, + }, }); export default RegisterPage; diff --git a/app/Screens/TeamPage.jsx b/app/Screens/TeamPage.jsx index 0e80242..34e8035 100644 --- a/app/Screens/TeamPage.jsx +++ b/app/Screens/TeamPage.jsx @@ -2,14 +2,15 @@ import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import MemberFooterNavbar from '../components/MemberFooterNavbar'; import useTeamViewModel from '../ViewModel/useTeamViewModel'; +import ScreenHeader from '../components/ScreenHeader'; const TeamPage = () => { const { team } = useTeamViewModel(); return ( + - Team Page Team details and members appear here. {team?.team?.TeamName || 'No team joined yet'} @@ -30,11 +31,6 @@ const styles = StyleSheet.create({ padding: 20, gap: 6, }, - title: { - fontSize: 26, - fontWeight: '700', - color: '#111827', - }, body: { color: '#4b5563', }, diff --git a/app/_layout.tsx b/app/_layout.tsx index fdf760e..5fc8c04 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -2,18 +2,18 @@ import { Stack } from "expo-router"; export default function RootLayout() { return ( - - - - - - - - - - - - + + + + + + + + + + + + ); } diff --git a/app/components/AdminFooterNavbar.jsx b/app/components/AdminFooterNavbar.jsx index e24be26..afae78d 100644 --- a/app/components/AdminFooterNavbar.jsx +++ b/app/components/AdminFooterNavbar.jsx @@ -1,12 +1,14 @@ import React from 'react'; import { View, Pressable, Text, StyleSheet } from 'react-native'; import { useNavigation } from '@react-navigation/native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; const AdminFooterNavbar = () => { const navigation = useNavigation(); + const insets = useSafeAreaInsets(); return ( - + navigation.navigate('(routes)/admin-hub')}> Admin Hub @@ -24,15 +26,18 @@ const styles = StyleSheet.create({ container: { flexDirection: 'row', justifyContent: 'space-between', + alignItems: 'center', borderTopWidth: 1, borderColor: '#d4d4d8', paddingHorizontal: 16, - paddingVertical: 10, + paddingTop: 14, backgroundColor: '#ffffff', + minHeight: 86, }, button: { flex: 1, alignItems: 'center', + paddingVertical: 8, }, text: { fontSize: 14, diff --git a/app/components/MemberFooterNavbar.jsx b/app/components/MemberFooterNavbar.jsx index 6b31b8a..4af4578 100644 --- a/app/components/MemberFooterNavbar.jsx +++ b/app/components/MemberFooterNavbar.jsx @@ -1,16 +1,18 @@ import React from 'react'; import { View, Pressable, Text, StyleSheet } from 'react-native'; import { useNavigation } from '@react-navigation/native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; const MemberFooterNavbar = ({ visible = false }) => { const navigation = useNavigation(); + const insets = useSafeAreaInsets(); if (!visible) { return null; } return ( - + navigation.navigate('(routes)/game-lobby')}> Lobby @@ -28,15 +30,18 @@ const styles = StyleSheet.create({ container: { flexDirection: 'row', justifyContent: 'space-between', + alignItems: 'center', borderTopWidth: 1, borderColor: '#d4d4d8', paddingHorizontal: 16, - paddingVertical: 10, + paddingTop: 14, backgroundColor: '#ffffff', + minHeight: 86, }, button: { flex: 1, alignItems: 'center', + paddingVertical: 8, }, text: { fontSize: 14, diff --git a/app/components/ScreenHeader.jsx b/app/components/ScreenHeader.jsx new file mode 100644 index 0000000..ca9cb6b --- /dev/null +++ b/app/components/ScreenHeader.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; + +const ScreenHeader = ({ title }) => { + const insets = useSafeAreaInsets(); + + return ( + + {title} + + ); +}; + +const styles = StyleSheet.create({ + container: { + backgroundColor: '#000000', + paddingHorizontal: 16, + paddingBottom: 12, + minHeight: 72, + justifyContent: 'flex-end', + }, + title: { + color: '#ffffff', + fontSize: 20, + fontWeight: '700', + }, +}); + +export default ScreenHeader; +