Skip to content

Commit c2d89b9

Browse files
authored
ch(#44): add redirect handler (#47)
fix: login labels
1 parent 1a47570 commit c2d89b9

File tree

15 files changed

+346
-4499
lines changed

15 files changed

+346
-4499
lines changed

Diff for: __tests__/components/sidebar.test.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ describe('Sidebar', () => {
4141
const attendanceItem = getByText('Attendance').parent;
4242
expect(attendanceItem?.props.style).toEqual(
4343
expect.objectContaining({
44-
backgroundColor: expect.stringContaining('indigo')
44+
backgroundColor: expect.stringContaining('indigo'),
4545
})
4646
);
4747
});
@@ -56,11 +56,10 @@ describe('Sidebar', () => {
5656
it('navigates and closes sidebar when an item is pressed', async () => {
5757
const { getByText } = render(<Sidebar onClose={mockOnClose} />);
5858
fireEvent.press(getByText('Attendance'));
59-
59+
6060
await waitFor(() => {
6161
expect(mockPush).toHaveBeenCalledWith('/dashboard/trainee');
6262
expect(mockOnClose).toHaveBeenCalled();
6363
});
6464
});
65-
66-
});
65+
});

Diff for: app/(onboarding)/index.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ export default function AppOnboarding() {
7979
</View>
8080
<View className={`flex-1 flex-row justify-center items-center ${bgColor}`}>
8181
<TouchableOpacity>
82-
<Text className={`text-lg font-Inter-Medium ${textColor}`} onPress={() => router.push('/auth/login')}>
82+
<Text
83+
className="text-lg font-Inter-Medium dark:text-white"
84+
onPress={() => router.push('/redirect?path=/auth/login&dest=app')}
85+
>
8386
Get Started
8487
</Text>
8588
</TouchableOpacity>

Diff for: app/+not-found.tsx

+17-27
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,30 @@
11
import { Link } from 'expo-router';
2-
import { StyleSheet } from 'react-native';
32

43
import { Text, View } from '@/components/Themed';
5-
import React from 'react';
4+
import { Image } from 'expo-image';
65

76
export default function NotFoundScreen() {
87
return (
98
<>
10-
<View style={styles.container}>
11-
<Text style={styles.title}>This screen doesn't exist.</Text>
9+
<View className="flex-1 justify-center items-center p-8">
10+
<View className="h-60 w-full mb-10">
11+
<Image
12+
source={require('@/assets/images/page_not_found.svg')}
13+
contentFit="contain"
14+
className="mb-6 justify-center items-end"
15+
style={{ width: '100%', flex: 1 }}
16+
/>
17+
</View>
18+
<Text className="text-2xl font-Inter-Bold dark:text-white text-center max-w-64">
19+
Oops! We can't find the page you're looking for.
20+
</Text>
1221

13-
<Link href="/" style={styles.link}>
14-
<Text style={styles.linkText}>Go to home screen!</Text>
22+
<Link href="/" className="mt-12">
23+
<View className="py-4 px-6 bg-action-500 rounded-full">
24+
<Text className="text-lg text-white">Go to home screen!</Text>
25+
</View>
1526
</Link>
1627
</View>
1728
</>
1829
);
1930
}
20-
21-
const styles = StyleSheet.create({
22-
container: {
23-
flex: 1,
24-
alignItems: 'center',
25-
justifyContent: 'center',
26-
padding: 20,
27-
},
28-
title: {
29-
fontSize: 20,
30-
fontWeight: 'bold',
31-
},
32-
link: {
33-
marginTop: 15,
34-
paddingVertical: 15,
35-
},
36-
linkText: {
37-
fontSize: 14,
38-
color: '#2e78b7',
39-
},
40-
});

Diff for: app/_layout.tsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ function RootLayoutNav() {
5757

5858
return (
5959
<ApolloProvider client={client}>
60-
<ToastProvider>
61-
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
62-
<Stack>
63-
<Stack.Screen name="(onboarding)" options={{ headerShown: false }} />
64-
<Stack.Screen name="auth" options={{ headerShown: false }} />
65-
<Stack.Screen name="dashboard" options={{ headerShown: false }}/>
66-
</Stack>
67-
</ThemeProvider>
60+
<ToastProvider placement="top" duration={5000}>
61+
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
62+
<Stack screenOptions={{ headerShown: false }}>
63+
<Stack.Screen name="(onboarding)" options={{ headerShown: false }} />
64+
<Stack.Screen name="auth" options={{ headerShown: false }} />
65+
<Stack.Screen name="dashboard" options={{ headerShown: false }} />
66+
</Stack>
67+
</ThemeProvider>
6868
</ToastProvider>
6969
</ApolloProvider>
7070
);

Diff for: app/auth/register.tsx

+12-7
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ import {
1616
ActivityIndicator,
1717
Alert,
1818
TextInput,
19-
ToastAndroid,
2019
TouchableOpacity,
2120
useColorScheme,
2221
} from 'react-native';
2322
import { SvgXml } from 'react-native-svg';
23+
import { useToast } from 'react-native-toast-notifications';
2424

2525
type FormValues = {
2626
firstName: string;
@@ -44,6 +44,7 @@ type RegisterResponse = {
4444

4545
export default function RegisterForm() {
4646
const router = useRouter();
47+
const toast = useToast();
4748
const params = useLocalSearchParams();
4849
const colorScheme = useColorScheme();
4950

@@ -69,7 +70,9 @@ export default function RegisterForm() {
6970
} else {
7071
router.push('/dashboard/trainee');
7172
}
72-
} catch (err) {}
73+
} catch (err) {
74+
toast.show('Invalid token or expired token', { type: 'danger' });
75+
}
7376
}
7477
};
7578

@@ -94,19 +97,19 @@ export default function RegisterForm() {
9497
});
9598

