summaryrefslogtreecommitdiff
path: root/app/(tabs)/_layout.tsx
diff options
context:
space:
mode:
authorJustZvan <justzvan@justzvan.xyz>2026-02-06 13:22:33 +0100
committerJustZvan <justzvan@justzvan.xyz>2026-02-06 13:22:33 +0100
commit7eb8ccae48b0cc18a9dcaa9c3626a02df8e6d919 (patch)
tree57b7dd06ac9aa7053c671d916f7183e3b4fa9410 /app/(tabs)/_layout.tsx
feat: initial commit!
Diffstat (limited to 'app/(tabs)/_layout.tsx')
-rw-r--r--app/(tabs)/_layout.tsx188
1 files changed, 188 insertions, 0 deletions
diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx
new file mode 100644
index 0000000..6bd6527
--- /dev/null
+++ b/app/(tabs)/_layout.tsx
@@ -0,0 +1,188 @@
+import { Ionicons } from "@expo/vector-icons";
+import * as Notifications from "expo-notifications";
+import { Redirect, Tabs, router } from "expo-router";
+import { useEffect, useRef } from "react";
+import { View } from "react-native";
+import { useAuth } from "../../lib/auth";
+import { DeviceProvider } from "../../lib/device";
+import { t } from "../../lib/locales";
+import {
+ addNotificationReceivedListener,
+ addNotificationResponseListener,
+ getLastNotificationResponse,
+ initializeNotifications,
+} from "../../lib/notifications";
+import { colors } from "../../lib/theme";
+import { LoadingScreen } from "../../lib/ui";
+
+export default function TabsLayout() {
+ const { isLoading, isAuthenticated } = useAuth();
+ const notificationListener = useRef<Notifications.EventSubscription | null>(
+ null
+ );
+ const responseListener = useRef<Notifications.EventSubscription | null>(null);
+
+ useEffect(() => {
+ if (!isAuthenticated) return;
+
+ // Initialize notifications when authenticated
+ initializeNotifications().then(({ permissionStatus, tokenRegistered }) => {
+ console.log(
+ `Notifications initialized: permission=${permissionStatus}, tokenRegistered=${tokenRegistered}`
+ );
+ });
+
+ // Set up notification listeners
+ notificationListener.current = addNotificationReceivedListener(
+ (notification) => {
+ console.log("Notification received:", notification);
+ }
+ );
+
+ responseListener.current = addNotificationResponseListener((response) => {
+ console.log("Notification tapped:", response);
+ const data = response.notification.request.content.data;
+
+ // Navigate based on notification type
+ if (data?.type === "dangerous_content") {
+ router.push("/(tabs)/alerts");
+ } else if (data?.type === "new_contact") {
+ // Navigate to contact detail screen with contact info
+ router.push({
+ pathname: "/(tabs)/contact-detail",
+ params: {
+ contactName: String(data.contactName || "Unknown"),
+ contactIdentifier: String(data.contactIdentifier || "Not provided"),
+ contactType: String(data.contactType || "unknown"),
+ deviceName: String(data.deviceName || "Unknown Device"),
+ },
+ });
+ }
+ });
+
+ // Check if app was opened from a notification (cold start)
+ getLastNotificationResponse().then((response) => {
+ if (response) {
+ const data = response.notification.request.content.data;
+ if (data?.type === "dangerous_content") {
+ router.push("/(tabs)/alerts");
+ } else if (data?.type === "new_contact") {
+ router.push({
+ pathname: "/(tabs)/contact-detail",
+ params: {
+ contactName: String(data.contactName || "Unknown"),
+ contactIdentifier: String(
+ data.contactIdentifier || "Not provided"
+ ),
+ contactType: String(data.contactType || "unknown"),
+ deviceName: String(data.deviceName || "Unknown Device"),
+ },
+ });
+ }
+ }
+ });
+
+ return () => {
+ if (notificationListener.current) {
+ notificationListener.current.remove();
+ }
+ if (responseListener.current) {
+ responseListener.current.remove();
+ }
+ };
+ }, [isAuthenticated]);
+
+ if (isLoading) {
+ return <LoadingScreen />;
+ }
+
+ if (!isAuthenticated) {
+ return <Redirect href="/(auth)/welcome" />;
+ }
+
+ return (
+ <DeviceProvider>
+ <View
+ style={{
+ flex: 1,
+ backgroundColor: colors.background,
+ }}
+ >
+ <Tabs
+ screenOptions={{
+ tabBarShowLabel: true,
+ tabBarActiveTintColor: colors.primary,
+ tabBarInactiveTintColor: colors.onSurfaceVariant,
+ tabBarLabelStyle: {
+ fontSize: 11,
+ fontWeight: "600",
+ },
+ tabBarStyle: {
+ backgroundColor: colors.surfaceContainer,
+ borderTopColor: colors.outline,
+ },
+ headerStyle: {
+ backgroundColor: colors.background,
+ borderWidth: 0,
+ marginBottom: 10,
+ },
+ headerTintColor: colors.onBackground,
+ headerTitleStyle: {
+ color: colors.onBackground,
+ fontSize: 30,
+ fontWeight: "700",
+ },
+ }}
+ >
+ <Tabs.Screen
+ name="index"
+ options={{
+ title: t("home"),
+ tabBarIcon: ({ color, size }) => (
+ <Ionicons name="home" size={size ?? 24} color={color} />
+ ),
+ }}
+ />
+ <Tabs.Screen
+ name="alerts"
+ options={{
+ title: t("alerts"),
+ tabBarIcon: ({ color, size }) => (
+ <Ionicons name="alert-circle" size={size ?? 24} color={color} />
+ ),
+ }}
+ />
+ <Tabs.Screen
+ name="controls"
+ options={{
+ title: t("controls"),
+ tabBarIcon: ({ color, size }) => (
+ <Ionicons
+ name="shield-checkmark"
+ size={size ?? 24}
+ color={color}
+ />
+ ),
+ }}
+ />
+ <Tabs.Screen
+ name="contact-detail"
+ options={{
+ title: "Contact Details",
+ href: null,
+ }}
+ />
+ <Tabs.Screen
+ name="settings"
+ options={{
+ title: t("settings"),
+ tabBarIcon: ({ color, size }) => (
+ <Ionicons name="settings" size={size ?? 24} color={color} />
+ ),
+ }}
+ />
+ </Tabs>
+ </View>
+ </DeviceProvider>
+ );
+}