Skip to content

Commit

Permalink
ft(#67): setup in-app notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
fredshema committed Dec 5, 2024
1 parent f0f9a3c commit d591407
Show file tree
Hide file tree
Showing 78 changed files with 5,022 additions and 7,881 deletions.
1 change: 0 additions & 1 deletion %ProgramData%/Microsoft/Windows/UUS/State/_active.uusver

This file was deleted.

3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ expo-env.d.ts
coverage/**/*
.idea/
android/
ios/
ios/
# google-services.json
59 changes: 38 additions & 21 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
"slug": "devpulse",
"version": "1.0.1",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "devpulse",
"scheme": "pulseapp",
"userInterfaceStyle": "automatic",
"newArchEnabled": false,
"icon": "./assets/images/icon.png",
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.atlp.pulseapp",
Expand All @@ -15,11 +16,12 @@
}
},
"android": {
"package": "com.atlp.pulseapp",
"googleServicesFile": "./google-services.json",
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.atlp.pulseapp",
"intentFilters": [
{
"action": "VIEW",
Expand All @@ -35,25 +37,40 @@
}
]
},
"plugins": ["expo-router", "expo-font", "expo-localization", [
"expo-image-picker",
{
"photosPermission": "The app needs access to your photos to let you upload a profile picture."
}
],
[
"expo-splash-screen",
{
"backgroundColor": "#E0E7FF",
"image": "./assets/images/icon.png",
"dark": {
"web": {
"bundler": "metro"
},
"plugins": [
"expo-router",
"expo-font",
"expo-localization",
[
"expo-notifications",
{
"icon": "./assets/images/icon.png",
"color": "#E0E7FF",
"mode": "production"
}
],
[
"expo-splash-screen",
{
"backgroundColor": "#E0E7FF",
"image": "./assets/images/icon.png",
"backgroundColor": "#020917"
},
"imageWidth": 128
}
]
],
"dark": {
"image": "./assets/images/icon.png",
"backgroundColor": "#020917"
},
"imageWidth": 128
}
],
[
"expo-image-picker",
{
"photosPermission": "The app needs access to your photos to let you upload a profile picture."
}
]
],
"experiments": {
"typedRoutes": true
},
Expand Down
2 changes: 1 addition & 1 deletion app/(onboarding)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function AppOnboardingLayout() {
const currentTime = Math.floor(Date.now() / 1000);

if (expiryTime > currentTime) {
return router.push('/dashboard');
return router.replace('/dashboard');
}

await AsyncStorage.removeItem('authToken');
Expand Down
67 changes: 35 additions & 32 deletions app/(onboarding)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,38 +53,41 @@ export default function AppOnboarding() {

return (
<ScrollView
className="flex-1"
bounces={false}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
bounces={false}
contentContainerClassName="flex-1"
>
{/* Pager View for Onboarding Screens */}
<PagerView
initialPage={page}
style={{ minHeight: 580 }}
onPageSelected={(p) => setPage(p.nativeEvent.position)}
ref={pagerViewRef}
>
{pages.map((page, index) => (
<View key={index} className={`flex-1 px-8 py-12 ${bgColor}`}>
<Image
source={page.image}
contentFit="contain"
className="items-end justify-center mb-6"
style={{ width: '100%', flex: 1 }}
/>
<Text
style={{ fontSize: 24 }}
className={`font-Inter-SemiBold text-center leading-9 ${textColor}`}
>
{page.content}
</Text>
</View>
))}
</PagerView>
<View className="flex-1 flex-row justify-center items-center">
<PagerView
className="bg-red-500 justify-center items-center"
initialPage={page}
style={{ height: '100%', width: '100%' }}
onPageSelected={(p) => setPage(p.nativeEvent.position)}
ref={pagerViewRef}
>
{pages.map((page, index) => (
<View key={index} className={`flex-1 px-8 py-12 ${bgColor}`}>
<Image
source={page.image}
contentFit="contain"
className="items-end justify-center mb-6"
style={{ width: '100%', flex: 1 }}
/>
<Text
style={{ fontSize: 24 }}
className={`font-Inter-SemiBold text-center leading-9 ${textColor}`}
>
{page.content}
</Text>
</View>
))}
</PagerView>
</View>

{/* Pagination Dots */}
<View className={`flex-1 flex-row justify-center items-center gap-3 ${bgColor}`}>
<View className={`flex-row w-full justify-center items-center gap-3 ${bgColor}`}>
<View className={`rounded-full w-4 h-4 ${getDotColor(0)}`}></View>
<View className={`rounded-full w-4 h-4 ${getDotColor(1)}`}></View>
<View className={`rounded-full w-4 h-4 ${getDotColor(2)}`}></View>
Expand All @@ -96,12 +99,12 @@ export default function AppOnboarding() {
</View>

{/* Get Started Button */}
<View className={`flex-1 flex-row justify-center items-center ${bgColor}`}>
<TouchableOpacity>
<Text
className="text-lg font-Inter-Medium dark:text-white"
onPress={() => router.push('/auth/login')}
>
<View className={`flex-row justify-center items-center my-8`}>
<TouchableOpacity
onPress={() => router.push('/auth/login')}
className="bg-action-500 py-4 px-16 rounded-lg"
>
<Text className="text-lg font-Inter-Medium dark:text-white">
{t('onboarding.getStarted')}
</Text>
</TouchableOpacity>
Expand Down
2 changes: 1 addition & 1 deletion app/+not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function NotFoundScreen() {
{t('notFound.title')}
</Text>

<Link href="/" className="mt-12">
<Link href="/(onboarding)" className="mt-12">
<View className="px-6 py-4 rounded-full bg-action-500">
<Text className="text-lg text-white">{t('notFound.goHome')}</Text>
</View>
Expand Down
32 changes: 18 additions & 14 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useColorScheme } from '@/components/useColorScheme';
import '@/global.css';
import { client } from '@/graphql/client';
import NotificationsProvider from '@/providers/notifications';
import { ApolloProvider } from '@apollo/client';
import { useApolloClientDevTools } from '@dev-plugins/apollo-client';
import {
Inter_400Regular,
Inter_500Medium,
Expand All @@ -11,22 +11,27 @@ import {
} from '@expo-google-fonts/inter';
import FontAwesome from '@expo/vector-icons/FontAwesome';
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { isDevice } from 'expo-device';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect } from 'react';
import 'react-native-reanimated';
import { ToastProvider } from 'react-native-toast-notifications';
export { ErrorBoundary } from 'expo-router';
import '../internationalization/index';
import { NotificationProvider } from '@/hooks/useNotification';

export const unstable_settings = {
initialRouteName: '(onboarding)',
};

SplashScreen.preventAutoHideAsync();

if (isDevice) {
SplashScreen.setOptions({
duration: 1000,
fade: true,
});
}

export default function RootLayout() {
const [loaded, error] = useFonts({
Inter_400Regular,
Expand Down Expand Up @@ -55,21 +60,20 @@ export default function RootLayout() {

function RootLayoutNav() {
const colorScheme = useColorScheme();
useApolloClientDevTools(client);

return (

<ApolloProvider client={client}>
<ToastProvider placement="top" duration={5000}>
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="(onboarding)" options={{ headerShown: false }} />
<Stack.Screen name="auth" options={{ headerShown: false }} />
<Stack.Screen name="dashboard" options={{ headerShown: false }} />
</Stack>
</ThemeProvider>
<NotificationsProvider>
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="(onboarding)" />
<Stack.Screen name="auth" />
<Stack.Screen name="dashboard" />
</Stack>
</ThemeProvider>
</NotificationsProvider>
</ToastProvider>
</ApolloProvider>

);
}
4 changes: 3 additions & 1 deletion app/auth/forgot-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ export default function ResetPassword() {
keyboardType="email-address"
/>
</View>
{formik.touched.email && formik.errors.email && <Text className="mb-4 text-error-500">{t('forgotPassword.errorEmail')}</Text>}
{formik.touched.email && formik.errors.email && (
<Text className="mb-4 text-error-500">{t('forgotPassword.errorEmail')}</Text>
)}
<TouchableOpacity
testID="submit-button"
onPress={() => formik.handleSubmit()}
Expand Down
66 changes: 16 additions & 50 deletions app/auth/login/index.tsx → app/auth/login.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,21 @@
import OrgLogin from '@/components/Login/OrgLogin';
import UserLogin from '@/components/Login/UserLogin';
import TwoFactorScreen from '../two-factor';
import { LOGIN_MUTATION, ORG_LOGIN_MUTATION } from '@/graphql/mutations/login.mutation';
import { ApolloError, useApolloClient, useMutation } from '@apollo/client';
import { ApolloError, useMutation } from '@apollo/client';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Href, useLocalSearchParams, useRouter } from 'expo-router';
import { useEffect,useState } from 'react';
import { useToast } from 'react-native-toast-notifications';
import {ToastAndroid } from 'react-native';
import { RelativePathString, useLocalSearchParams, useRouter } from 'expo-router';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';

class ErrorHandler {
static handleNetworkError() {
ToastAndroid.show('There was a problem contacting the server', ToastAndroid.LONG);
}

static handleInvalidCredentials() {
ToastAndroid.show('Error Invalid credentials',ToastAndroid.LONG);
}

static handleCustomError(message: string | undefined) {
ToastAndroid.show('Error:' + message,ToastAndroid.LONG);
}

static handleGeneralError() {
ToastAndroid.show('Error An unexpected error occurred.',ToastAndroid.LONG);
}
}
import { useToast } from 'react-native-toast-notifications';

export default function SignInOrganization() {
const toast = useToast();
const router = useRouter();
const {t} = useTranslation();
const { t } = useTranslation();
const [orgLoginSuccess, setOrgLoginSuccess] = useState(false);
const [orgLoginMutation] = useMutation(ORG_LOGIN_MUTATION);
const [LoginUser] = useMutation(LOGIN_MUTATION);
const params = useLocalSearchParams<{ redirect?: string; logout: string }>();
const client = useApolloClient();

useEffect(() => {
if (params.logout == '1') {
while (router.canGoBack()) {
router.back();
}
client.clearStore();
router.replace('/auth/login');
}
}, []);
const params = useLocalSearchParams<{ redirect?: string }>();

const onOrgSubmit = async (values: any) => {
try {
Expand All @@ -69,13 +38,13 @@ export default function SignInOrganization() {
setOrgLoginSuccess(true);
},
onError(err: any) {
toast.show(err.message,{
toast.show(err.message, {
type: 'fail',
placement : 'top',
duration : 5000,
animationType : 'slide-in',
placement: 'top',
duration: 5000,
animationType: 'slide-in',
style: { backgroundColor: 'red' },
})
});
},
});
} catch (err: any) {
Expand Down Expand Up @@ -105,13 +74,10 @@ export default function SignInOrganization() {
if (data.loginUser.user.role === 'trainee') {
await AsyncStorage.setItem('authToken', token);

while (router.canGoBack()) {
router.back();
}

router.canDismiss() && router.dismissAll();
params.redirect
? router.push(`${params.redirect}` as Href<string | object>)
: router.push('/dashboard');
? router.replace(`${params.redirect}` as RelativePathString)
: router.replace('/dashboard');
return;
} else {
toast.show(t('toasts.auth.loginErr'), {
Expand All @@ -129,7 +95,7 @@ export default function SignInOrganization() {
}
else {
await AsyncStorage.setItem('authToken', data.loginUser.token);
router.push('/dashboard');
router.replace('/dashboard');
}
},
onError: (err) => {
Expand All @@ -143,7 +109,7 @@ export default function SignInOrganization() {
},
});
} catch (error: any) {
toast.show(t('toasts.auth.generalError') , { type: 'danger' });
toast.show(t('toasts.auth.generalError'), { type: 'danger' });
}
};

Expand Down
Loading

0 comments on commit d591407

Please sign in to comment.