From 61679d8228dc4fb2527103101892ead481f5d22a Mon Sep 17 00:00:00 2001 From: Luiz Ramos Date: Mon, 16 Jun 2025 21:33:26 -0700 Subject: [PATCH 1/6] Fixed web bugs related to signin and signup --- app/(auth)/index.tsx | 4 +- app/(auth)/signuppage.tsx | 35 +++++++------- app/(tabs)/_layout.tsx | 4 +- hooks/shift-navigation.tsx | 6 +-- lib/expoSecureStoreAdapter.ts | 87 +++++++++++++++++++++++++++++++---- 5 files changed, 103 insertions(+), 33 deletions(-) diff --git a/app/(auth)/index.tsx b/app/(auth)/index.tsx index 1631ef2..6157c54 100644 --- a/app/(auth)/index.tsx +++ b/app/(auth)/index.tsx @@ -10,7 +10,7 @@ import { } from 'react-native'; import {useRouter} from "expo-router"; import {supabase} from "@/lib/supabaseClient"; -import * as SecureStore from 'expo-secure-store'; +import { ExpoSecureStoreAdapter } from '@/lib/expoSecureStoreAdapter'; const { width } = Dimensions.get('window'); // Get the current screen width @@ -60,7 +60,7 @@ export default function LoginPage() { console.error('Error fetching role:', roleError); } else { console.log('User role:', roleData); - await SecureStore.setItemAsync('role', roleData.role?.toLowerCase()); + await ExpoSecureStoreAdapter.setItem('role', roleData.role?.toLowerCase()); } // Navigate after everything is ready diff --git a/app/(auth)/signuppage.tsx b/app/(auth)/signuppage.tsx index 6427821..3d83cf9 100644 --- a/app/(auth)/signuppage.tsx +++ b/app/(auth)/signuppage.tsx @@ -97,7 +97,6 @@ export default function SignUpPage() { } try { - // Sign up with Supabase const { data: authData, error: authError } = await supabase.auth.signUp({ email: formData.email, password: formData.password, @@ -116,16 +115,21 @@ export default function SignUpPage() { } if (authData.user) { - Alert.alert( - 'Success', - 'Account created successfully! Please check your email for verification.', - [ - { - text: 'OK', - onPress: () => router.replace('/(auth)'), - }, - ] - ); + if (Platform.OS === 'web') { + window.alert('Account created successfully! Please check your email for verification.'); + router.replace('/(auth)'); + } else { + Alert.alert( + 'Success', + 'Account created successfully! Please check your email for verification.', + [ + { + text: 'OK', + onPress: () => router.replace('/(auth)'), + }, + ] + ); + } } } catch (error) { console.error('Sign up error:', error); @@ -216,11 +220,10 @@ export default function SignUpPage() { {renderInput('Supervisor', 'supervisor', formData.supervisor, handleInputChange)} - Sign Up + Sign Up @@ -272,7 +275,7 @@ const styles = StyleSheet.create({ fontSize: 14, marginTop: 5, }, - signUpButton: { + button: { width: '85%', maxWidth: 400, height: width > 400 ? 50 : 45, @@ -282,7 +285,7 @@ const styles = StyleSheet.create({ borderRadius: 8, marginBottom: 15, }, - signUpButtonText: { + buttonText: { color: '#fff', fontSize: 16, fontWeight: 'bold', diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index ca5d88a..6460618 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,14 +1,14 @@ import FontAwesome from '@expo/vector-icons/FontAwesome'; import { Tabs } from 'expo-router'; import {useEffect, useState} from "react"; -import * as SecureStore from "expo-secure-store"; +import { ExpoSecureStoreAdapter } from "@/lib/expoSecureStoreAdapter"; export default function TabLayout() { const [role, setRole] = useState(null); useEffect(() => { const fetchRole = async () => { - const storedRole = await SecureStore.getItemAsync('role'); + const storedRole = await ExpoSecureStoreAdapter.getItem('role'); setRole(storedRole); }; diff --git a/hooks/shift-navigation.tsx b/hooks/shift-navigation.tsx index 2192153..8455397 100644 --- a/hooks/shift-navigation.tsx +++ b/hooks/shift-navigation.tsx @@ -16,11 +16,7 @@ export const useShiftNavigation = (currentShiftId: number) => { }; const showAlert = (title: string, message: string): void => { - if (Platform.OS === 'web') { - window.alert(`${title}\n${message}`); - } else { - Alert.alert(title, message); - } + Alert.alert(title, message); }; const goToPreviousShift = () => { diff --git a/lib/expoSecureStoreAdapter.ts b/lib/expoSecureStoreAdapter.ts index 887a100..b576276 100644 --- a/lib/expoSecureStoreAdapter.ts +++ b/lib/expoSecureStoreAdapter.ts @@ -1,16 +1,57 @@ import * as SecureStore from "expo-secure-store"; +import { Platform } from 'react-native'; + +const isWeb = Platform.OS === 'web'; +const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; + +// Cookie storage for web platform +const getCookie = (name: string): string | null => { + if (!isWeb || !isBrowser) return null; + const value = `; ${document.cookie}`; + const parts = value.split(`; ${name}=`); + if (parts.length === 2) { + const cookieValue = parts.pop()?.split(';').shift(); + return cookieValue ? decodeURIComponent(cookieValue) : null; + } + return null; +}; + +const setCookie = (name: string, value: string, days = 7): void => { + if (!isWeb || !isBrowser) return; + const expires = new Date(); + expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000); + document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/`; +}; + +const deleteCookie = (name: string): void => { + if (!isWeb || !isBrowser) return; + document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`; +}; + +// Memory storage as fallback for non-browser environments +const memoryStorage = new Map(); export const ExpoSecureStoreAdapter = { getItem: async (key: string) => { try { - const value = await SecureStore.getItemAsync(key); + let value; + if (isWeb) { + if (isBrowser) { + value = getCookie(key); + } else { + value = memoryStorage.get(key); + } + } else { + value = await SecureStore.getItemAsync(key); + } + if (value) { const { access_token, refresh_token } = JSON.parse(value); return JSON.stringify({access_token, refresh_token, token_type: 'bearer', user: null}) } return null; } catch (error) { - console.error('Error getting item from Securestore:', error); + console.error('Error getting item from storage:', error); return null; } }, @@ -18,17 +59,47 @@ export const ExpoSecureStoreAdapter = { try { const session = JSON.parse(value); const { access_token, refresh_token } = session; - // Store only the tokens in SecureStore - await SecureStore.setItemAsync(key, JSON.stringify({ access_token, refresh_token })); + const storageValue = JSON.stringify({ access_token, refresh_token }); + + if (isWeb) { + if (isBrowser) { + setCookie(key, storageValue); + } else { + memoryStorage.set(key, storageValue); + } + } else { + await SecureStore.setItemAsync(key, storageValue); + } } catch (error) { - console.error('Error setting item to Securestore:', error); + console.error('Error setting item to storage:', error); } }, removeItem: async (key: string): Promise => { try { - await SecureStore.deleteItemAsync(key); + if (isWeb) { + if (isBrowser) { + deleteCookie(key); + } else { + memoryStorage.delete(key); + } + } else { + await SecureStore.deleteItemAsync(key); + } } catch (error) { - console.error('Error deleting item from Securestore:', error); + console.error('Error deleting item from storage:', error); } }, -}; \ No newline at end of file +}; + +if (isWeb) { + // Polyfill for Supabase Auth JS expecting these methods + (ExpoSecureStoreAdapter as any).setValueWithKeyAsync = async (key: string, value: string) => { + return ExpoSecureStoreAdapter.setItem(key, value); + }; + (ExpoSecureStoreAdapter as any).getValueWithKeyAsync = async (key: string) => { + return ExpoSecureStoreAdapter.getItem(key); + }; + (ExpoSecureStoreAdapter as any).deleteValueWithKeyAsync = async (key: string) => { + return ExpoSecureStoreAdapter.removeItem(key); + }; +} \ No newline at end of file From b69cd099e40cdaaeb4f9f9a864c06977ffb58032 Mon Sep 17 00:00:00 2001 From: Luiz Ramos Date: Sat, 21 Jun 2025 15:47:10 -0700 Subject: [PATCH 2/6] Kind of fixed the signin problem. Not entirely sure what was causing it --- app/(tabs)/_layout.tsx | 64 ++++++------------------------------------ app/_layout.tsx | 27 ++++++++++++++++-- app/index.tsx | 2 +- 3 files changed, 34 insertions(+), 59 deletions(-) diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 6460618..4e9dd5e 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,86 +1,38 @@ -import FontAwesome from '@expo/vector-icons/FontAwesome'; -import { Tabs } from 'expo-router'; -import {useEffect, useState} from "react"; -import { ExpoSecureStoreAdapter } from "@/lib/expoSecureStoreAdapter"; +import { Stack } from 'expo-router'; export default function TabLayout() { - const [role, setRole] = useState(null); - - useEffect(() => { - const fetchRole = async () => { - const storedRole = await ExpoSecureStoreAdapter.getItem('role'); - setRole(storedRole); - }; - - fetchRole(); - }, []); - const isAdmin = role === 'administrator' || role === 'supervisor'; return ( - - + , }} /> - , - href: isAdmin ? null : '/(tabs)/add-shift' }} /> - , }} /> - , }} /> - , - }} - /> - {/* These screens are not direct tabs and are handled by file-system routing or other navigation methods */} - {/* Remove the explicit definition for shift-details-page/[id] */} - {/* - - - - - */} - + ); } \ No newline at end of file diff --git a/app/_layout.tsx b/app/_layout.tsx index 2d1da3c..b84d344 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,5 +1,28 @@ import { Stack } from "expo-router"; -import { Slot } from "expo-router"; +import { useEffect } from "react"; +import { useColorScheme } from "react-native"; +import * as SplashScreen from "expo-splash-screen"; + +// Keep the splash screen visible while we fetch resources +SplashScreen.preventAutoHideAsync(); + export default function RootLayout() { - return (); + const colorScheme = useColorScheme(); + + useEffect(() => { + SplashScreen.hideAsync(); + }, []); + + return ( + + + + + + + + + + + ); } diff --git a/app/index.tsx b/app/index.tsx index ff2954c..31c9a71 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -94,4 +94,4 @@ const styles = StyleSheet.create({ textAlign: "left", marginTop: 20, }, -}); \ No newline at end of file +}); \ No newline at end of file From 476f2f600dfb5689af1d8d60490dc2bb20f11b2f Mon Sep 17 00:00:00 2001 From: Luiz Ramos Date: Sat, 21 Jun 2025 16:21:05 -0700 Subject: [PATCH 3/6] Brought back nav --- app/(tabs)/_layout.tsx | 104 +++++++++++++++++++++++----------- lib/expoSecureStoreAdapter.ts | 37 ++++++++++-- 2 files changed, 103 insertions(+), 38 deletions(-) diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 4e9dd5e..a3dbdea 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,38 +1,76 @@ import { Stack } from 'expo-router'; +import { View, TouchableOpacity, Text, StyleSheet } from 'react-native'; +import { useRouter, usePathname } from 'expo-router'; +import FontAwesome from '@expo/vector-icons/FontAwesome'; export default function TabLayout() { + const router = useRouter(); + const pathname = usePathname(); + + const tabs = [ + { name: 'index', title: 'Schedule', icon: 'calendar-check-o' }, + { name: 'add-shift', title: 'Add Shift', icon: 'calendar-plus-o' }, + { name: 'coworkers', title: 'Coworkers', icon: 'users' }, + { name: 'notifications', title: 'Notifications', icon: 'bell' }, + { name: 'profileView', title: 'Profile', icon: 'user' }, + ]; + return ( - - - - - - - + + + + + + + + + + {/* Custom Bottom Tab Bar */} + + {tabs.map((tab) => { + const isActive = pathname === `/(tabs)/${tab.name}`; + return ( + router.push(`/(tabs)/${tab.name}`)} + > + + + {tab.title} + + + ); + })} + + ); -} \ No newline at end of file +} + +const styles = StyleSheet.create({ + tabBar: { + flexDirection: 'row', + backgroundColor: '#fff', + borderTopWidth: 1, + borderTopColor: '#E5E5EA', + paddingBottom: 20, + paddingTop: 10, + }, + tab: { + flex: 1, + alignItems: 'center', + paddingVertical: 8, + }, + tabText: { + fontSize: 12, + marginTop: 4, + color: '#8E8E93', + }, + activeTabText: { + color: '#007AFF', + }, +}); \ No newline at end of file diff --git a/lib/expoSecureStoreAdapter.ts b/lib/expoSecureStoreAdapter.ts index b576276..43e39a3 100644 --- a/lib/expoSecureStoreAdapter.ts +++ b/lib/expoSecureStoreAdapter.ts @@ -46,8 +46,21 @@ export const ExpoSecureStoreAdapter = { } if (value) { - const { access_token, refresh_token } = JSON.parse(value); - return JSON.stringify({access_token, refresh_token, token_type: 'bearer', user: null}) + // Try to parse as JSON first (for session data) + try { + const parsed = JSON.parse(value); + if (parsed.access_token && parsed.refresh_token) { + // This is session data + const { access_token, refresh_token } = parsed; + return JSON.stringify({access_token, refresh_token, token_type: 'bearer', user: null}) + } else { + // This is not session data, return as simple string + return value; + } + } catch { + // Not valid JSON, return as simple string + return value; + } } return null; } catch (error) { @@ -57,9 +70,23 @@ export const ExpoSecureStoreAdapter = { }, setItem: async (key: string, value: string): Promise => { try { - const session = JSON.parse(value); - const { access_token, refresh_token } = session; - const storageValue = JSON.stringify({ access_token, refresh_token }); + let storageValue; + + // Try to parse as JSON first (for session data) + try { + const session = JSON.parse(value); + if (session.access_token && session.refresh_token) { + // This is session data + const { access_token, refresh_token } = session; + storageValue = JSON.stringify({ access_token, refresh_token }); + } else { + // This is not session data, store as simple string + storageValue = value; + } + } catch { + // Not valid JSON, store as simple string + storageValue = value; + } if (isWeb) { if (isBrowser) { From 4a365a2a79f725d711ff278fe1be047cb6265f06 Mon Sep 17 00:00:00 2001 From: Luiz Ramos Date: Sat, 21 Jun 2025 22:12:55 -0700 Subject: [PATCH 4/6] Fixed profile page --- app/(auth)/index.tsx | 23 ++-------------------- app/(tabs)/_layout.tsx | 21 +++++++++++++++++--- app/(tabs)/index.tsx | 12 +++++++++--- app/(tabs)/profileView.tsx | 40 +++++++++++++++++++++++++++++++------- lib/supabaseClient.ts | 4 ---- 5 files changed, 62 insertions(+), 38 deletions(-) diff --git a/app/(auth)/index.tsx b/app/(auth)/index.tsx index 6157c54..90f993f 100644 --- a/app/(auth)/index.tsx +++ b/app/(auth)/index.tsx @@ -10,7 +10,6 @@ import { } from 'react-native'; import {useRouter} from "expo-router"; import {supabase} from "@/lib/supabaseClient"; -import { ExpoSecureStoreAdapter } from '@/lib/expoSecureStoreAdapter'; const { width } = Dimensions.get('window'); // Get the current screen width @@ -44,31 +43,13 @@ export default function LoginPage() { if (data?.user) { console.log("Signed in user:", data.user); + console.log("Session data:", data.session); - // Fetch role using the user ID directly - if (!supabase) { - Alert.alert("Error", "Supabase client is not initialized."); - return; - } - const { data: roleData, error: roleError } = await supabase - .from('profiles') - .select('role') - .eq('profile_id', data.user.id) - .single(); - - if (roleError) { - console.error('Error fetching role:', roleError); - } else { - console.log('User role:', roleData); - await ExpoSecureStoreAdapter.setItem('role', roleData.role?.toLowerCase()); - } - - // Navigate after everything is ready + // Navigate after successful login router.replace('/(tabs)'); } } - await signInWithEmail() } diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index a3dbdea..a9abc98 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -15,6 +15,21 @@ export default function TabLayout() { { name: 'profileView', title: 'Profile', icon: 'user' }, ]; + const handleTabPress = (tabName: string) => { + if (tabName === 'index') { + router.push('/(tabs)' as any); + } else { + router.push(`/(tabs)/${tabName}` as any); + } + }; + + const isTabActive = (tabName: string) => { + if (tabName === 'index') { + return pathname === '/(tabs)/' || pathname === '/(tabs)/index'; + } + return pathname === `/(tabs)/${tabName}`; + }; + return ( @@ -28,16 +43,16 @@ export default function TabLayout() { {/* Custom Bottom Tab Bar */} {tabs.map((tab) => { - const isActive = pathname === `/(tabs)/${tab.name}`; + const isActive = isTabActive(tab.name); return ( router.push(`/(tabs)/${tab.name}`)} + onPress={() => handleTabPress(tab.name)} > diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index e4b471d..d6e40b7 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -101,9 +101,15 @@ export default function UserDashboard() { useEffect(() => { const fetchShiftData = async () => { if (supabase != null) { - const shifts = await getAll(supabase, 'shifts'); - if (shifts) - setShiftData(shifts as Shift[]); + // Check if user is authenticated + const { data: { session } } = await supabase.auth.getSession(); + if (session && session.user) { + const shifts = await getAll(supabase, 'shifts'); + if (shifts) + setShiftData(shifts as Shift[]); + } else { + console.log('No authenticated session found'); + } } } fetchShiftData(); diff --git a/app/(tabs)/profileView.tsx b/app/(tabs)/profileView.tsx index 0a6014f..3be75bb 100644 --- a/app/(tabs)/profileView.tsx +++ b/app/(tabs)/profileView.tsx @@ -23,19 +23,31 @@ const ProfileView = () => { const [error, setError] = useState(null); const router = useRouter(); - // Using the profile_int_id provided - const profileIntId = 5; - const fetchProfileById = useCallback(async () => { setLoading(true); setError(null); try { if (supabase) { + // Get the current session + const { data: { session }, error: sessionError } = await supabase.auth.getSession(); + + if (sessionError) { + console.error('Error getting session:', sessionError); + setError(sessionError.message); + return; + } + + if (!session || !session.user) { + setError('No active session found. Please log in again.'); + return; + } + + // Fetch profile using the user's ID from the session const { data, error } = await supabase .from('profiles') .select('*') - .eq('profile_int_id', profileIntId) + .eq('profile_id', session.user.id) .single(); if (error) { @@ -59,9 +71,23 @@ const ProfileView = () => { fetchProfileById(); }, [fetchProfileById]); - const handleLogout = () => { - router.replace('/(auth)'); // Navigate to the login page - console.log('Logout pressed'); + const handleLogout = async () => { + try { + if (supabase) { + const { error } = await supabase.auth.signOut(); + if (error) { + console.error('Error signing out:', error); + } else { + console.log('Successfully signed out'); + router.replace('/(auth)'); + } + } else { + router.replace('/(auth)'); + } + } catch (error) { + console.error('Error during logout:', error); + router.replace('/(auth)'); + } }; const handleEditProfile = () => { diff --git a/lib/supabaseClient.ts b/lib/supabaseClient.ts index 65460f0..00263c9 100644 --- a/lib/supabaseClient.ts +++ b/lib/supabaseClient.ts @@ -1,7 +1,4 @@ -// @ts-ignore -import * as SecureStore from 'expo-secure-store'; import { createClient } from '@supabase/supabase-js'; -import {ExpoSecureStoreAdapter} from "@/lib/expoSecureStoreAdapter"; const SUPABASE_URL = process.env.EXPO_PUBLIC_SUPABASE_URL; const SUPABASE_ANON_KEY = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY; @@ -13,7 +10,6 @@ if (!SUPABASE_URL || !SUPABASE_ANON_KEY) { export const supabase = SUPABASE_URL && SUPABASE_ANON_KEY ? createClient(SUPABASE_URL, SUPABASE_ANON_KEY, { auth: { - storage: ExpoSecureStoreAdapter, autoRefreshToken: true, persistSession: true, detectSessionInUrl: false, From 73d7c0002076cfc3c8ebec56e4a8e58e2cde865a Mon Sep 17 00:00:00 2001 From: Luiz Ramos Date: Sun, 22 Jun 2025 15:50:57 -0700 Subject: [PATCH 5/6] Brought back logic for dynamic navbar --- app/(auth)/index.tsx | 2 +- app/(auth)/signuppage.tsx | 8 ++++---- app/(tabs)/_layout.tsx | 28 +++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/(auth)/index.tsx b/app/(auth)/index.tsx index 90f993f..19a94e6 100644 --- a/app/(auth)/index.tsx +++ b/app/(auth)/index.tsx @@ -6,7 +6,7 @@ import { TouchableOpacity, StyleSheet, Dimensions, - Alert, + Alert, Platform, } from 'react-native'; import {useRouter} from "expo-router"; import {supabase} from "@/lib/supabaseClient"; diff --git a/app/(auth)/signuppage.tsx b/app/(auth)/signuppage.tsx index 3d83cf9..b290842 100644 --- a/app/(auth)/signuppage.tsx +++ b/app/(auth)/signuppage.tsx @@ -220,10 +220,10 @@ export default function SignUpPage() { {renderInput('Supervisor', 'supervisor', formData.supervisor, handleInputChange)} - Sign Up + Sign Up @@ -275,7 +275,7 @@ const styles = StyleSheet.create({ fontSize: 14, marginTop: 5, }, - button: { + signUpButton: { width: '85%', maxWidth: 400, height: width > 400 ? 50 : 45, @@ -285,7 +285,7 @@ const styles = StyleSheet.create({ borderRadius: 8, marginBottom: 15, }, - buttonText: { + signUpButtonText: { color: '#fff', fontSize: 16, fontWeight: 'bold', diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index a9abc98..6838aca 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -2,14 +2,40 @@ import { Stack } from 'expo-router'; import { View, TouchableOpacity, Text, StyleSheet } from 'react-native'; import { useRouter, usePathname } from 'expo-router'; import FontAwesome from '@expo/vector-icons/FontAwesome'; +import { useEffect, useState } from 'react'; +import { supabase } from '@/lib/supabaseClient'; export default function TabLayout() { const router = useRouter(); const pathname = usePathname(); + const [role, setRole] = useState(null); + + useEffect(() => { + const fetchRole = async () => { + if (supabase) { + const { data: { session } } = await supabase.auth.getSession(); + if (session?.user) { + const { data: roleData } = await supabase + .from('profiles') + .select('role') + .eq('profile_id', session.user.id) + .single(); + + if (roleData?.role) { + setRole(roleData.role.toLowerCase()); + } + } + } + }; + + fetchRole(); + }, []); + + const isAdmin = role === 'administrator' || role === 'supervisor'; const tabs = [ { name: 'index', title: 'Schedule', icon: 'calendar-check-o' }, - { name: 'add-shift', title: 'Add Shift', icon: 'calendar-plus-o' }, + ...(isAdmin ? [{ name: 'add-shift', title: 'Add Shift', icon: 'calendar-plus-o' }] : []), { name: 'coworkers', title: 'Coworkers', icon: 'users' }, { name: 'notifications', title: 'Notifications', icon: 'bell' }, { name: 'profileView', title: 'Profile', icon: 'user' }, From c1a4015c684f9e62bc9ea36cad0b8c67c5ec7b02 Mon Sep 17 00:00:00 2001 From: Luiz Ramos Date: Sun, 22 Jun 2025 16:04:36 -0700 Subject: [PATCH 6/6] Brought back logic for dynamic navbar --- app/(tabs)/_layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 6838aca..10b8ddd 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -31,7 +31,7 @@ export default function TabLayout() { fetchRole(); }, []); - const isAdmin = role === 'administrator' || role === 'supervisor'; + const isAdmin = role === 'admin'; const tabs = [ { name: 'index', title: 'Schedule', icon: 'calendar-check-o' },