-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
46b9627
commit 3854745
Showing
10 changed files
with
1,140 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,84 @@ | ||
import { StatusBar } from 'expo-status-bar'; | ||
import { StyleSheet, Text, View } from 'react-native'; | ||
import React, { useEffect, useState } from "react"; | ||
import { NavigationContainer } from "@react-navigation/native"; | ||
import { createNativeStackNavigator } from "@react-navigation/native-stack"; | ||
import * as SplashScreen from "expo-splash-screen"; | ||
import * as Font from "expo-font"; | ||
|
||
import { StyleSheet, Text, View } from "react-native"; | ||
|
||
import { useAppTheme } from "./providers/hooks.js"; | ||
import { AxiosProvider } from "./providers/AxiosProvider"; | ||
import { NotificationProvider } from "./providers/NotificationProvider.js"; | ||
import { ThemeProvider } from "./providers/ThemeProvider"; | ||
import { QueryProvider } from "./providers/QueryProvider.js"; | ||
import { BottomNav } from "./components/BottomNav.js"; | ||
|
||
async function cacheFonts(fonts) { | ||
for (let i = 0; i < fonts.length; i++) { | ||
const element = fonts[i]; | ||
await Font.loadAsync(element); | ||
} | ||
} | ||
|
||
const Stack = createNativeStackNavigator(); | ||
function GetRoutes() { | ||
const { paperTheme } = useAppTheme(); | ||
|
||
return ( | ||
<NavigationContainer | ||
theme={{ | ||
colors: { background: paperTheme.colors.background }, | ||
}} | ||
> | ||
<BottomNav /> | ||
</NavigationContainer> | ||
); | ||
} | ||
|
||
export default function App() { | ||
const [appIsReady, setAppIsReady] = useState(false); | ||
|
||
useEffect(() => { | ||
async function loadResourcesAndDataAsync() { | ||
try { | ||
await SplashScreen.preventAutoHideAsync(); | ||
|
||
await cacheFonts([ | ||
{ MagazineLetter: require("./assets/fonts/MagazineLetter.otf") }, | ||
]); | ||
} catch (e) { | ||
console.warn(e); | ||
} finally { | ||
setAppIsReady(true); | ||
SplashScreen.hideAsync(); | ||
} | ||
} | ||
|
||
loadResourcesAndDataAsync(); | ||
}, []); | ||
|
||
if (!appIsReady) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<View style={styles.container}> | ||
<Text>Open up App.js to start working on your app!</Text> | ||
<StatusBar style="auto" /> | ||
</View> | ||
<ThemeProvider> | ||
<NotificationProvider> | ||
<AxiosProvider> | ||
<QueryProvider> | ||
<GetRoutes /> | ||
</QueryProvider> | ||
</AxiosProvider> | ||
</NotificationProvider> | ||
</ThemeProvider> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
backgroundColor: '#fff', | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
backgroundColor: "#fff", | ||
alignItems: "center", | ||
justifyContent: "center", | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export const API_URL = | ||
process.env.NODE_ENV === "development" | ||
? process.env.EXPO_PUBLIC_LOCAL_API_URL | ||
: process.env.EXPO_PUBLIC_API_URL; | ||
|
||
export const API_KEY = process.env.EXPO_PUBLIC_API_KEY; | ||
export const FAKE_API = process.env.EXPO_PUBLIC_FAKE_API; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import React, { createContext, useContext } from "react"; | ||
import axios from "axios"; | ||
|
||
import { NotificationContext } from "./NotificationProvider"; | ||
import { API_URL, API_KEY, FAKE_API } from "../config/config"; | ||
import { fakeData } from "../config/fakeData"; | ||
|
||
const AxiosContext = createContext(); | ||
const { Provider } = AxiosContext; | ||
|
||
function AxiosProvider({ children }) { | ||
const { showNotification } = useContext(NotificationContext); | ||
|
||
const publicAxios = axios.create({ | ||
baseURL: `${API_URL}`, | ||
}); | ||
|
||
publicAxios.interceptors.request.use( | ||
(config) => { | ||
if (FAKE_API) { | ||
throw { isLocal: true, data: fakeData }; | ||
} else { | ||
config.headers.Accept = "application/json"; | ||
config.headers["x-api-key"] = API_KEY; | ||
} | ||
return config; | ||
}, | ||
(error) => { | ||
return error?.isLocal ? Promise.resolve(error) : Promise.reject(error); | ||
} | ||
); | ||
|
||
publicAxios.interceptors.response.use( | ||
(response) => { | ||
return response.data; | ||
}, | ||
(error) => { | ||
if (error?.isLocal) { | ||
return Promise.resolve(error.data); | ||
} | ||
|
||
showNotification({ | ||
title: "Request failed", | ||
description: | ||
error.response?.data?.message || error.message || "Please try again.", | ||
type: "error", | ||
}); | ||
return Promise.reject(error); | ||
} | ||
); | ||
|
||
return ( | ||
<Provider | ||
value={{ | ||
publicAxios, | ||
}} | ||
> | ||
{children} | ||
</Provider> | ||
); | ||
} | ||
|
||
export { AxiosContext, AxiosProvider }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { createContext, useEffect, useState } from "react"; | ||
import { Platform } from "react-native"; | ||
import * as Notifications from "expo-notifications"; | ||
import { GestureHandlerRootView } from "react-native-gesture-handler"; | ||
import { | ||
Easing, | ||
Notifier, | ||
NotifierComponents, | ||
NotifierWrapper, | ||
} from "react-native-notifier"; | ||
import * as Device from "expo-device"; | ||
import { LoadingIcon } from "../components/LoadingIcon"; | ||
import { | ||
getScheduledNotifications, | ||
setScheduledNotifications, | ||
} from "../storage/securestorage"; | ||
|
||
const NotificationContext = createContext(null); | ||
const { Provider } = NotificationContext; | ||
|
||
Notifications.setNotificationHandler({ | ||
handleNotification: async () => ({ | ||
shouldShowAlert: true, | ||
shouldPlaySound: false, | ||
shouldSetBadge: false, | ||
}), | ||
}); | ||
|
||
function NotificationProvider({ children }) { | ||
const [loading, setLoading] = useState(true); | ||
useEffect(() => { | ||
async function registerForPushNotificationsAsync() { | ||
if (Platform.OS === "android") { | ||
await Notifications.setNotificationChannelAsync("default", { | ||
name: "default", | ||
importance: Notifications.AndroidImportance.MAX, | ||
vibrationPattern: [0, 250, 250, 250], | ||
lightColor: "#FF231F7C", | ||
}); | ||
} | ||
if (Device.isDevice) await Notifications.getPermissionsAsync(); | ||
setLoading(false); | ||
} | ||
registerForPushNotificationsAsync(); | ||
}, []); | ||
|
||
async function scheduleEventNotification(event) { | ||
const scheduledNotifications = await getScheduledNotifications(); | ||
if (!scheduledNotifications[event.id]) { | ||
const reminderDate = new Date(event.date); | ||
reminderDate.setDate(reminderDate.getDate() - 1); | ||
await Notifications.scheduleNotificationAsync({ | ||
content: { | ||
title: "Event Reminder", | ||
body: `Reminder: ${event.name} is due tomorrow!`, | ||
}, | ||
trigger: { date: reminderDate }, | ||
}); | ||
scheduledNotifications[event.id] = true; | ||
await setScheduledNotifications(scheduledNotifications); | ||
} | ||
} | ||
|
||
async function schedulePushNotification(content, delay = 2) { | ||
await Notifications.scheduleNotificationAsync({ | ||
content, | ||
trigger: { seconds: delay }, | ||
}); | ||
} | ||
|
||
async function pushNotification(content) { | ||
await Notifications.scheduleNotificationAsync({ | ||
content, | ||
trigger: { seconds: 0 }, | ||
}); | ||
} | ||
|
||
function showNotification(content) { | ||
Notifier.showNotification({ | ||
duration: 3000, | ||
showAnimationDuration: 800, | ||
showEasing: Easing.ease, | ||
hideOnPress: true, | ||
Component: content.type | ||
? NotifierComponents.Alert | ||
: NotifierComponents.Notification, | ||
componentProps: { | ||
alertType: content.type, | ||
}, | ||
...content, | ||
}); | ||
} | ||
|
||
if (loading) return <LoadingIcon fullSize={true} />; | ||
|
||
return ( | ||
<GestureHandlerRootView style={{ flex: 1 }}> | ||
<NotifierWrapper queueMode="reset"> | ||
<Provider | ||
value={{ | ||
schedulePushNotification, | ||
pushNotification, | ||
showNotification, | ||
scheduleEventNotification, | ||
}} | ||
> | ||
{children} | ||
</Provider> | ||
</NotifierWrapper> | ||
</GestureHandlerRootView> | ||
); | ||
} | ||
|
||
export { NotificationContext, NotificationProvider }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React, { createContext } from "react"; | ||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; | ||
|
||
const QueryContext = createContext(null); | ||
const { Provider } = QueryContext; | ||
|
||
const queryClient = new QueryClient(); | ||
|
||
function QueryProvider({ children }) { | ||
return ( | ||
<QueryClientProvider client={queryClient}> | ||
<Provider | ||
value={{ | ||
queryClient, | ||
}} | ||
> | ||
{children} | ||
</Provider> | ||
</QueryClientProvider> | ||
); | ||
} | ||
|
||
export { QueryContext, QueryProvider }; |
Oops, something went wrong.