Compare commits

..

17 Commits

Author SHA1 Message Date
60e5c0663c Merge pull request 'Checkpoint 2' (#28) from checkpoint-2/12-dec-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/28
2025-12-12 14:59:49 +08:00
ae0bf4dd60 Merge pull request 'Fix QC ( Ayu )' (#27) from qc/10-dec-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/27
2025-12-10 17:39:06 +08:00
bb63f7fa9a Merge pull request 'Apple reject and QC: Ayu' (#26) from qc/9-dec-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/26
2025-12-09 17:41:55 +08:00
9742c1849a Merge pull request 'Fix QC Admin' (#25) from qc/5-dec-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/25
2025-12-05 17:23:16 +08:00
2265ef64cc Merge pull request 'QC Hipmi' (#24) from qc/4-dec-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/24
2025-12-04 17:47:01 +08:00
fbd096af9c Merge pull request 'Fix rejected Apple' (#23) from qc/3-dec-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/23
2025-12-03 17:24:07 +08:00
5019b00f59 Merge pull request 'Clearing apple rejected & QC' (#22) from qc/2-dec-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/22
2025-12-02 17:50:22 +08:00
249ada221b Merge pull request 'QC: Inno dan Pak Jun' (#21) from qc/1-dec-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/21
2025-12-01 17:45:26 +08:00
19814315a4 Merge pull request 'Fix loader dan prebuild' (#20) from apple-reject/28-nov-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/20
2025-11-28 17:32:49 +08:00
77ef3a055e Merge pull request 'Halaman unblock user' (#19) from apple-reject/28-nov-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/19
2025-11-28 13:58:01 +08:00
aba3ad8ded Merge pull request 'apple-rejected' (#18) from apple-rejected/26-nov-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/18
2025-11-27 05:57:04 +08:00
7799c7720d Merge pull request 'Fix map android :' (#17) from fix-map/21-nov-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/17
2025-11-21 17:45:18 +08:00
2926b6eac1 Merge pull request 'delete-account' (#16) from delete-account/20-nov-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/16
2025-11-20 15:44:03 +08:00
637d444c5c Merge pull request 'Versi 1.0.1 : Qr Code & Start notifications' (#11) from staging into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/11
2025-11-14 17:46:16 +08:00
a614cfaac9 Merge pull request 'QR Code & Notification' (#10) from qc/14-nov-25 into staging
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/10
2025-11-14 17:45:29 +08:00
1a7ad58505 Merge pull request 'QR Code Scan' (#9) from qrcode-access/13-nov-25 into staging
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/9
2025-11-13 17:43:08 +08:00
7612be7366 Merge pull request 'UPDATE Build' (#8) from build/12-nov-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/8
2025-11-12 15:03:36 +08:00
21 changed files with 48 additions and 785 deletions

View File

@@ -15,7 +15,7 @@
<data android:scheme="https"/>
</intent>
</queries>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:enableOnBackInvokedCallback="false" android:fullBackupContent="@xml/secure_store_backup_rules" android:dataExtractionRules="@xml/secure_store_data_extraction_rules">
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:enableOnBackInvokedCallback="false">
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/notification_icon_color"/>
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon"/>
<meta-data android:name="expo.modules.notifications.default_notification_color" android:resource="@color/notification_icon_color"/>

View File

@@ -21,7 +21,7 @@ export default {
"Aplikasi membutuhkan akses lokasi untuk menampilkan peta.",
},
associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"],
buildNumber: "16",
buildNumber: "15",
},
android: {

View File

@@ -1,6 +1,4 @@
import { BackButton } from "@/components";
import { IconPlus } from "@/components/_Icon";
import { IconDot } from "@/components/_Icon/IconComponent";
import LeftButtonCustom from "@/components/Button/BackButton";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
@@ -58,12 +56,6 @@ export default function UserLayout() {
options={{
title: "Notifikasi",
headerLeft: () => <BackButton />,
headerRight: () => (
<IconPlus
color={MainColor.yellow}
onPress={() => router.push("/test-notifications")}
/>
),
}}
/>

View File

@@ -1,10 +1,9 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */
import { ButtonCustom, StackCustom, ViewWrapper } from "@/components";
import { StackCustom, ViewWrapper } from "@/components";
import { MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth";
import Home_BottomFeatureSection from "@/screens/Home/bottomFeatureSection";
import HeaderBell from "@/screens/Home/HeaderBell";
import Home_ImageSection from "@/screens/Home/imageSection";
import TabSection from "@/screens/Home/tabSection";
import { tabsHome } from "@/screens/Home/tabsList";
@@ -13,14 +12,16 @@ import { apiUser } from "@/service/api-client/api-user";
import { apiVersion } from "@/service/api-config";
import { Ionicons } from "@expo/vector-icons";
import { Redirect, router, Stack, useFocusEffect } from "expo-router";
import { useCallback, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { RefreshControl } from "react-native";
export default function Application() {
const { token, user, userData } = useAuth();
const [data, setData] = useState<any>();
const [refreshing, setRefreshing] = useState(false);
console.log("[User] >>", JSON.stringify(user?.id, null, 2));
// ‼️ Untuk cek apakah: 1. user ada, 2. user punya profile, 3. accept temrs of forum nya ada atau tidak
useFocusEffect(
useCallback(() => {
onLoadData();
@@ -81,7 +82,17 @@ export default function Application() {
}}
/>
),
headerRight: () => <HeaderBell />,
headerRight: () => (
<Ionicons
disabled={true}
name="notifications"
size={20}
color={MainColor.placeholder}
onPress={() => {
router.push("/notifications");
}}
/>
),
}}
/>
<ViewWrapper
@@ -98,10 +109,6 @@ export default function Application() {
}
>
<StackCustom>
{/* <ButtonCustom onPress={() => router.push("./test-notifications")}>
Test Notif
</ButtonCustom> */}
<Home_ImageSection />
<Home_FeatureSection />

View File

@@ -1,77 +0,0 @@
import {
ButtonCustom,
NewWrapper,
StackCustom,
TextInputCustom,
} from "@/components";
import { useAuth } from "@/hooks/use-auth";
import { apiGetAllTokenDevice } from "@/service/api-device-token";
import { apiNotificationsSend } from "@/service/api-notifications";
import { useEffect, useState } from "react";
import Toast from "react-native-toast-message";
export default function TestNotification() {
const { user } = useAuth();
const [data, setData] = useState("");
useEffect(() => {
// fecthData();
}, []);
const fecthData = async () => {
const response = await apiGetAllTokenDevice();
console.log(
"[RES GET ALL TOKEN DEVICE]",
JSON.stringify(response.data, null, 2)
);
};
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,
userLoginId: user?.id || "",
},
});
if (response.success) {
console.log("[RES SEND NOTIF]", JSON.stringify(response, null, 2));
Toast.show({
type: "success",
text1: "Notifikasi berhasil dikirim",
});
} else {
Toast.show({
type: "error",
text1: "Gagal mengirim notifikasi",
});
}
};
return (
<>
<NewWrapper>
<StackCustom>
<TextInputCustom
required
label="Nama"
placeholder="Masukkan nama"
value={data}
onChangeText={(text) => setData(text)}
/>
<ButtonCustom
onPress={() => {
handleSubmit();
}}
>
Kirim
</ButtonCustom>
</StackCustom>
</NewWrapper>
</>
);
}

View File

@@ -1,26 +1,15 @@
import { BackButton } from "@/components";
import NotificationInitializer from "@/components/Notification/NotificationInitializer";
import { NotificationProvider } from "@/hooks/use-notification-store";
import { HeaderStyles } from "@/styles/header-styles";
import { Stack } from "expo-router";
export default function ApplicationLayout() {
return (
<>
<NotificationProvider>
<NotificationInitializer />
<ApplicationStack />
</NotificationProvider>
</>
);
}
function ApplicationStack() {
return (
<>
<Stack screenOptions={HeaderStyles}>
<Stack.Screen name="(user)" options={{ headerShown: false }} />
<Stack.Screen name="admin" options={{ headerShown: false }} />
{/* Take Picture */}
<Stack.Screen

View File

@@ -1,6 +1,4 @@
import NotificationInitializer from "@/components/Notification/NotificationInitializer";
import { AuthProvider } from "@/context/AuthContext";
import { NotificationProvider } from "@/hooks/use-notification-store";
import AppRoot from "@/screens/RootLayout/AppRoot";
import "react-native-gesture-handler";
import { SafeAreaProvider } from "react-native-safe-area-context";

View File

@@ -1,111 +0,0 @@
// src/components/NotificationInitializer.tsx
import { useEffect } from "react";
import { useForegroundNotifications } from "@/hooks/use-foreground-notifications";
import { useNotificationStore } from "@/hooks/use-notification-store";
import type { FirebaseMessagingTypes } from "@react-native-firebase/messaging";
import { useAuth } from "@/hooks/use-auth";
import { Platform } from "react-native";
import * as Device from "expo-device";
import * as Application from "expo-application";
import { apiDeviceRegisterToken } from "@/service/api-device-token";
import messaging, {
isSupported,
requestPermission,
getToken,
AuthorizationStatus,
} from "@react-native-firebase/messaging";
// ✅ Modular imports (sesuai v22+)
export default function NotificationInitializer() {
// Setup handler notifikasi
const { user, logout } = useAuth(); // dari AuthContext
const { addNotification } = useNotificationStore();
// Ambil token FCM (opsional, hanya untuk log)
useEffect(() => {
if (!user) {
console.log("User not available, skipping token sync");
return;
}
const registerDeviceToken = async () => {
try {
// ✅ Dapatkan instance messaging
const messagingInstance = messaging();
// ✅ Gunakan instance sebagai argumen
const supported = await isSupported(messagingInstance);
if (!supported) {
console.log("‼️ FCM tidak didukung");
return;
};
const authStatus = await requestPermission(messagingInstance);
if (authStatus !== AuthorizationStatus.AUTHORIZED) {
console.warn("Izin telah ditolak");
return;
}
const fcmToken = await getToken(messagingInstance);
if (!fcmToken) {
logout();
return;
}
console.log("✅ FCM Token:", fcmToken);
const platform = Platform.OS; // "ios" | "android"
const model = Device.modelName || "unknown";
const appVersion =
(Application.nativeApplicationVersion || "unknown") +
"-" +
(Application.nativeBuildVersion || "unknown");
const deviceId =
Device.osInternalBuildId || Device.modelName + "-" + Date.now();
// Kirim ke backend
await apiDeviceRegisterToken({
data: {
fcmToken,
platform,
deviceId,
model,
appVersion,
userId: user?.id || "",
},
});
console.log("✅ Device token berhasil didaftarkan ke backend");
} catch (error) {
console.error("❌ Gagal mendaftarkan device token:", error);
}
};
registerDeviceToken();
}, [user?.id]);
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 , type: "notification", });
console.log("✅ Notifikasi ditambahkan ke state");
};
useForegroundNotifications(handleForegroundNotification);
return null; // komponen ini tidak merender apa-apa
}

View File

@@ -98,14 +98,13 @@ export const IconView = ({
);
};
export const IconDot = ({ size, color, onPress }: { size?: number; color?: string , onPress?: () => void}) => {
export const IconDot = ({ size, color }: { size?: number; color?: string }) => {
return (
<>
<Ionicons
name="ellipsis-vertical"
size={size || ICON_SIZE_MEDIUM}
color={color || MainColor.darkblue}
onPress={onPress}
/>
</>
);

View File

@@ -4,21 +4,12 @@ import { Octicons } from "@expo/vector-icons";
export { IconPlus };
function IconPlus({
color,
size,
onPress,
}: {
color?: string;
size?: number;
onPress?: () => void;
}) {
function IconPlus({ color, size }: { color?: string; size?: number }) {
return (
<Octicons
name="plus-circle"
size={size || ICON_SIZE_MEDIUM}
color={color || MainColor.white}
onPress={onPress}
/>
);
}

View File

@@ -4,7 +4,6 @@ import {
apiRegister,
apiValidationCode,
} from "@/service/api-config";
import { apiDeviceTokenDeleted } from "@/service/api-device-token";
import { IUser } from "@/types/User";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { router } from "expo-router";
@@ -140,15 +139,13 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
await AsyncStorage.setItem("userData", JSON.stringify(dataUser));
if (response.active) {
// if (response.roleId === "1") {
// router.replace("/(application)/(user)/home");
// return;
// } else {
// router.replace("/(application)/admin/dashboard");
// return;
// }
router.replace("/(application)/(user)/home");
return
if (response.roleId === "1") {
router.replace("/(application)/(user)/home");
return;
} else {
router.replace("/(application)/admin/dashboard");
return;
}
} else {
router.replace("/(application)/(user)/waiting-room");
return;
@@ -285,7 +282,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
setUser(null);
await AsyncStorage.removeItem("authToken");
await AsyncStorage.removeItem("userData");
await apiDeviceTokenDeleted({userId: user?.id as any})
setIsLoading(false);
Toast.show({
type: "success",

View File

@@ -1,27 +0,0 @@
import { useEffect } from "react";
import {
getMessaging,
onMessage,
FirebaseMessagingTypes,
} from "@react-native-firebase/messaging";
// Gunakan tipe resmi dari library
type RemoteMessage = FirebaseMessagingTypes.RemoteMessage;
export function useForegroundNotifications(
onMessageReceived: (message: RemoteMessage) => void
) {
useEffect(() => {
const messaging = getMessaging();
const unsubscribe = onMessage(messaging, (remoteMessage) => {
console.log(
"🔔 Notifikasi diterima saat app aktif:",
JSON.stringify(remoteMessage, null, 2)
);
onMessageReceived(remoteMessage);
});
return unsubscribe;
}, [onMessageReceived]);
}

View File

@@ -1,131 +0,0 @@
// hooks/useNotificationStore.ts
import {
createContext,
ReactNode,
useContext,
useEffect,
useState,
} from "react";
import { useAuth } from "./use-auth";
import {
apiGetNotificationsById,
apiNotificationUnreadCount,
} from "@/service/api-notifications";
type AppNotification = {
id: string;
title: string;
body: string;
data?: Record<string, string>;
isRead: boolean;
timestamp: number;
type: "notification" | "trigger";
// untuk id dari setiap kategori app
appId?: string;
kategoriApp?:
| "JOB"
| "VOTING"
| "EVENT"
| "DONASI"
| "INVESTASI"
| "COLLABORATION"
| "FORUM"
| "ACCESS"; // Untuk trigger akses user;
};
type NotificationContextType = {
notifications: AppNotification[];
unreadCount: number;
addNotification: (
notif: Omit<AppNotification, "id" | "isRead" | "timestamp">
) => void;
markAsRead: (id: string) => void;
syncUnreadCount: () => Promise<void>;
};
const NotificationContext = createContext<NotificationContextType>({
notifications: [],
unreadCount: 0,
addNotification: () => {},
markAsRead: () => {},
syncUnreadCount: async () => {},
});
export const NotificationProvider = ({ children }: { children: ReactNode }) => {
const { user } = useAuth();
const [notifications, setNotifications] = useState<AppNotification[]>([]);
const [unreadCount, setUnreadCount] = useState(0);
console.log(
"🚀 Notifications Masuk:",
JSON.stringify(notifications, null, 2)
);
// Sync unread count dari backend saat provider di-mount
useEffect(() => {
fetchUnreadCount();
}, [user?.id]);
const fetchUnreadCount = async () => {
try {
const count = await apiNotificationUnreadCount({
id: user?.id as any,
}); // ← harus return number
const result = count.data;
console.log("📖 Unread count:", result);
setUnreadCount(result);
} catch (error) {
console.error("Gagal fetch unread count:", error);
}
};
const addNotification = (
notif: Omit<AppNotification, "id" | "isRead" | "timestamp">
) => {
setNotifications((prev) => [
{
...notif,
id: Date.now().toString(),
isRead: false,
timestamp: Date.now(),
},
...prev,
]);
setUnreadCount((prev) => prev + 1);
};
const markAsRead = (id: string) => {
setNotifications((prev) =>
prev.map((n) => (n.id === id ? { ...n, isRead: true } : n))
);
};
const syncUnreadCount = async () => {
try {
const count = await apiNotificationUnreadCount({
id: user?.id as any,
}); // ← harus return number
const result = count.data;
setUnreadCount(result);
} catch (error) {
console.warn("⚠️ Gagal sync unread count:", error);
}
};
return (
<NotificationContext.Provider
value={{
notifications,
addNotification,
markAsRead,
unreadCount,
syncUnreadCount,
}}
>
{children}
</NotificationContext.Provider>
);
};
export const useNotificationStore = () => useContext(NotificationContext);

View File

@@ -1,113 +0,0 @@
// hooks/useNotificationStore.ts
import { apiGetNotificationsById } from "@/service/api-notifications";
import { createContext, ReactNode, useContext, useState, useEffect } from "react";
import { useAuth } from "./use-auth";
type AppNotification = {
id: string;
title: string;
body: string;
data?: Record<string, string>;
isRead: boolean;
timestamp: number;
type: "notification" | "trigger";
appId?: string;
kategoriApp?:
| "JOB"
| "VOTING"
| "EVENT"
| "DONASI"
| "INVESTASI"
| "COLLABORATION"
| "FORUM"
| "ACCESS";
};
type NotificationContextType = {
notifications: AppNotification[];
unreadCount: number;
addNotification: (
notif: Omit<AppNotification, "id" | "isRead" | "timestamp">
) => void;
markAsRead: (id: string) => void;
syncUnreadCount: () => Promise<void>;
};
const NotificationContext = createContext<NotificationContextType>({
notifications: [],
unreadCount: 0,
addNotification: () => {},
markAsRead: () => {},
syncUnreadCount: async () => {},
});
export const NotificationProvider = ({ children }: { children: ReactNode }) => {
const {user} = useAuth()
const [notifications, setNotifications] = useState<AppNotification[]>([]);
const [unreadCount, setUnreadCount] = useState(0);
// 🔔 Sync unread count dari backend saat provider di-mount
useEffect(() => {
const fetchUnreadCount = async () => {
try {
const count = await apiGetNotificationsById({
id: user?.id as any,
category: "count-as-unread"
}); // ← harus return number
const result = count.data
setUnreadCount(result);
} catch (error) {
console.erro("⚠️ Gagal fetch unread count:", error);
}
};
fetchUnreadCount();
}, []);
const addNotification = (
notif: Omit<AppNotification, "id" | "isRead" | "timestamp">
) => {
setNotifications((prev) => [
{
...notif,
id: Date.now().toString(),
isRead: false,
timestamp: Date.now(),
},
...prev,
]);
// Tambahkan ke unread count (untuk notifikasi foreground)
setUnreadCount((prev) => prev + 1);
};
const markAsRead = (id: string) => {
setNotifications((prev) =>
prev.map((n) => (n.id === id ? { ...n, isRead: true } : n))
);
// Kurangi unread count
setUnreadCount((prev) => Math.max(0, prev - 1));
};
const syncUnreadCount = async () => {
try {
const count = await apiGetNotificationsById({
id: user?.id as any,
category: "count-as-unread"
}); // ← harus return number
const result = count.data
setUnreadCount(result);
} catch (error) {
console.warn("⚠️ Gagal sync unread count:", error);
}
};
return (
<NotificationContext.Provider
value={{ notifications, unreadCount, addNotification, markAsRead, syncUnreadCount }}
>
{children}
</NotificationContext.Provider>
);
};
export const useNotificationStore = () => useContext(NotificationContext);

File diff suppressed because one or more lines are too long

View File

@@ -39,7 +39,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>16</string>
<string>15</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSMinimumSystemVersion</key>
@@ -55,8 +55,6 @@
</dict>
<key>NSCameraUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your camera</string>
<key>NSFaceIDUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your Face ID biometric data.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your location</string>
<key>NSLocationAlwaysUsageDescription</key>

View File

@@ -51,7 +51,6 @@ target 'HIPMIBadungConnect' do
:privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
)
pod 'Firebase'
pod 'Firebase/Messaging'
# @generated begin post_installer - expo prebuild (DO NOT MODIFY) sync-4092f82b887b5b9edb84642c2a56984d69b9a403

View File

@@ -279,83 +279,31 @@ PODS:
- EXUpdatesInterface (2.0.0):
- ExpoModulesCore
- FBLazyVector (0.81.4)
- Firebase (12.6.0):
- Firebase/Core (= 12.6.0)
- Firebase/Core (12.6.0):
- Firebase/CoreOnly (12.7.0):
- FirebaseCore (~> 12.7.0)
- Firebase/Messaging (12.7.0):
- Firebase/CoreOnly
- FirebaseAnalytics (~> 12.6.0)
- Firebase/CoreOnly (12.6.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)
- FirebaseMessaging (~> 12.7.0)
- FirebaseCore (12.7.0):
- FirebaseCoreInternal (~> 12.7.0)
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/Logger (~> 8.1)
- FirebaseCoreExtension (12.6.0):
- FirebaseCore (~> 12.6.0)
- FirebaseCoreInternal (12.6.0):
- FirebaseCoreInternal (12.7.0):
- "GoogleUtilities/NSData+zlib (~> 8.1)"
- FirebaseInstallations (12.6.0):
- FirebaseCore (~> 12.6.0)
- FirebaseInstallations (12.7.0):
- FirebaseCore (~> 12.7.0)
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/UserDefaults (~> 8.1)
- PromisesObjC (~> 2.4)
- FirebaseMessaging (12.6.0):
- FirebaseCore (~> 12.6.0)
- FirebaseInstallations (~> 12.6.0)
- FirebaseMessaging (12.7.0):
- FirebaseCore (~> 12.7.0)
- FirebaseInstallations (~> 12.7.0)
- GoogleDataTransport (~> 10.1)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/Reachability (~> 8.1)
- GoogleUtilities/UserDefaults (~> 8.1)
- 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):
- nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4)
@@ -369,9 +317,6 @@ PODS:
- GoogleUtilities/Logger (8.1.0):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- GoogleUtilities/MethodSwizzler (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GoogleUtilities/Network (8.1.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
@@ -2253,14 +2198,6 @@ PODS:
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- 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):
- hermes-engine
- RCTRequired
@@ -2622,7 +2559,6 @@ DEPENDENCIES:
- ExpoWebBrowser (from `../node_modules/expo-web-browser/ios`)
- EXUpdatesInterface (from `../node_modules/expo-updates-interface/ios`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- Firebase
- Firebase/Messaging
- hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
- RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`)
@@ -2697,8 +2633,6 @@ DEPENDENCIES:
- ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "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`)
- "rnmapbox-maps (from `../node_modules/@rnmapbox/maps`)"
- RNReanimated (from `../node_modules/react-native-reanimated`)
@@ -2711,14 +2645,10 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- Firebase
- FirebaseAnalytics
- FirebaseCore
- FirebaseCoreExtension
- FirebaseCoreInternal
- FirebaseInstallations
- FirebaseMessaging
- GoogleAdsOnDeviceConversion
- GoogleAppMeasurement
- GoogleDataTransport
- GoogleUtilities
- libavif
@@ -2948,10 +2878,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNDateTimePicker:
:path: "../node_modules/@react-native-community/datetimepicker"
RNFBApp:
:path: "../node_modules/@react-native-firebase/app"
RNFBMessaging:
:path: "../node_modules/@react-native-firebase/messaging"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
rnmapbox-maps:
@@ -3003,15 +2929,11 @@ SPEC CHECKSUMS:
ExpoWebBrowser: b973e1351fdcf5fec0c400997b1851f5a8219ec3
EXUpdatesInterface: 5adf50cb41e079c861da6d9b4b954c3db9a50734
FBLazyVector: 9e0cd874afd81d9a4d36679daca991b58b260d42
Firebase: a451a7b61536298fd5cbfe3a746fd40443a50679
FirebaseAnalytics: d0a97a0db6425e5a5d966340b87f92ca7b13a557
FirebaseCore: 0e38ad5d62d980a47a64b8e9301ffa311457be04
FirebaseCoreExtension: 032fd6f8509e591fda8cb76f6651f20d926b121f
FirebaseCoreInternal: 69bf1306a05b8ac43004f6cc1f804bb7b05b229e
FirebaseInstallations: 631b38da2e11a83daa4bfb482f79d286a5dfa7ad
FirebaseMessaging: a61bc42dcab3f7a346d94bbb54dab2c9435b18b2
GoogleAdsOnDeviceConversion: d68c69dd9581a0f5da02617b6f377e5be483970f
GoogleAppMeasurement: 3bf40aff49a601af5da1c3345702fcb4991d35ee
Firebase: 2d19a10c9a2e48ac532a4303115d3fc9b2798396
FirebaseCore: c7b57863ce0859281a66d16ca36d665c45d332b5
FirebaseCoreInternal: 571a2dd8c975410966199623351db3a3265c874d
FirebaseInstallations: 6d05424a046b68ca146b4de4376f05b4e9262fc3
FirebaseMessaging: b5f7bdc62b91b6102015991fb7bc6fa75f643908
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
hermes-engine: 35c763d57c9832d0eef764316ca1c4d043581394
@@ -3094,8 +3016,6 @@ SPEC CHECKSUMS:
ReactNativeDependencies: ed6d1e64802b150399f04f1d5728ec16b437251e
RNCAsyncStorage: 3a4f5e2777dae1688b781a487923a08569e27fe4
RNDateTimePicker: be0e44bcb9ed0607c7c5f47dbedd88cf091f6791
RNFBApp: 0c4cadae3900893d4631ea9a9effd14f853cd8e0
RNFBMessaging: 873220424f6f6aa5c787baf5c7099e1e2ba087c9
RNGestureHandler: 2914750df066d89bf9d8f48a10ad5f0051108ac3
rnmapbox-maps: 3c20ce786a7991498445c32de4fe4244e32aa0ee
RNReanimated: 8d3a14606ad49f022c17d9e12a2d339e9e5ad9b0
@@ -3111,6 +3031,6 @@ SPEC CHECKSUMS:
Yoga: 051f086b5ccf465ff2ed38a2cf5a558ae01aaaa1
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5
PODFILE CHECKSUM: 9c1ecbc7e57ca21dc7c93635b18e66f8f6d7bdd9
PODFILE CHECKSUM: 61c4a9d35618e5f2a420f47e5a24c89e86706f00
COCOAPODS: 1.16.2

View File

@@ -1,45 +0,0 @@
// components/HeaderBell.tsx
import { MainColor } from "@/constants/color-palet";
import { useNotificationStore } from "@/hooks/use-notification-store";
import { Ionicons } from "@expo/vector-icons";
import { router } from "expo-router";
import { useEffect } from "react";
import { Text, View } from "react-native";
export default function HeaderBell() {
const { notifications , unreadCount} = useNotificationStore();
// 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>
);
}

View File

@@ -1,51 +0,0 @@
import { apiConfig } from "./api-config";
type DeviceTokenData = {
fcmToken: string;
platform: string;
deviceId: string;
model: string;
appVersion: string;
userId: string;
};
export async function apiDeviceRegisterToken({
data,
}: {
data: DeviceTokenData;
}) {
try {
const response = await apiConfig.post(`/mobile/auth/device-tokens`, {
data: data,
});
return response.data;
} catch (error) {
console.error("Failed to register device token:", error);
throw error;
}
}
export async function apiDeviceTokenDeleted({ userId }: { userId: string }) {
try {
const response = await apiConfig.delete(
`/mobile/auth/device-tokens/${userId}`
);
console.log("Device token deleted:", response.data);
return response.data;
} catch (error) {
console.error("Failed to delete device token:", error);
throw error;
}
}
export async function apiGetAllTokenDevice() {
try {
const response = await apiConfig.get(`/mobile/auth/device-tokens`);
console.log("Device token deleted:", response.data);
return response.data;
} catch (error) {
console.error("Failed to delete device token:", error);
throw error;
}
}

View File

@@ -1,56 +0,0 @@
import { apiConfig } from "./api-config";
type NotificationProp = {
fcmToken: string;
title: string;
body: Object;
userLoginId?: string;
};
export async function apiNotificationsSend({
data,
}: {
data: NotificationProp;
}) {
try {
const response = await apiConfig.post(`/mobile/notification`, {
data: data,
});
return response.data;
} catch (error) {
throw error;
}
}
export async function apiGetNotificationsById({
id,
category,
}: {
id: string;
category: "count-as-unread" | "all";
}) {
console.log("ID", id);
console.log("Category", category);
try {
const response = await apiConfig.get(
`/mobile/notification/${id}?category=${category}`
);
return response.data;
} catch (error) {
throw error;
}
}
export async function apiNotificationUnreadCount({ id }: { id: string }) {
try {
const response = await apiConfig.get(
`/mobile/notification/${id}/unread-count`
);
return response.data;
} catch (error) {
throw error;
}
}