Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notification/local notify #439

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0832f2c
updated the way we notify locally
shreya1mishra Aug 18, 2024
fb23fc6
fix ui of notify screen button
shreya1mishra Aug 18, 2024
48dc277
integtrated the notify api
shreya1mishra Aug 19, 2024
339b35a
updated the api and applied on form
shreya1mishra Aug 28, 2024
aeca783
added firebase messaging package
shreya1mishra Aug 31, 2024
e839964
getting urls from env
shreya1mishra Aug 31, 2024
396ebe2
getting url from staging
shreya1mishra Sep 1, 2024
748aa7e
fix cookie issue
shreya1mishra Sep 1, 2024
789712a
refactor: Remove the unused props
divyansh0908 Sep 29, 2024
73da022
style: Give some style to notification's title
divyansh0908 Sep 29, 2024
dfef746
feat: Add env template
divyansh0908 Sep 29, 2024
a2bc9ea
fix: Remove git tracking of google-services.json
divyansh0908 Sep 29, 2024
8a0876c
feat: Add postinstall script to generate google-services.json
divyansh0908 Sep 29, 2024
7f730fd
refactor: Remove google-services.json
divyansh0908 Sep 29, 2024
e0a78d3
notify test cases
shreya1mishra Sep 29, 2024
73d9359
Merge branch 'Real-Dev-Squad:notification/local_notify' into notifica…
divyansh0908 Sep 29, 2024
63d6e16
fix: Remove unused code from `NotificationScreen`
divyansh0908 Sep 29, 2024
0fb6d0a
fix: Write test according to the modified code
divyansh0908 Sep 29, 2024
179b039
feat: Update notify form to request for notification
divyansh0908 Sep 29, 2024
b30102a
feat: Add test for notification form component
divyansh0908 Sep 29, 2024
3b806be
feat: Add ios package for firebase notification
divyansh0908 Sep 29, 2024
c761f8d
feat: Update test for NotifyScreen and NotificationForm
divyansh0908 Oct 1, 2024
9465ff4
chore: Remove console logs
divyansh0908 Oct 3, 2024
9150ce9
style: Update fontSize to use responsive value
divyansh0908 Oct 3, 2024
02ad0ff
Merge pull request #453 from divyansh0908/notification/local_notify
shreya-mishra Oct 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
BASE_UTL=
RDS_SESSION=
FIREBASE_PROJECT_ID=
FIREBASE_MESSAGING_SENDER_ID=
FIREBASE_STORAGE_BUCKET=
MOBILE_SDK_APP_ID=
OAUTH_CLIENT_ID=
FIREBASE_CURRENT_API_KEY=
OTHER_PLATFORM_OAUTH_CLIENT_ID=
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ buck-out/
# CocoaPods
/ios/Pods/

# ignore google-services
/android/app/google-services.json



#env
Expand Down
1 change: 0 additions & 1 deletion App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import reducers from './src/reducers';
import { Provider } from 'react-redux';
import createSagaMiddleware from '@redux-saga/core';
import rootSaga from './src/sagas/rootSaga';