9699
if (data) {
97-
ToastAndroid.show('Successfully registered', ToastAndroid.LONG);
100+
toast.show('Successfully registered', { type: 'success' });
98101
await AsyncStorage.setItem('org_token', data.createUser.token);
99102
router.push('/auth/login');
100103
}
101104

102105
if (errors) {
103-
ToastAndroid.show(errors[0].message, ToastAndroid.LONG);
106+
toast.show(errors[0].message, { type: 'danger' });
104107
}
105108
} catch (error) {
106109
if (error instanceof ApolloError) {
107-
ToastAndroid.show(`Error: ${error.message}`, ToastAndroid.LONG);
110+
toast.show(`Error: ${error.message}`, { type: 'danger' });
108111
} else {
109-
ToastAndroid.show(`Error: Unknown error`, ToastAndroid.LONG);
112+
toast.show(`Error: Unknown error`, { type: 'danger' });
110113
}
111114
}
112115
setLoading(false);
@@ -121,7 +124,9 @@ export default function RegisterForm() {
121124
setEmail(parsedToken.email);
122125
setOrgName(parsedToken.name);
123126
}
124-
} catch (err) {}
127+
} catch (err) {
128+
toast.show('Invalid token or expired token', { type: 'danger' });
129+
}
125130
}, []);
126131

