Compare commits
3 Commits
main
...
notificati
| Author | SHA1 | Date | |
|---|---|---|---|
| d27c01ed56 | |||
| 34680a4c38 | |||
| 43c8c105cf |
@@ -1,9 +1,11 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import { StackCustom, ViewWrapper } from "@/components";
|
import { ButtonCustom, StackCustom, ViewWrapper } from "@/components";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { useAuth } from "@/hooks/use-auth";
|
import { useAuth } from "@/hooks/use-auth";
|
||||||
|
import { useNotificationStore } from "@/hooks/use-notification-store";
|
||||||
import Home_BottomFeatureSection from "@/screens/Home/bottomFeatureSection";
|
import Home_BottomFeatureSection from "@/screens/Home/bottomFeatureSection";
|
||||||
|
import HeaderBell from "@/screens/Home/HeaderBell";
|
||||||
import Home_ImageSection from "@/screens/Home/imageSection";
|
import Home_ImageSection from "@/screens/Home/imageSection";
|
||||||
import TabSection from "@/screens/Home/tabSection";
|
import TabSection from "@/screens/Home/tabSection";
|
||||||
import { tabsHome } from "@/screens/Home/tabsList";
|
import { tabsHome } from "@/screens/Home/tabsList";
|
||||||
@@ -13,15 +15,19 @@ import { apiVersion } from "@/service/api-config";
|
|||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { Redirect, router, Stack, useFocusEffect } from "expo-router";
|
import { Redirect, router, Stack, useFocusEffect } from "expo-router";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { RefreshControl } from "react-native";
|
import { RefreshControl, Text, View } from "react-native";
|
||||||
|
|
||||||
export default function Application() {
|
export default function Application() {
|
||||||
const { token, user, userData } = useAuth();
|
const { token, user, userData } = useAuth();
|
||||||
const [data, setData] = useState<any>();
|
const [data, setData] = useState<any>();
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
console.log("[User] >>", JSON.stringify(user?.id, null, 2));
|
// console.log("[User] >>", JSON.stringify(user?.id, null, 2));
|
||||||
|
|
||||||
|
// const { notifications } = useNotificationStore();
|
||||||
|
// const unreadCount = notifications.filter((n) => !n.read).length;
|
||||||
|
// console.log("UNREAD", notifications)
|
||||||
// ‼️ Untuk cek apakah: 1. user ada, 2. user punya profile, 3. accept temrs of forum nya ada atau tidak
|
// ‼️ Untuk cek apakah: 1. user ada, 2. user punya profile, 3. accept temrs of forum nya ada atau tidak
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
onLoadData();
|
onLoadData();
|
||||||
@@ -82,17 +88,47 @@ export default function Application() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
headerRight: () => (
|
headerRight: () => <HeaderBell />,
|
||||||
<Ionicons
|
// headerRight: () => {
|
||||||
disabled={true}
|
// return (
|
||||||
name="notifications"
|
// <View style={{ position: "relative" }}>
|
||||||
size={20}
|
// <Ionicons
|
||||||
color={MainColor.placeholder}
|
// name="notifications"
|
||||||
onPress={() => {
|
// size={20}
|
||||||
router.push("/notifications");
|
// color={MainColor.yellow}
|
||||||
}}
|
// onPress={() => {
|
||||||
/>
|
// router.push("/notifications");
|
||||||
),
|
// }}
|
||||||
|
// />
|
||||||
|
// {unreadCount > 0 && (
|
||||||
|
// <View
|
||||||
|
// style={{
|
||||||
|
// position: "absolute",
|
||||||
|
// top: -4,
|
||||||
|
// right: -4,
|
||||||
|
// backgroundColor: "red",
|
||||||
|
// borderRadius: 8,
|
||||||
|
// minWidth: 16,
|
||||||
|
// height: 16,
|
||||||
|
// justifyContent: "center",
|
||||||
|
// alignItems: "center",
|
||||||
|
// paddingHorizontal: 2,
|
||||||
|
// }}
|
||||||
|
// >
|
||||||
|
// <Text
|
||||||
|
// style={{
|
||||||
|
// color: "white",
|
||||||
|
// fontSize: 10,
|
||||||
|
// fontWeight: "bold",
|
||||||
|
// }}
|
||||||
|
// >
|
||||||
|
// {unreadCount > 9 ? "9+" : unreadCount}
|
||||||
|
// </Text>
|
||||||
|
// </View>
|
||||||
|
// )}
|
||||||
|
// </View>
|
||||||
|
// );
|
||||||
|
// },
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ViewWrapper
|
<ViewWrapper
|
||||||
@@ -109,6 +145,8 @@ export default function Application() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<StackCustom>
|
<StackCustom>
|
||||||
|
<ButtonCustom onPress={() => router.push("./test-notifications")}>Test Notif</ButtonCustom>
|
||||||
|
|
||||||
<Home_ImageSection />
|
<Home_ImageSection />
|
||||||
|
|
||||||
<Home_FeatureSection />
|
<Home_FeatureSection />
|
||||||
|
|||||||
48
app/(application)/(user)/test-notifications.tsx
Normal file
48
app/(application)/(user)/test-notifications.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import {
|
||||||
|
ButtonCustom,
|
||||||
|
NewWrapper,
|
||||||
|
StackCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
} from "@/components";
|
||||||
|
import { apiNotificationsSend } from "@/service/api-notifications";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function TestNotification() {
|
||||||
|
const [data, setData] = useState("");
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
console.log("[Data Dikirim]", data);
|
||||||
|
const response = await apiNotificationsSend({
|
||||||
|
data: {
|
||||||
|
fcmToken:
|
||||||
|
"cVmHm-3P4E-1vjt6AA9kSF:APA91bHTkHjGTLxrFsb6Le6bZmzboZhwMGYXU4p0FP9yEeXixLDXNKS4F5vLuZV3sRgSnjjQsPpLOgstVLHJB8VJTObctKLdN-CxAp4dnP7Jbc_mH53jWvs",
|
||||||
|
title: "Test dari Backend (App Router)!",
|
||||||
|
body: data,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("[RES SEND NOTIF]", JSON.stringify(response.data, null, 2));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<NewWrapper>
|
||||||
|
<StackCustom>
|
||||||
|
<TextInputCustom
|
||||||
|
required
|
||||||
|
label="Nama"
|
||||||
|
placeholder="Masukkan nama"
|
||||||
|
value={data}
|
||||||
|
onChangeText={(text) => setData(text)}
|
||||||
|
/>
|
||||||
|
<ButtonCustom
|
||||||
|
onPress={() => {
|
||||||
|
handleSubmit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Kirim
|
||||||
|
</ButtonCustom>
|
||||||
|
</StackCustom>
|
||||||
|
</NewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,15 @@
|
|||||||
|
import NotificationInitializer from "@/components/_ShareComponent/NotificationInitializer";
|
||||||
import { AuthProvider } from "@/context/AuthContext";
|
import { AuthProvider } from "@/context/AuthContext";
|
||||||
|
import { useForegroundNotifications } from "@/hooks/use-foreground-notifications";
|
||||||
|
import {
|
||||||
|
NotificationProvider,
|
||||||
|
useNotificationStore,
|
||||||
|
} from "@/hooks/use-notification-store";
|
||||||
import AppRoot from "@/screens/RootLayout/AppRoot";
|
import AppRoot from "@/screens/RootLayout/AppRoot";
|
||||||
|
import messaging, {
|
||||||
|
FirebaseMessagingTypes,
|
||||||
|
} from "@react-native-firebase/messaging";
|
||||||
|
import { useEffect } from "react";
|
||||||
import "react-native-gesture-handler";
|
import "react-native-gesture-handler";
|
||||||
import { SafeAreaProvider } from "react-native-safe-area-context";
|
import { SafeAreaProvider } from "react-native-safe-area-context";
|
||||||
import Toast from "react-native-toast-message";
|
import Toast from "react-native-toast-message";
|
||||||
@@ -7,12 +17,15 @@ import Toast from "react-native-toast-message";
|
|||||||
export default function RootLayout() {
|
export default function RootLayout() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SafeAreaProvider>
|
<NotificationProvider>
|
||||||
<AuthProvider>
|
<SafeAreaProvider>
|
||||||
<AppRoot />
|
<AuthProvider>
|
||||||
</AuthProvider>
|
<NotificationInitializer />
|
||||||
</SafeAreaProvider>
|
<AppRoot />
|
||||||
<Toast />
|
</AuthProvider>
|
||||||
|
</SafeAreaProvider>
|
||||||
|
<Toast />
|
||||||
|
</NotificationProvider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
49
components/_ShareComponent/NotificationInitializer.tsx
Normal file
49
components/_ShareComponent/NotificationInitializer.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// src/components/NotificationInitializer.tsx
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import messaging from "@react-native-firebase/messaging";
|
||||||
|
import { useForegroundNotifications } from "@/hooks/use-foreground-notifications";
|
||||||
|
import {
|
||||||
|
useNotificationStore,
|
||||||
|
} from "@/hooks/use-notification-store";
|
||||||
|
import type { FirebaseMessagingTypes } from "@react-native-firebase/messaging";
|
||||||
|
|
||||||
|
export default function NotificationInitializer() {
|
||||||
|
// 1. Ambil token FCM (opsional, hanya untuk log)
|
||||||
|
useEffect(() => {
|
||||||
|
const getFCMToken = async () => {
|
||||||
|
if (!messaging().isSupported()) return;
|
||||||
|
const authStatus = await messaging().requestPermission();
|
||||||
|
if (authStatus === messaging.AuthorizationStatus.AUTHORIZED) {
|
||||||
|
const token = await messaging().getToken();
|
||||||
|
console.log("✅ FCM Token:", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
getFCMToken();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 2. Setup handler notifikasi
|
||||||
|
const { addNotification } = useNotificationStore();
|
||||||
|
|
||||||
|
const handleForegroundNotification = (
|
||||||
|
message: FirebaseMessagingTypes.RemoteMessage
|
||||||
|
) => {
|
||||||
|
const title = message.notification?.title || "Notifikasi";
|
||||||
|
const body = message.notification?.body || "";
|
||||||
|
const rawData = message.data || {};
|
||||||
|
|
||||||
|
const safeData: Record<string, string> = {};
|
||||||
|
for (const key in rawData) {
|
||||||
|
safeData[key] = typeof rawData[key] === "string"
|
||||||
|
? rawData[key]
|
||||||
|
: JSON.stringify(rawData[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("📥 Menambahkan ke store:", { title, body, safeData });
|
||||||
|
addNotification({ title, body, data: safeData });
|
||||||
|
console.log("✅ Notifikasi ditambahkan ke state");
|
||||||
|
};
|
||||||
|
|
||||||
|
useForegroundNotifications(handleForegroundNotification);
|
||||||
|
|
||||||
|
return null; // komponen ini tidak merender apa-apa
|
||||||
|
}
|
||||||
23
hooks/use-foreground-notifications.ts
Normal file
23
hooks/use-foreground-notifications.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import messaging, {
|
||||||
|
FirebaseMessagingTypes,
|
||||||
|
} from "@react-native-firebase/messaging";
|
||||||
|
|
||||||
|
// Gunakan tipe resmi dari library
|
||||||
|
type RemoteMessage = FirebaseMessagingTypes.RemoteMessage;
|
||||||
|
|
||||||
|
export function useForegroundNotifications(
|
||||||
|
onMessageReceived: (message: RemoteMessage) => void
|
||||||
|
) {
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = messaging().onMessage((remoteMessage) => {
|
||||||
|
console.log(
|
||||||
|
"🔔 Notifikasi diterima saat app aktif:",
|
||||||
|
JSON.stringify(remoteMessage, null, 2)
|
||||||
|
);
|
||||||
|
onMessageReceived(remoteMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
return unsubscribe;
|
||||||
|
}, [onMessageReceived]);
|
||||||
|
}
|
||||||
52
hooks/use-notification-store.tsx
Normal file
52
hooks/use-notification-store.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// hooks/useNotificationStore.ts
|
||||||
|
import { createContext, useContext, useState, ReactNode } from 'react';
|
||||||
|
import type { FirebaseMessagingTypes } from '@react-native-firebase/messaging';
|
||||||
|
|
||||||
|
type AppNotification = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
data?: Record<string, string>;
|
||||||
|
read: boolean;
|
||||||
|
timestamp: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const NotificationContext = createContext<{
|
||||||
|
notifications: AppNotification[];
|
||||||
|
addNotification: (notif: Omit<AppNotification, 'id' | 'read' | 'timestamp'>) => void;
|
||||||
|
markAsRead: (id: string) => void;
|
||||||
|
}>({
|
||||||
|
notifications: [],
|
||||||
|
addNotification: () => {},
|
||||||
|
markAsRead: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const NotificationProvider = ({ children }: { children: ReactNode }) => {
|
||||||
|
const [notifications, setNotifications] = useState<AppNotification[]>([]);
|
||||||
|
|
||||||
|
const addNotification = (notif: Omit<AppNotification, 'id' | 'read' | 'timestamp'>) => {
|
||||||
|
setNotifications(prev => [
|
||||||
|
{
|
||||||
|
...notif,
|
||||||
|
id: Date.now().toString(),
|
||||||
|
read: false,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
...prev,
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const markAsRead = (id: string) => {
|
||||||
|
setNotifications(prev =>
|
||||||
|
prev.map(n => (n.id === id ? { ...n, read: true } : n))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NotificationContext.Provider value={{ notifications, addNotification, markAsRead }}>
|
||||||
|
{children}
|
||||||
|
</NotificationContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useNotificationStore = () => useContext(NotificationContext);
|
||||||
File diff suppressed because one or more lines are too long
@@ -51,6 +51,7 @@ target 'HIPMIBadungConnect' do
|
|||||||
:privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
|
:privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
pod 'Firebase'
|
||||||
pod 'Firebase/Messaging'
|
pod 'Firebase/Messaging'
|
||||||
|
|
||||||
# @generated begin post_installer - expo prebuild (DO NOT MODIFY) sync-4092f82b887b5b9edb84642c2a56984d69b9a403
|
# @generated begin post_installer - expo prebuild (DO NOT MODIFY) sync-4092f82b887b5b9edb84642c2a56984d69b9a403
|
||||||
|
|||||||
116
ios/Podfile.lock
116
ios/Podfile.lock
@@ -279,31 +279,83 @@ PODS:
|
|||||||
- EXUpdatesInterface (2.0.0):
|
- EXUpdatesInterface (2.0.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- FBLazyVector (0.81.4)
|
- FBLazyVector (0.81.4)
|
||||||
- Firebase/CoreOnly (12.7.0):
|
- Firebase (12.6.0):
|
||||||
- FirebaseCore (~> 12.7.0)
|
- Firebase/Core (= 12.6.0)
|
||||||
- Firebase/Messaging (12.7.0):
|
- Firebase/Core (12.6.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseMessaging (~> 12.7.0)
|
- FirebaseAnalytics (~> 12.6.0)
|
||||||
- FirebaseCore (12.7.0):
|
- Firebase/CoreOnly (12.6.0):
|
||||||
- FirebaseCoreInternal (~> 12.7.0)
|
- FirebaseCore (~> 12.6.0)
|
||||||
|
- Firebase/Messaging (12.6.0):
|
||||||
|
- Firebase/CoreOnly
|
||||||
|
- FirebaseMessaging (~> 12.6.0)
|
||||||
|
- FirebaseAnalytics (12.6.0):
|
||||||
|
- FirebaseAnalytics/Default (= 12.6.0)
|
||||||
|
- FirebaseCore (~> 12.6.0)
|
||||||
|
- FirebaseInstallations (~> 12.6.0)
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
|
- nanopb (~> 3.30910.0)
|
||||||
|
- FirebaseAnalytics/Default (12.6.0):
|
||||||
|
- FirebaseCore (~> 12.6.0)
|
||||||
|
- FirebaseInstallations (~> 12.6.0)
|
||||||
|
- GoogleAppMeasurement/Default (= 12.6.0)
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
|
- nanopb (~> 3.30910.0)
|
||||||
|
- FirebaseCore (12.6.0):
|
||||||
|
- FirebaseCoreInternal (~> 12.6.0)
|
||||||
- GoogleUtilities/Environment (~> 8.1)
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
- GoogleUtilities/Logger (~> 8.1)
|
- GoogleUtilities/Logger (~> 8.1)
|
||||||
- FirebaseCoreInternal (12.7.0):
|
- FirebaseCoreExtension (12.6.0):
|
||||||
|
- FirebaseCore (~> 12.6.0)
|
||||||
|
- FirebaseCoreInternal (12.6.0):
|
||||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
- FirebaseInstallations (12.7.0):
|
- FirebaseInstallations (12.6.0):
|
||||||
- FirebaseCore (~> 12.7.0)
|
- FirebaseCore (~> 12.6.0)
|
||||||
- GoogleUtilities/Environment (~> 8.1)
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||||
- PromisesObjC (~> 2.4)
|
- PromisesObjC (~> 2.4)
|
||||||
- FirebaseMessaging (12.7.0):
|
- FirebaseMessaging (12.6.0):
|
||||||
- FirebaseCore (~> 12.7.0)
|
- FirebaseCore (~> 12.6.0)
|
||||||
- FirebaseInstallations (~> 12.7.0)
|
- FirebaseInstallations (~> 12.6.0)
|
||||||
- GoogleDataTransport (~> 10.1)
|
- GoogleDataTransport (~> 10.1)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/Environment (~> 8.1)
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
- GoogleUtilities/Reachability (~> 8.1)
|
- GoogleUtilities/Reachability (~> 8.1)
|
||||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
|
- GoogleAdsOnDeviceConversion (3.2.0):
|
||||||
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
|
- GoogleUtilities/Logger (~> 8.1)
|
||||||
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
|
- nanopb (~> 3.30910.0)
|
||||||
|
- GoogleAppMeasurement/Core (12.6.0):
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
|
- nanopb (~> 3.30910.0)
|
||||||
|
- GoogleAppMeasurement/Default (12.6.0):
|
||||||
|
- GoogleAdsOnDeviceConversion (~> 3.2.0)
|
||||||
|
- GoogleAppMeasurement/Core (= 12.6.0)
|
||||||
|
- GoogleAppMeasurement/IdentitySupport (= 12.6.0)
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
|
- nanopb (~> 3.30910.0)
|
||||||
|
- GoogleAppMeasurement/IdentitySupport (12.6.0):
|
||||||
|
- GoogleAppMeasurement/Core (= 12.6.0)
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
|
- nanopb (~> 3.30910.0)
|
||||||
- GoogleDataTransport (10.1.0):
|
- GoogleDataTransport (10.1.0):
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- PromisesObjC (~> 2.4)
|
- PromisesObjC (~> 2.4)
|
||||||
@@ -317,6 +369,9 @@ PODS:
|
|||||||
- GoogleUtilities/Logger (8.1.0):
|
- GoogleUtilities/Logger (8.1.0):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/MethodSwizzler (8.1.0):
|
||||||
|
- GoogleUtilities/Logger
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
- GoogleUtilities/Network (8.1.0):
|
- GoogleUtilities/Network (8.1.0):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- "GoogleUtilities/NSData+zlib"
|
- "GoogleUtilities/NSData+zlib"
|
||||||
@@ -2198,6 +2253,14 @@ PODS:
|
|||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- ReactNativeDependencies
|
- ReactNativeDependencies
|
||||||
- Yoga
|
- Yoga
|
||||||
|
- RNFBApp (23.7.0):
|
||||||
|
- Firebase/CoreOnly (= 12.6.0)
|
||||||
|
- React-Core
|
||||||
|
- RNFBMessaging (23.7.0):
|
||||||
|
- Firebase/Messaging (= 12.6.0)
|
||||||
|
- FirebaseCoreExtension
|
||||||
|
- React-Core
|
||||||
|
- RNFBApp
|
||||||
- RNGestureHandler (2.28.0):
|
- RNGestureHandler (2.28.0):
|
||||||
- hermes-engine
|
- hermes-engine
|
||||||
- RCTRequired
|
- RCTRequired
|
||||||
@@ -2559,6 +2622,7 @@ DEPENDENCIES:
|
|||||||
- ExpoWebBrowser (from `../node_modules/expo-web-browser/ios`)
|
- ExpoWebBrowser (from `../node_modules/expo-web-browser/ios`)
|
||||||
- EXUpdatesInterface (from `../node_modules/expo-updates-interface/ios`)
|
- EXUpdatesInterface (from `../node_modules/expo-updates-interface/ios`)
|
||||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
|
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
|
||||||
|
- Firebase
|
||||||
- Firebase/Messaging
|
- Firebase/Messaging
|
||||||
- hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
|
- hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
|
||||||
- RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`)
|
- RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`)
|
||||||
@@ -2633,6 +2697,8 @@ DEPENDENCIES:
|
|||||||
- ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)
|
- ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)
|
||||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||||
- "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)"
|
- "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)"
|
||||||
|
- "RNFBApp (from `../node_modules/@react-native-firebase/app`)"
|
||||||
|
- "RNFBMessaging (from `../node_modules/@react-native-firebase/messaging`)"
|
||||||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
||||||
- "rnmapbox-maps (from `../node_modules/@rnmapbox/maps`)"
|
- "rnmapbox-maps (from `../node_modules/@rnmapbox/maps`)"
|
||||||
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
||||||
@@ -2645,10 +2711,14 @@ DEPENDENCIES:
|
|||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
- Firebase
|
- Firebase
|
||||||
|
- FirebaseAnalytics
|
||||||
- FirebaseCore
|
- FirebaseCore
|
||||||
|
- FirebaseCoreExtension
|
||||||
- FirebaseCoreInternal
|
- FirebaseCoreInternal
|
||||||
- FirebaseInstallations
|
- FirebaseInstallations
|
||||||
- FirebaseMessaging
|
- FirebaseMessaging
|
||||||
|
- GoogleAdsOnDeviceConversion
|
||||||
|
- GoogleAppMeasurement
|
||||||
- GoogleDataTransport
|
- GoogleDataTransport
|
||||||
- GoogleUtilities
|
- GoogleUtilities
|
||||||
- libavif
|
- libavif
|
||||||
@@ -2878,6 +2948,10 @@ EXTERNAL SOURCES:
|
|||||||
:path: "../node_modules/@react-native-async-storage/async-storage"
|
:path: "../node_modules/@react-native-async-storage/async-storage"
|
||||||
RNDateTimePicker:
|
RNDateTimePicker:
|
||||||
:path: "../node_modules/@react-native-community/datetimepicker"
|
:path: "../node_modules/@react-native-community/datetimepicker"
|
||||||
|
RNFBApp:
|
||||||
|
:path: "../node_modules/@react-native-firebase/app"
|
||||||
|
RNFBMessaging:
|
||||||
|
:path: "../node_modules/@react-native-firebase/messaging"
|
||||||
RNGestureHandler:
|
RNGestureHandler:
|
||||||
:path: "../node_modules/react-native-gesture-handler"
|
:path: "../node_modules/react-native-gesture-handler"
|
||||||
rnmapbox-maps:
|
rnmapbox-maps:
|
||||||
@@ -2929,11 +3003,15 @@ SPEC CHECKSUMS:
|
|||||||
ExpoWebBrowser: b973e1351fdcf5fec0c400997b1851f5a8219ec3
|
ExpoWebBrowser: b973e1351fdcf5fec0c400997b1851f5a8219ec3
|
||||||
EXUpdatesInterface: 5adf50cb41e079c861da6d9b4b954c3db9a50734
|
EXUpdatesInterface: 5adf50cb41e079c861da6d9b4b954c3db9a50734
|
||||||
FBLazyVector: 9e0cd874afd81d9a4d36679daca991b58b260d42
|
FBLazyVector: 9e0cd874afd81d9a4d36679daca991b58b260d42
|
||||||
Firebase: 2d19a10c9a2e48ac532a4303115d3fc9b2798396
|
Firebase: a451a7b61536298fd5cbfe3a746fd40443a50679
|
||||||
FirebaseCore: c7b57863ce0859281a66d16ca36d665c45d332b5
|
FirebaseAnalytics: d0a97a0db6425e5a5d966340b87f92ca7b13a557
|
||||||
FirebaseCoreInternal: 571a2dd8c975410966199623351db3a3265c874d
|
FirebaseCore: 0e38ad5d62d980a47a64b8e9301ffa311457be04
|
||||||
FirebaseInstallations: 6d05424a046b68ca146b4de4376f05b4e9262fc3
|
FirebaseCoreExtension: 032fd6f8509e591fda8cb76f6651f20d926b121f
|
||||||
FirebaseMessaging: b5f7bdc62b91b6102015991fb7bc6fa75f643908
|
FirebaseCoreInternal: 69bf1306a05b8ac43004f6cc1f804bb7b05b229e
|
||||||
|
FirebaseInstallations: 631b38da2e11a83daa4bfb482f79d286a5dfa7ad
|
||||||
|
FirebaseMessaging: a61bc42dcab3f7a346d94bbb54dab2c9435b18b2
|
||||||
|
GoogleAdsOnDeviceConversion: d68c69dd9581a0f5da02617b6f377e5be483970f
|
||||||
|
GoogleAppMeasurement: 3bf40aff49a601af5da1c3345702fcb4991d35ee
|
||||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||||
hermes-engine: 35c763d57c9832d0eef764316ca1c4d043581394
|
hermes-engine: 35c763d57c9832d0eef764316ca1c4d043581394
|
||||||
@@ -3016,6 +3094,8 @@ SPEC CHECKSUMS:
|
|||||||
ReactNativeDependencies: ed6d1e64802b150399f04f1d5728ec16b437251e
|
ReactNativeDependencies: ed6d1e64802b150399f04f1d5728ec16b437251e
|
||||||
RNCAsyncStorage: 3a4f5e2777dae1688b781a487923a08569e27fe4
|
RNCAsyncStorage: 3a4f5e2777dae1688b781a487923a08569e27fe4
|
||||||
RNDateTimePicker: be0e44bcb9ed0607c7c5f47dbedd88cf091f6791
|
RNDateTimePicker: be0e44bcb9ed0607c7c5f47dbedd88cf091f6791
|
||||||
|
RNFBApp: 0c4cadae3900893d4631ea9a9effd14f853cd8e0
|
||||||
|
RNFBMessaging: 873220424f6f6aa5c787baf5c7099e1e2ba087c9
|
||||||
RNGestureHandler: 2914750df066d89bf9d8f48a10ad5f0051108ac3
|
RNGestureHandler: 2914750df066d89bf9d8f48a10ad5f0051108ac3
|
||||||
rnmapbox-maps: 3c20ce786a7991498445c32de4fe4244e32aa0ee
|
rnmapbox-maps: 3c20ce786a7991498445c32de4fe4244e32aa0ee
|
||||||
RNReanimated: 8d3a14606ad49f022c17d9e12a2d339e9e5ad9b0
|
RNReanimated: 8d3a14606ad49f022c17d9e12a2d339e9e5ad9b0
|
||||||
@@ -3031,6 +3111,6 @@ SPEC CHECKSUMS:
|
|||||||
Yoga: 051f086b5ccf465ff2ed38a2cf5a558ae01aaaa1
|
Yoga: 051f086b5ccf465ff2ed38a2cf5a558ae01aaaa1
|
||||||
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5
|
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5
|
||||||
|
|
||||||
PODFILE CHECKSUM: 61c4a9d35618e5f2a420f47e5a24c89e86706f00
|
PODFILE CHECKSUM: 9c1ecbc7e57ca21dc7c93635b18e66f8f6d7bdd9
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
45
screens/Home/HeaderBell.tsx
Normal file
45
screens/Home/HeaderBell.tsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// components/HeaderBell.tsx
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { View, Text } from "react-native";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import { useNotificationStore } from "@/hooks/use-notification-store";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
|
||||||
|
export default function HeaderBell() {
|
||||||
|
const { notifications } = useNotificationStore();
|
||||||
|
const unreadCount = notifications.filter((n) => !n.read).length;
|
||||||
|
console.log("NOTIF:", JSON.stringify(notifications, null, 2));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{ position: "relative" }}>
|
||||||
|
<Ionicons
|
||||||
|
name="notifications"
|
||||||
|
size={20}
|
||||||
|
color={MainColor.yellow}
|
||||||
|
onPress={() => {
|
||||||
|
router.push("/notifications");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{unreadCount > 0 && (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: -4,
|
||||||
|
right: -4,
|
||||||
|
backgroundColor: "red",
|
||||||
|
borderRadius: 8,
|
||||||
|
minWidth: 16,
|
||||||
|
height: 16,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
paddingHorizontal: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text style={{ color: "white", fontSize: 10, fontWeight: "bold" }}>
|
||||||
|
{unreadCount > 9 ? "9+" : unreadCount}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
service/api-notifications.ts
Normal file
23
service/api-notifications.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { apiConfig } from "./api-config";
|
||||||
|
|
||||||
|
|
||||||
|
type NotificationProp = {
|
||||||
|
fcmToken: string
|
||||||
|
title: string,
|
||||||
|
body: Object
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function apiNotificationsSend({ data }: { data: NotificationProp }) {
|
||||||
|
try {
|
||||||
|
const response = await apiConfig.post(`/mobile/notifications`, {
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Fecth Notif", response.data)
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user