notifications
This commit is contained in:
@@ -1,22 +1,41 @@
|
|||||||
/**
|
|
||||||
* Sample React Native App
|
|
||||||
* https://github.com/facebook/react-native
|
|
||||||
*
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { NewAppScreen } from '@react-native/new-app-screen';
|
import React, { useEffect } from 'react';
|
||||||
import { StatusBar, StyleSheet, useColorScheme, View } from 'react-native';
|
import { StyleSheet, useColorScheme } from 'react-native';
|
||||||
import {
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
SafeAreaProvider,
|
|
||||||
useSafeAreaInsets,
|
|
||||||
} from 'react-native-safe-area-context';
|
|
||||||
import AppNavigator from './src/navigation/AppNavigator';
|
|
||||||
import { PaperProvider } from 'react-native-paper';
|
import { PaperProvider } from 'react-native-paper';
|
||||||
|
import AppNavigator from './src/navigation/AppNavigator';
|
||||||
|
import notifee from '@notifee/react-native';
|
||||||
|
import FirebaseService from './src/utils/firebase/firebaseServices';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const isDarkMode = useColorScheme() === 'dark';
|
const isDarkMode = useColorScheme() === 'dark';
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// 🔹 Ask for permission
|
||||||
|
FirebaseService.requestPermission();
|
||||||
|
|
||||||
|
// 🔹 Handle background + quit state
|
||||||
|
FirebaseService.backgroundHandler();
|
||||||
|
|
||||||
|
// 🔹 Listen for foreground messages
|
||||||
|
const unsubscribe = FirebaseService.foregroundListener();
|
||||||
|
|
||||||
|
// 🔹 Listen for token refresh
|
||||||
|
const unsubscribeRefresh = FirebaseService.tokenRefreshHandler();
|
||||||
|
|
||||||
|
// 🔹 Create default notification channel (Android)
|
||||||
|
notifee.createChannel({
|
||||||
|
id: 'default',
|
||||||
|
name: 'Default Channel',
|
||||||
|
importance: 4, // HIGH
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
unsubscribeRefresh();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
<PaperProvider>
|
<PaperProvider>
|
||||||
|
|||||||
@@ -117,3 +117,4 @@ dependencies {
|
|||||||
implementation jscFlavor
|
implementation jscFlavor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
apply plugin: "com.google.gms.google-services"
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "590063852259",
|
||||||
|
"project_id": "abin-91b63",
|
||||||
|
"storage_bucket": "abin-91b63.firebasestorage.app"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:590063852259:android:14cddf7965aeab364183d6",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.circlecollect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyAV4WtB8_ZnQgsOgrVnz_J9-5-zlGdTG0I"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ buildscript {
|
|||||||
classpath("com.android.tools.build:gradle")
|
classpath("com.android.tools.build:gradle")
|
||||||
classpath("com.facebook.react:react-native-gradle-plugin")
|
classpath("com.facebook.react:react-native-gradle-plugin")
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
|
||||||
|
classpath 'com.google.gms:google-services:4.4.3'
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+1048
-1
File diff suppressed because it is too large
Load Diff
@@ -10,9 +10,12 @@
|
|||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@notifee/react-native": "^9.1.8",
|
||||||
"@react-native-clipboard/clipboard": "^1.16.3",
|
"@react-native-clipboard/clipboard": "^1.16.3",
|
||||||
"@react-native-community/blur": "^4.4.1",
|
"@react-native-community/blur": "^4.4.1",
|
||||||
"@react-native-community/slider": "^5.0.1",
|
"@react-native-community/slider": "^5.0.1",
|
||||||
|
"@react-native-firebase/app": "^23.4.0",
|
||||||
|
"@react-native-firebase/messaging": "^23.4.0",
|
||||||
"@react-native-picker/picker": "^2.11.2",
|
"@react-native-picker/picker": "^2.11.2",
|
||||||
"@react-native-vector-icons/ionicons": "^12.3.0",
|
"@react-native-vector-icons/ionicons": "^12.3.0",
|
||||||
"@react-native-vector-icons/material-icons": "^12.3.0",
|
"@react-native-vector-icons/material-icons": "^12.3.0",
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const InviteScreen: FC<InviteScreenProps> = ({ route }) => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
const response = await apiCall(`http://192.168.1.9:9060/api/fund/group/details?groupId=${groupId}`, 'GET') as { status: string; data?: GroupDetails; message?: string };
|
const response = await apiCall(`https://api.godemo.in/FundCollect/api/fund/group/details?groupId=${groupId}`, 'GET') as { status: string; data?: GroupDetails; message?: string };
|
||||||
if (response.status === 'success' && response.data) {
|
if (response.status === 'success' && response.data) {
|
||||||
setGroupDetails(response.data);
|
setGroupDetails(response.data);
|
||||||
} else {
|
} else {
|
||||||
@@ -76,7 +76,7 @@ const InviteScreen: FC<InviteScreenProps> = ({ route }) => {
|
|||||||
try {
|
try {
|
||||||
// Replace with your actual API call to join the group
|
// Replace with your actual API call to join the group
|
||||||
// For now, it just shows an alert.
|
// For now, it just shows an alert.
|
||||||
await apiCall(`http://192.168.1.9:9060/api/fund/groups/join/invite/${code}`, 'POST');
|
await apiCall(`https://api.godemo.in/FundCollect/api/fund/groups/join/invite/${code}`, 'POST');
|
||||||
Alert.alert('Success!', `You have requested to join "${groupDetails.groupName}".`);
|
Alert.alert('Success!', `You have requested to join "${groupDetails.groupName}".`);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
Alert.alert('Join Error', e.message || 'An unexpected error occurred.');
|
Alert.alert('Join Error', e.message || 'An unexpected error occurred.');
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { LOGIN_URL, VARIFY_OTP_URL } from "../utils/ApiUrls";
|
|||||||
import colors from "../components/colors";
|
import colors from "../components/colors";
|
||||||
import LinearGradient from "react-native-linear-gradient";
|
import LinearGradient from "react-native-linear-gradient";
|
||||||
import CustomAlert from "../components/CostomAlart";
|
import CustomAlert from "../components/CostomAlart";
|
||||||
|
import FirebaseService from "../utils/firebase/firebaseServices";
|
||||||
|
|
||||||
const CELL_COUNT = 6;
|
const CELL_COUNT = 6;
|
||||||
type OtpVerifyRouteProp = RouteProp<RootStackParamList, "OtpVarify">;
|
type OtpVerifyRouteProp = RouteProp<RootStackParamList, "OtpVarify">;
|
||||||
@@ -125,7 +126,10 @@ export default function OtpVerificationScreen() {
|
|||||||
|
|
||||||
if (res.data?.statusCode === 200) {
|
if (res.data?.statusCode === 200) {
|
||||||
const { jwt } = res.data?.data || {};
|
const { jwt } = res.data?.data || {};
|
||||||
|
console.log("✅ OTP Verified:", res.data);
|
||||||
await saveToken(jwt);
|
await saveToken(jwt);
|
||||||
|
await FirebaseService.getFcmToken(res.data?.data?.userId);
|
||||||
|
|
||||||
|
|
||||||
let hasActionRun = false;
|
let hasActionRun = false;
|
||||||
const successAction = () => {
|
const successAction = () => {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const RequestList: React.FC = () => {
|
|||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
"http://192.168.1.9:9060/api/fund/group/pending/request",
|
"https://api.godemo.in/FundCollect/api/fund/group/pending/request",
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -124,7 +124,7 @@ const RequestList: React.FC = () => {
|
|||||||
|
|
||||||
// Make API call to approve the request
|
// Make API call to approve the request
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`http://192.168.1.9:9060/api/fund/requests/${requestId}/approve`,
|
`https://api.godemo.in/FundCollect/api/fund/requests/${requestId}/approve`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -170,7 +170,7 @@ const RequestList: React.FC = () => {
|
|||||||
|
|
||||||
// Make API call to decline the request
|
// Make API call to decline the request
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`http://192.168.1.9:9060/api/fund/requests/${requestedId}/reject?reason=/${reason}`,
|
`https://api.godemo.in/FundCollect/api/fund/requests/${requestedId}/reject?reason=/${reason}`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ const MemberScreen = ({ route }) => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await apiCall<ApiResponse>(
|
const response = await apiCall<ApiResponse>(
|
||||||
`http://192.168.1.9:9060/api/fund/group/all/member?groupId=${groupId}`,
|
`https://api.godemo.in/FundCollect/api/fund/group/all/member?groupId=${groupId}`,
|
||||||
'GET'
|
'GET'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { apiCall } from '../../utils/ApiHelper';
|
|||||||
import { BASE_URL } from '../../utils/ApiUrls';
|
import { BASE_URL } from '../../utils/ApiUrls';
|
||||||
|
|
||||||
// --- CONSTANTS ---
|
// --- CONSTANTS ---
|
||||||
const API_BASE_URL = 'http://192.168.1.9:9060/api/payments';
|
const API_BASE_URL = 'https://api.godemo.in/FundCollect/api/payments';
|
||||||
|
|
||||||
// --- TYPE DEFINITIONS ---
|
// --- TYPE DEFINITIONS ---
|
||||||
interface ApiResponse<T> {
|
interface ApiResponse<T> {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const BecomeOrg = () => {
|
|||||||
const token = credentials.password;
|
const token = credentials.password;
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
"http://192.168.1.9:9060/api/organizer/registration/apply",
|
"https://api.godemo.in/FundCollect/api/organizer/registration/apply",
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import { useDispatch } from "react-redux";
|
|||||||
import { clearUser, setUserData } from "../../redux/userSlice";
|
import { clearUser, setUserData } from "../../redux/userSlice";
|
||||||
import { StackNavigationProp } from "@react-navigation/stack";
|
import { StackNavigationProp } from "@react-navigation/stack";
|
||||||
import { RootStackParamList } from "../../navigation/AppNavigator";
|
import { RootStackParamList } from "../../navigation/AppNavigator";
|
||||||
|
import { firebase } from "@react-native-firebase/messaging";
|
||||||
|
import FirebaseService from "../../utils/firebase/firebaseServices";
|
||||||
|
|
||||||
|
|
||||||
type UserProfile = {
|
type UserProfile = {
|
||||||
@@ -303,6 +305,7 @@ const Profile = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await FirebaseService.deleteFcmToken();
|
||||||
|
|
||||||
// Clear stored credentials
|
// Clear stored credentials
|
||||||
await Keychain.resetGenericPassword();
|
await Keychain.resetGenericPassword();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
// export const BASE_URL = "https://api.godemo.in/FundCollect/api/"
|
// export const BASE_URL = "https://api.godemo.in/FundCollect/api/"
|
||||||
export const BASE_URL = "http://192.168.1.9:9060/api/"
|
export const BASE_URL = "https://api.godemo.in/FundCollect/api/"
|
||||||
export const LOGIN_URL = `${BASE_URL}user/generate/otp?mobiles=`
|
export const LOGIN_URL = `${BASE_URL}user/generate/otp?mobiles=`
|
||||||
export const VARIFY_OTP_URL = `${BASE_URL}user/otp/verify`
|
export const VARIFY_OTP_URL = `${BASE_URL}user/otp/verify`
|
||||||
export const ORGRAGISTRATION = `${BASE_URL}organizer/registration/apply`
|
export const ORGRAGISTRATION = `${BASE_URL}organizer/registration/apply`
|
||||||
@@ -22,4 +22,5 @@ export const UPDATE_BANK_URL = `${BASE_URL}user/bank/update`;
|
|||||||
export const CONTRIBUTE = `${BASE_URL}payments/groups/`;
|
export const CONTRIBUTE = `${BASE_URL}payments/groups/`;
|
||||||
export const TRANSACTION = `${BASE_URL}payments/my-transactions`;
|
export const TRANSACTION = `${BASE_URL}payments/my-transactions`;
|
||||||
export const UPLOAD_GROUP_IMAGE = `${BASE_URL}fund/groups/`;
|
export const UPLOAD_GROUP_IMAGE = `${BASE_URL}fund/groups/`;
|
||||||
|
export const STORE_FCM_TOKEN = `${BASE_URL}token/store?fcmToken=`
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import messaging from '@react-native-firebase/messaging';
|
||||||
|
import notifee, { AndroidImportance } from '@notifee/react-native';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { apiCall } from '../ApiHelper';
|
||||||
|
|
||||||
|
// replace with your backend
|
||||||
|
|
||||||
|
class FirebaseService {
|
||||||
|
// 🔹 Request notification permission
|
||||||
|
static async requestPermission() {
|
||||||
|
await messaging().requestPermission();
|
||||||
|
await notifee.requestPermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 Display local notification
|
||||||
|
static async displayNotification(title: string, body: string) {
|
||||||
|
await notifee.displayNotification({
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
android: {
|
||||||
|
channelId: 'default',
|
||||||
|
smallIcon: 'ic_launcher', // ensure you have this icon in android/app/src/main/res/mipmap
|
||||||
|
importance: AndroidImportance.HIGH,
|
||||||
|
pressAction: {
|
||||||
|
id: 'default',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 Get & send token to backend
|
||||||
|
static async getFcmToken(userId: string) {
|
||||||
|
try {
|
||||||
|
const token = await messaging().getToken();
|
||||||
|
console.log('FCM Token:', token);
|
||||||
|
await apiCall(`https://api.godemo.in/FundCollect/api/token/store?fcmToken=${token}&userId=${userId}`, 'POST');
|
||||||
|
console.log('FCM Token sent to backend');
|
||||||
|
return token;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting FCM token:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 Delete token from backend
|
||||||
|
static async deleteFcmToken() {
|
||||||
|
try {
|
||||||
|
const token = await messaging().getToken();
|
||||||
|
await apiCall(`https://api.godemo.in/FundCollect/api/token/remove?fcmToken=${token}`, 'DELETE');
|
||||||
|
console.log('FCM Token deleted from backend');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting FCM token:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 Foreground notifications
|
||||||
|
static foregroundListener() {
|
||||||
|
return messaging().onMessage(async remoteMessage => {
|
||||||
|
console.log('Foreground message:', remoteMessage);
|
||||||
|
if (remoteMessage.notification) {
|
||||||
|
await this.displayNotification(
|
||||||
|
remoteMessage.notification.title ?? 'New Message',
|
||||||
|
remoteMessage.notification.body ?? ''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 Background & Quit state
|
||||||
|
static backgroundHandler() {
|
||||||
|
messaging().setBackgroundMessageHandler(async remoteMessage => {
|
||||||
|
console.log('Background message:', remoteMessage);
|
||||||
|
if (remoteMessage.notification) {
|
||||||
|
await this.displayNotification(
|
||||||
|
remoteMessage.notification.title ?? 'New Message',
|
||||||
|
remoteMessage.notification.body ?? ''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
messaging().onNotificationOpenedApp(remoteMessage => {
|
||||||
|
console.log('App opened from background:', remoteMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
messaging().getInitialNotification().then(remoteMessage => {
|
||||||
|
if (remoteMessage) {
|
||||||
|
console.log('App opened from quit state:', remoteMessage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 Token auto-refresh
|
||||||
|
static tokenRefreshHandler() {
|
||||||
|
return messaging().onTokenRefresh(async token => {
|
||||||
|
console.log('New refreshed FCM Token:', token);
|
||||||
|
// 👉 send to backend
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FirebaseService;
|
||||||
Reference in New Issue
Block a user