const sagaMiddleware = createSagaMiddleware();
const middleware = [sagaMiddleware];
export const store = compose(applyMiddleware(...middleware))(createStore)(
Expand Down
130 changes: 130 additions & 0 deletions __tests__/Goals/components/NotificationForm.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react-native';
import NotifyForm from '../../../src/components/Notify/NotifyForm';
import { AuthContext } from '../../../src/context/AuthContext';
import {
postFcmToken,
getAllUsers,
sendNotification,
} from '../../../src/screens/AuthScreen/Util';

// Mock the functions used in the component
jest.mock('../../../src/screens/AuthScreen/Util', () => ({
postFcmToken: jest.fn(),
sendNotification: jest.fn(),
getAllUsers: jest.fn(() => Promise.resolve([])), // Mock getAllUsers with an empty array
}));

jest.mock('@react-native-firebase/messaging', () => ({
firebase: {
messaging: jest.fn(() => ({
getToken: jest.fn(() => Promise.resolve('mocked-fcm-token')),
hasPermission: jest.fn(() => Promise.resolve(1)), // Mock permission granted
requestPermission: jest.fn(() => Promise.resolve()), // Mock permission request
})),
},
}));

describe('NotifyForm', () => {
const loggedInUserData = { token: 'user-token' };

const renderComponent = () => {
return render(
<AuthContext.Provider value={{ loggedInUserData }}>
<NotifyForm />
</AuthContext.Provider>,
);
};

beforeEach(() => {
jest.clearAllMocks();
});

it('renders the form with title, description, and Notify button', () => {
const { getByText, getByPlaceholderText } = renderComponent();

expect(getByText('Title:')).toBeTruthy();
expect(getByText('Description:')).toBeTruthy();
expect(getByText('Notify To:')).toBeTruthy();
expect(getByPlaceholderText('Enter title')).toBeTruthy();
expect(getByPlaceholderText('Enter description')).toBeTruthy();
expect(getByText('Notify')).toBeTruthy();
});

it('Calls postFcmToken', async () => {
renderComponent();

await waitFor(() => {
expect(postFcmToken).toHaveBeenCalledWith(
'mocked-fcm-token',
'user-token',
);
});
});

it('fetches users and updates the dropdown', async () => {
const mockUsers = [
{ id: '1', username: 'john_doe', first_name: 'John', last_name: 'Doe' },
{ id: '2', username: 'jane_doe', first_name: 'Jane', last_name: 'Doe' },
];

getAllUsers.mockResolvedValue(mockUsers); // Mock resolved users

const { getByTestId, getByText } = renderComponent();

// Wait for users to load
await waitFor(() => {
expect(getAllUsers).toHaveBeenCalledWith('user-token');
});

const dropdown = getByTestId('dropdown');
fireEvent.press(dropdown); // Simulate dropdown press to show user list

await waitFor(() => {
expect(getByText('john_doe')).toBeTruthy();
expect(getByText('jane_doe')).toBeTruthy();
});
});

it('selects a user from the dropdown and sends a notification', async () => {
const mockUsers = [
{ id: '1', username: 'john_doe', first_name: 'John', last_name: 'Doe' },
];

getAllUsers.mockResolvedValue(mockUsers);

const { getByTestId, getByPlaceholderText, getByText } = renderComponent();

// Wait for users to load
await waitFor(() => {
expect(getAllUsers).toHaveBeenCalledWith('user-token');
});

const dropdown = getByTestId('dropdown');
fireEvent.press(dropdown); // Open dropdown

// Select a user from the dropdown
await waitFor(() => {
fireEvent.press(getByText('john_doe'));
});

// Fill in title and description
fireEvent.changeText(getByPlaceholderText('Enter title'), 'Test Title');
fireEvent.changeText(
getByPlaceholderText('Enter description'),
'Test Description',
);

// Press Notify button
fireEvent.press(getByText('Notify'));

await waitFor(() => {
expect(sendNotification).toHaveBeenCalledWith(
'Test Title',
'Test Description',
'1',
'user-token',
);
});
});
});
27 changes: 27 additions & 0 deletions __tests__/screens/NotifyScreen.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { render } from '@testing-library/react-native';
import NotifyScreen from '../../src/screens/NotifyScreen/NotifyScreen';

jest.mock('../../src/screens/AuthScreen/Util', () => ({
postFcmToken: jest.fn(),
sendNotification: jest.fn(),
getAllUsers: jest.fn(() => Promise.resolve([])), // Mock getAllUsers with an empty array
}));

jest.mock('@react-native-firebase/messaging', () => ({
firebase: {
messaging: jest.fn(() => ({
getToken: jest.fn(() => Promise.resolve('mocked-fcm-token')),
hasPermission: jest.fn(() => Promise.resolve(1)), // Mock permission granted
requestPermission: jest.fn(() => Promise.resolve()), // Mock permission request
})),
},
}));
describe('NotifyScreen', () => {
it('should render correctly with title and NotifyForm', async () => {
const { getByText } = render(<NotifyScreen />);

expect(getByText('Event Notifications')).toBeTruthy();
// Wait for the getToken to be called
});
});
5 changes: 4 additions & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"

apply plugin: 'com.google.gms.google-services'
/**
* This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need.
Expand Down Expand Up @@ -67,6 +67,8 @@ android {
dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
implementation(platform("com.google.firebase:firebase-bom:33.1.2"))
implementation("com.google.firebase:firebase-analytics")

if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
Expand All @@ -76,3 +78,4 @@ dependencies {
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
31 changes: 31 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,44 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme">
<meta-data android:name="com.dieam.reactnativepushnotification.notification_foreground"
android:value="true" />
<meta-data android:name="com.dieam.reactnativepushnotification.channel_create_default"
android:value="true" />
<meta-data android:name="com.dieam.reactnativepushnotification.notification_color"
android:resource="@color/white" />

<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationActions"
android:exported="true" />
<receiver
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher"
android:exported="true" />
<receiver
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<service
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>

<activity
android:name=".MainActivity"
android:exported="true"
Expand Down
3 changes: 3 additions & 0 deletions android/app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<resources>
<color name="white">#FFF</color>
</resources>
1 change: 1 addition & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ buildscript {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
classpath("com.google.gms:google-services:4.3.15")
}
}

Expand Down
12 changes: 12 additions & 0 deletions bin/postInstall
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!usr/bin/env node
run('node ./src/service/googleServiceTemplate.js');

function run(command) {
console.info(`./bin/postInstall scripit running: ${command}`);
try {
require('child_process').execSync(command, { stdio: 'inherit' });
} catch (err) {
console.error(`./bin/postInstall failed on command ${command}`);
process.exit(err.status);
}
}
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
import firebase from '@react-native-firebase/app';

firebase.initializeApp();

AppRegistry.registerComponent(appName, () => App);
16 changes: 12 additions & 4 deletions jest-setup.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { jest } from '@jest/globals';
import mockRNDeviceInfo from 'react-native-device-info/jest/react-native-device-info-mock';

require('react-native-reanimated/lib/reanimated2/jestUtils').setUpTests();
jest.mock('react-native-device-info', () => mockRNDeviceInfo);
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter');
jest.mock('@react-native-firebase/app', () => {
return {
firebase: {
app: jest.fn(() => ({
initializeApp: jest.fn(),
})),
messaging: jest.fn(() => ({
getToken: jest.fn(),
})),
},
};
});
9 changes: 9 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,26 @@
"build-assets-folder": "cd android/app/src/main && if [ -d 'assets' ]; then rm -r assets; fi",
"build": "mkdir -p android/app/src/main/assets && npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res && cd android && ./gradlew assembleDebug",
"build-release": "mkdir -p android/app/src/main/assets && npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/build/intermediates/res/merged/release/ && rm -rf android/app/src/main/res/drawable-* && rm -rf android/app/src/main/res/raw/* && cd android && ./gradlew bundleRelease"
"postinstall": "node ./bin/postInstall"
},
"dependencies": {
"@babel/helper-hoist-variables": "^7.24.7",
"@react-native-async-storage/async-storage": "^1.15.16",
"@react-native-community/netinfo": "^5.9.9",
"@react-native-community/push-notification-ios": "^1.11.0",
"@react-native-community/slider": "^4.4.3",
"@react-native-firebase/app": "^20.4.0",
"@react-native-firebase/messaging": "^20.4.0",
"@react-native-masked-view/masked-view": "^0.2.6",
"@react-native-picker/picker": "^2.7.7",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • why are we adding this package in this pr?

"@react-navigation/bottom-tabs": "^6.0.9",
"@react-navigation/drawer": "^6.1.8",
"@react-navigation/material-top-tabs": "^6.6.4",
"@react-navigation/native": "^6.0.8",
"@react-navigation/native-stack": "^6.9.12",
"@react-navigation/stack": "^6.2.0",
"axios": "^0.26.0",
"dotenv": "^16.4.5",
"eslint-plugin-prettier": "^4.1.0",
"moment": "^2.29.4",
"react": "18.2.0",
Expand All @@ -39,6 +45,7 @@
"react-native-circular-progress-indicator": "^4.4.2",
"react-native-collapsible": "^1.6.1",
"react-native-collapsible-tab-view": "^6.2.1",
"react-native-config": "^1.5.3",
"react-native-date-picker": "^4.2.13",
"react-native-datepicker": "^1.7.2",
"react-native-device-info": "^10.8.0",
Expand All @@ -53,6 +60,7 @@
"react-native-pager-view": "^6.2.1",
"react-native-paper": "^5.11.2",
"react-native-progress": "^5.0.1",
"react-native-push-notification": "^8.1.1",
"react-native-radio-buttons-group": "^2.2.11",
"react-native-reanimated": "^3.9.0-rc.1",
"react-native-safe-area-context": "^3.2.0",
Expand Down Expand Up @@ -84,6 +92,7 @@
"@types/react": "^18.2.6",
"@types/react-native": "^0.66.4",
"@types/react-native-datepicker": "^1.7.1",
"@types/react-native-push-notification": "^8.1.4",
"@types/react-test-renderer": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.7.0",
"@typescript-eslint/parser": "^5.7.0",
Expand Down
22 changes: 22 additions & 0 deletions src/actions/LocalNotification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import PushNotification from 'react-native-push-notification';

const LocalNotification = () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Can we export this directly instead of using the default export? It would be easy to find references to LocalNotification once they are used in multiple places.

const key = Date.now().toString(); // Key must be unique everytime
PushNotification.createChannel(
{
channelId: key, // (required)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • how will the notification work if the channelId is different everytime?

channelName: 'Local messasge', // (required)
channelDescription: 'Notification for Local message', // (optional) default: undefined.
importance: 4, // (optional) default: 4. Int value of the Android notification importance
vibrate: true, // (optional) default: true. Creates the default vibration patten if true.
},
(created) => console.log(`createChannel returned '${created}'`), // (optional) callback returns whether the channel was created, false means it already existed.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • do we need this? where are the logs stored?

);
PushNotification.localNotification({
channelId: key, //this must be same with channelid in createchannel
title: 'Local Message',
message: 'Local message !!',
});
};

export default LocalNotification;
Loading
Loading