Skip to content
This repository was archived by the owner on Oct 8, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 3 additions & 22 deletions app/(auth)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
TouchableOpacity,
StyleSheet,
Dimensions,
Alert,
Alert, Platform,

Check warning on line 9 in app/(auth)/index.tsx

View workflow job for this annotation

GitHub Actions / on pull request / build-and-test

'Platform' is defined but never used
} from 'react-native';
import {useRouter} from "expo-router";
import {supabase} from "@/lib/supabaseClient";
import * as SecureStore from 'expo-secure-store';

const { width } = Dimensions.get('window'); // Get the current screen width

Expand Down Expand Up @@ -44,31 +43,13 @@

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 SecureStore.setItemAsync('role', roleData.role?.toLowerCase());
}

// Navigate after everything is ready
// Navigate after successful login
router.replace('/(tabs)');
}
}


await signInWithEmail()
}

Expand Down
27 changes: 15 additions & 12 deletions app/(auth)/signuppage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@
}

try {
// Sign up with Supabase
const { data: authData, error: authError } = await supabase.auth.signUp({
email: formData.email,
password: formData.password,
Expand All @@ -116,22 +115,27 @@
}

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);
Alert.alert('Error', 'An unexpected error occurred. Please try again.');
}
}, [formData, router]);

Check warning on line 138 in app/(auth)/signuppage.tsx

View workflow job for this annotation

GitHub Actions / on pull request / build-and-test

React Hook useCallback has an unnecessary dependency: 'router'. Either exclude it or remove the dependency array. Outer scope values like 'router' aren't valid dependencies because mutating them doesn't re-render the component

const renderInput = useCallback(
(
Expand Down Expand Up @@ -218,7 +222,6 @@
<TouchableOpacity
style={[styles.signUpButton, !isFormValid && { backgroundColor: '#ccc' }]}
onPress={handleSignUp}
disabled={!isFormValid}
>
<Text style={styles.signUpButtonText}>Sign Up</Text>
</TouchableOpacity>
Expand Down
177 changes: 104 additions & 73 deletions app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,86 +1,117 @@
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 { Tabs } from 'expo-router';
import {useEffect, useState} from "react";
import * as SecureStore from "expo-secure-store";
import { useEffect, useState } from 'react';
import { supabase } from '@/lib/supabaseClient';

export default function TabLayout() {
const router = useRouter();
const pathname = usePathname();
const [role, setRole] = useState<string | null>(null);

useEffect(() => {
const fetchRole = async () => {
const storedRole = await SecureStore.getItemAsync('role');
setRole(storedRole);
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 isAdmin = role === 'admin';

const tabs = [
{ name: 'index', title: 'Schedule', icon: 'calendar-check-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' },
];

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 (
<Tabs screenOptions={{ tabBarActiveTintColor: 'blue', tabBarStyle: { display: 'flex' }, }}>
<Tabs.Screen
name="index"
options={{
title: 'Schedule',
tabBarIcon: ({ color }) => <FontAwesome size={28} name="calendar-check-o" color={color} />,
}}
/>
<Tabs.Screen
name="add-shift"
options={{
title: 'Add Shift',
tabBarIcon: ({color}) => <FontAwesome size={28} name="calendar-plus-o" color={color}/>,
href: isAdmin ? null : '/(tabs)/add-shift'
}}
/>
<Tabs.Screen
name="coworkers"
options={{
title: 'Coworkers',
tabBarIcon: ({ color }) => <FontAwesome size={28} name="users" color={color} />,
}}
/>
<Tabs.Screen
name="notifications"
options={{
title: 'Notifications',
tabBarIcon: ({ color }) => <FontAwesome size={28} name="bell" color={color} />,
}}
/>
<Tabs.Screen
name="profileView"
options={{
title: 'Profile',
tabBarIcon: ({ color }) => <FontAwesome size={28} name="user" color={color} />,
}}
/>
{/* 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] */}
{/*
<Tabs.Screen
name="department-org"
options={{
href: null
}}
/>
<Tabs.Screen
name="help"
options={{
href: null
}}
/>
<Tabs.Screen
name="shift-details-page/[id]"
options={{
href: null
}}
/>
<Tabs.Screen
name="editProfile"
options={{
href: null
}}
/>
*/}
</Tabs>
<View style={{ flex: 1 }}>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" />
<Stack.Screen name="add-shift" />
<Stack.Screen name="coworkers" />
<Stack.Screen name="notifications" />
<Stack.Screen name="profileView" />
</Stack>

{/* Custom Bottom Tab Bar */}
<View style={styles.tabBar}>
{tabs.map((tab) => {
const isActive = isTabActive(tab.name);
return (
<TouchableOpacity
key={tab.name}
style={styles.tab}
onPress={() => handleTabPress(tab.name)}
>
<FontAwesome
size={24}
name={tab.icon as any}
color={isActive ? '#007AFF' : '#8E8E93'}
/>
<Text style={[styles.tabText, isActive && styles.activeTabText]}>
{tab.title}
</Text>
</TouchableOpacity>
);
})}
</View>
</View>
);
}
}

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',
},
});
12 changes: 9 additions & 3 deletions app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
40 changes: 33 additions & 7 deletions app/(tabs)/profileView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,31 @@ const ProfileView = () => {
const [error, setError] = useState<string | null>(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) {
Expand All @@ -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 = () => {
Expand Down
Loading
Loading