127132
return (

Diff for: app/dashboard/_layout.tsx

+25-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
1-
import { lightLogoIcon, darkLogoIcon, menu, lightNotifyIcon, darkNotifyIcon } from '@/assets/Icons/dashboard/Icons';
1+
import {
2+
lightLogoIcon,
3+
darkLogoIcon,
4+
menu,
5+
lightNotifyIcon,
6+
darkNotifyIcon,
7+
} from '@/assets/Icons/dashboard/Icons';
28
import { Slot } from 'expo-router';
39
import { useEffect, useState } from 'react';
4-
import { KeyboardAvoidingView, Platform, ScrollView, TouchableOpacity, View, useColorScheme, Image } from 'react-native';
10+
import {
11+
KeyboardAvoidingView,
12+
Platform,
13+
ScrollView,
14+
TouchableOpacity,
15+
View,
16+
useColorScheme,
17+
Image,
18+
} from 'react-native';
519
import { useSafeAreaInsets } from 'react-native-safe-area-context';
620
import { SvgXml } from 'react-native-svg';
721
import Sidebar from '@/components/sidebar';
@@ -13,7 +27,6 @@ export default function AuthLayout() {
1327

1428
const toggleSidebar = () => setIsSidebarOpen(!isSidebarOpen);
1529

16-
1730
return (
1831
<KeyboardAvoidingView
1932
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
@@ -39,17 +52,17 @@ export default function AuthLayout() {
3952
<TouchableOpacity onPress={toggleSidebar}>
4053
<SvgXml xml={menu} width={40} height={40} />
4154
</TouchableOpacity>
42-
<SvgXml
43-
xml={colorScheme === 'dark' ? darkLogoIcon : lightLogoIcon}
44-
width={100}
45-
height={40}
46-
/>
55+
<SvgXml
56+
xml={colorScheme === 'dark' ? darkLogoIcon : lightLogoIcon}
57+
width={100}
58+
height={40}
59+
/>
4760
</View>
4861
<View className="flex-row gap-5">
4962
<TouchableOpacity>
50-
<SvgXml
51-
xml={colorScheme === 'dark' ? darkNotifyIcon : lightNotifyIcon}
52-
width={25}
63+
<SvgXml
64+
xml={colorScheme === 'dark' ? darkNotifyIcon : lightNotifyIcon}
65+
width={25}
5366
height={40}
5467
/>
5568
</TouchableOpacity>
@@ -67,9 +80,7 @@ export default function AuthLayout() {
6780
</ScrollView>
6881
{isSidebarOpen && (
6982
<View className="absolute top-0 left-0 bottom-0">
70-
<Sidebar
71-
onClose={toggleSidebar}
72-
/>
83+
<Sidebar onClose={toggleSidebar} />
7384
</View>
7485
)}
7586
</KeyboardAvoidingView>

Diff for: app/dashboard/index.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ const Dashboard = () => {
66
const colorScheme = useColorScheme();
77
return (
88
<View>
9-
<Text className={`ml-2 text-base ${colorScheme === 'light' ? 'text-black' : 'text-white'}`}>Dashboard Coming soon</Text>
9+
<Text className={`ml-2 text-base ${colorScheme === 'light' ? 'text-black' : 'text-white'}`}>
10+
Dashboard Coming soon
11+
</Text>
1012
</View>
1113
);
1214
};

Diff for: app/redirect.tsx

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Text, View } from '@/components/Themed';
2+
import { Href, Link, useLocalSearchParams, useRouter } from 'expo-router';
3+
import { useEffect } from 'react';
4+
import { Linking } from 'react-native';
5+
import { useToast } from 'react-native-toast-notifications';
6+
7+
type RedirectParams = {
8+
path: string;
9+
dest: 'app' | 'web';
10+
};
11+
12+
export default function Redirect() {
13+
const router = useRouter();
14+
const toast = useToast();
15+
const { path, dest } = useLocalSearchParams<RedirectParams>();
16+
17+
useEffect(() => {
18+
(async () => {
19+
if (!path) {
20+
router.replace('/');
21+
return;
22+
}
23+
24+
if (dest === 'web') {
25+
try {
26+
const url = path.startsWith('http') ? path : `https://${path}`;
27+
await Linking.openURL(url);
28+
} catch (error) {
29+
toast.show('Unable to open link', {
30+
type: 'danger',
31+
duration: 5000,
32+
placement: 'top',
33+
});
34+
}
35+
} else {
36+
router.replace(path as Href);
37+
}
38+
})();
39+
}, [path, dest]);
40+
41+
return (
42+
<View className="flex-1 items-center justify-center">
43+
<Text className="text-xl dark:text-white">Redirecting...</Text>
44+
<Link href="/" className="mt-12">
45+
<View className="py-3 px-4 bg-action-500 rounded-full">
46+
<Text className="text-lg text-white">Go to home screen!</Text>
47+
</View>
48+
</Link>
49+
</View>
50+
);
51+
}

Diff for: assets/Icons/auth/Icons.tsx

-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)