diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 0000000..6b9f58e --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1,3 @@ +nodeLinker: node-modules + +yarnPath: .yarn/releases/yarn-3.6.1.cjs \ No newline at end of file diff --git a/README.md b/README.md index 4acfe36..a1538b3 100644 --- a/README.md +++ b/README.md @@ -107,9 +107,9 @@ Your `AndroidManifest.xml` should look liks this ### requestLocation ```javascript -import { requestLocation } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -const response = await requestLocation({ allowWhileUsing: true }); +const response = await Geofencing.requestLocation({ allowWhileUsing: true }); ``` Response: ```json @@ -121,9 +121,9 @@ Response: To request background location: ```javascript -import { requestLocation } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -const response = await requestLocation({ allowAlways: true }); +const response = await Geofencing.requestLocation({ allowAlways: true }); ``` Response: ```json @@ -141,17 +141,17 @@ Supported options: ### getLocationAuthorizationStatus ```javascript -import { getLocationAuthorizationStatus } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -const response = await getLocationAuthorizationStatus(); +const response = await Geofencing.getLocationAuthorizationStatus(); ``` Response: `WhileInUse` `Always` `Denied` ### getCurrentLocation ```javascript -import { getCurrentLocation } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -const response = await getCurrentLocation(); +const response = await Geofencing.getCurrentLocation(); ``` Reponse: ```json @@ -171,9 +171,9 @@ Reponse: ### addGeofence ```javascript -import { addGeofence } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -const response = await addGeofence({ +const response = await Geofencing.addGeofence({ id: 'a9957259-8036-4dcb-974c-34eae9b44bdb', latitude: 16.153062, longitude: 100.281585, @@ -195,9 +195,9 @@ Supported options: ### removeGeofence ```javascript -import { removeGeofence } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -const response = await removeGeofence(id) +const response = await Geofencing.removeGeofence(id) ``` Response: ```json @@ -211,9 +211,9 @@ Supported options: ### getRegisteredGeofences ```javascript -import { getRegisteredGeofences } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -const response = await getRegisteredGeofences() +const response = await Geofencing.getRegisteredGeofences() ``` Response: ```json @@ -250,9 +250,9 @@ import { Authorization } from '@rn-bridge/react-native-geofencing'; ### onEnter ```javascript -import { Geofence, Events } from '@rn-bridge/react-native-geofencing'; +import Geofencing, { Events } from '@rn-bridge/react-native-geofencing'; -Geofence.onEnter((ids: string[]) => { +Geofencing.onEnter((ids: string[]) => { console.log(Events.Enter, ids); }); ``` @@ -263,9 +263,9 @@ Response: ### onExit ```javascript -import { Geofence, Events } from '@rn-bridge/react-native-geofencing'; +import Geofencing, { Events } from '@rn-bridge/react-native-geofencing'; -Geofence.onExit((ids: string[]) => { +Geofencing.onExit((ids: string[]) => { console.log(Events.Exit, ids); }); ``` @@ -276,30 +276,30 @@ Response: ### removeOnEnterListener ```javascript -import { Geofence } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -Geofence.removeOnEnterListener() +Geofencing.removeOnEnterListener() ``` ### removeOnExitListener ```javascript -import { Geofence } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -Geofence.removeOnExitListener() +Geofencing.removeOnExitListener() ``` ### isOnEnterListenerAdded ```javascript -import { Geofence } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -Geofence.isOnEnterListenerAdded() // true or false +Geofencing.isOnEnterListenerAdded() // true or false ``` ### isOnExitListenerAdded ```javascript -import { Geofence } from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; -Geofence.isOnExitListenerAdded() // true or false +Geofencing.isOnExitListenerAdded() // true or false ``` ## How To Run Example App ? diff --git a/android/build.gradle b/android/build.gradle index a4dd9fd..13876f4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ import com.android.Version buildscript { // Buildscript is evaluated before everything else so we can't use getExtOrDefault - def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["ReactNativeGeofencing_kotlinVersion"] + def kotlin_version = project.properties["ReactNativeGeofencing_kotlinVersion"] repositories { google() diff --git a/example/index.ts b/example/index.js similarity index 63% rename from example/index.ts rename to example/index.js index 8cb4ff9..7c048c4 100644 --- a/example/index.ts +++ b/example/index.js @@ -1,13 +1,13 @@ import { AppRegistry } from 'react-native'; import { App } from './src/App'; import { name as appName } from './app.json'; -import { Geofence, Events } from '@rn-bridge/react-native-geofencing'; +import Geofencing, { Events } from '@rn-bridge/react-native-geofencing'; -Geofence.onEnter((ids: string[]) => { +Geofencing.onEnter((ids) => { console.log(Events.Enter, ids); }); -Geofence.onExit((ids: string[]) => { +Geofencing.onExit((ids) => { console.log(Events.Exit, ids); }); diff --git a/example/src/App.tsx b/example/src/App.tsx index e278b61..2f92990 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,12 +1,5 @@ import { StyleSheet, View, TouchableOpacity, Text, Alert } from 'react-native'; -import { - addGeofence, - removeGeofence, - getRegisteredGeofences, - requestLocation, - getLocationAuthorizationStatus, - getCurrentLocation -} from '@rn-bridge/react-native-geofencing'; +import Geofencing from '@rn-bridge/react-native-geofencing'; const Button = ({ title, @@ -34,7 +27,7 @@ export const App = () => { style={styles.button} title="Request Location While Using" onPress={async () => { - const response = await requestLocation({ allowWhileUsing: true }); + const response = await Geofencing.requestLocation({ allowWhileUsing: true }); console.log('requestLocation:', response); Alert.alert('', `Location: ${response.location}`); }} @@ -45,7 +38,7 @@ export const App = () => { style={styles.button} title="Request Location Always" onPress={async () => { - const response = await requestLocation({ allowAlways: true }); + const response = await Geofencing.requestLocation({ allowAlways: true }); console.log('requestLocation:', response); Alert.alert('', `Location: ${response.location}`); }} @@ -56,7 +49,7 @@ export const App = () => { style={styles.button} title="Get Current Location" onPress={async () => { - const response = await getCurrentLocation(); + const response = await Geofencing.getCurrentLocation(); console.log('getCurrentLocation:', response); Alert.alert( '', @@ -70,7 +63,7 @@ export const App = () => { style={styles.button} title="Add Geo Fence" onPress={async () => { - const response = await addGeofence({ + const response = await Geofencing.addGeofence({ id: 'a9957259-8036-4dcb-974c-34eae9b44bdb', latitude: 10.9314, longitude: 76.9781, @@ -92,7 +85,7 @@ export const App = () => { style={styles.button} title="Remove Geo Fence" onPress={async () => { - const response = await removeGeofence( + const response = await Geofencing.removeGeofence( 'a9957259-8036-4dcb-974c-34eae9b44bdb' ); @@ -111,7 +104,7 @@ export const App = () => { style={styles.button} title="Get Registered Geo Fences" onPress={async () => { - const response = await getRegisteredGeofences(); + const response = await Geofencing.getRegisteredGeofences(); console.log('getRegisteredGeofences:', response); const ids = response.map((id: string, index: number) => `id${index+1}: ${id}`).join("\n") const message = response.length == 0 ? "No geofence registered" : ids @@ -124,7 +117,7 @@ export const App = () => { style={styles.button} title="Get Authorization Status" onPress={async () => { - const response = await getLocationAuthorizationStatus(); + const response = await Geofencing.getLocationAuthorizationStatus(); console.log('getLocationAuthorizationStatus:', response); Alert.alert('', `Location: ${response}`); }} diff --git a/package.json b/package.json index 7582d16..2383828 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "@rn-bridge/react-native-geofencing", - "version": "0.7.0", + "version": "0.8.0", "description": "Native modules to determine if a location is within defined geographical boundaries", "source": "./src/index.tsx", - "main": "./lib/commonjs/index.js", + "main": "./src/index.tsx", "module": "./lib/module/index.js", "types": "./src/types/index.d.ts", "files": [ @@ -114,6 +114,13 @@ { "esm": true } + ], + [ + "typescript", + { + "project": "tsconfig.build.json", + "esm": true + } ] ] } diff --git a/src/__tests__/index.test.tsx b/src/__tests__/index.test.tsx index a6eb847..91dcca7 100644 --- a/src/__tests__/index.test.tsx +++ b/src/__tests__/index.test.tsx @@ -1,12 +1,5 @@ -import { NativeEventEmitter, NativeModules } from 'react-native'; - -const mockedCallbacks: { - onEnter: ((data: string[]) => void)[]; - onExit: ((data: string[]) => void)[]; -} = { - onEnter: [], - onExit: [] -}; +import { NativeModules } from 'react-native'; +import Geofencing, { Events } from "../" jest.mock('react-native', () => { return { @@ -19,39 +12,13 @@ jest.mock('react-native', () => { getRegisteredGeofences: jest.fn(), removeAllGeofence: jest.fn(), requestLocation: jest.fn(), - Geofence: { - onEnter: (callback: (data: string[]) => void) => { - mockedCallbacks.onEnter.push(callback); - }, - onExit: (callback: (data: string[]) => void) => { - mockedCallbacks.onExit.push(callback); - }, - removeOnEnterListener: jest.fn(), - removeOnExitListener: jest.fn() - } } }, NativeEventEmitter: jest.fn().mockImplementation(() => { return { addListener: jest.fn(), removeAllListeners: jest.fn(), - emit: (event: string, data: string[]) => { - if (event === 'onEnter') { - mockedCallbacks.onEnter.map( - (callback: (data: string[]) => void) => { - callback(data); - } - ); - - mockedCallbacks.onEnter = []; - } else if (event === 'onExit') { - mockedCallbacks.onExit.map((callback: (data: string[]) => void) => { - callback(data); - }); - - mockedCallbacks.onExit = []; - } - }, + emit: jest.fn(), listenerCount: jest.fn().mockReturnValue(1) }; }), @@ -69,7 +36,7 @@ jest.mock('react-native', () => { }, Platform: { select: jest.fn(), - OS: 'android' // You can switch to 'ios' for testing iOS specific code + OS: 'android' }, AppRegistry: { registerHeadlessTask: jest.fn() @@ -78,7 +45,6 @@ jest.mock('react-native', () => { }); describe('Geofencing Module', () => { - const geofencingEventEmitter = new NativeEventEmitter(); beforeEach(() => { jest.clearAllMocks(); @@ -100,14 +66,14 @@ describe('Geofencing Module', () => { NativeModules.Geofencing.getCurrentLocation.mockResolvedValueOnce( mockLocation ); - const location = await NativeModules.Geofencing.getCurrentLocation(); + const location = await Geofencing.getCurrentLocation(); expect(location).toEqual(mockLocation); }); it('should add a geofence', async () => { const mockResponse = { success: true, id: '1', error: '' }; NativeModules.Geofencing.addGeofence.mockResolvedValueOnce(mockResponse); - const response = await NativeModules.Geofencing.addGeofence({ + const response = await Geofencing.addGeofence({ id: '1', latitude: 10.0, longitude: 20.0, @@ -125,7 +91,7 @@ describe('Geofencing Module', () => { it('should remove a geofence', async () => { const mockResponse = { success: true, id: '1', error: '' }; NativeModules.Geofencing.removeGeofence.mockResolvedValueOnce(mockResponse); - const response = await NativeModules.Geofencing.removeGeofence('1'); + const response = await Geofencing.removeGeofence('1'); expect(response).toEqual(mockResponse); expect(NativeModules.Geofencing.removeGeofence).toHaveBeenCalledWith('1'); }); @@ -135,7 +101,7 @@ describe('Geofencing Module', () => { NativeModules.Geofencing.getRegisteredGeofences.mockResolvedValueOnce( mockGeofences ); - const geofences = await NativeModules.Geofencing.getRegisteredGeofences(); + const geofences = await Geofencing.getRegisteredGeofences(); expect(geofences).toEqual(mockGeofences); }); @@ -144,35 +110,29 @@ describe('Geofencing Module', () => { NativeModules.Geofencing.removeAllGeofence.mockResolvedValueOnce( mockResponse ); - const response = await NativeModules.Geofencing.removeAllGeofence(); + const response = await Geofencing.removeAllGeofence(); expect(response).toEqual(mockResponse); }); it('should handle geofence enter event', () => { const callback = jest.fn(); - NativeModules.Geofencing.Geofence.onEnter(callback); - geofencingEventEmitter.emit('onEnter', ['1', '2']); - expect(callback).toHaveBeenCalledWith(['1', '2']); + Geofencing.onEnter(callback); + expect(Geofencing.geofencingEventEmitter.addListener).toHaveBeenCalledWith(Events.Enter, callback); }); it('should handle geofence exit event', () => { const callback = jest.fn(); - NativeModules.Geofencing.Geofence.onExit(callback); - geofencingEventEmitter.emit('onExit', ['3', '4']); - expect(callback).toHaveBeenCalledWith(['3', '4']); + Geofencing.onExit(callback); + expect(Geofencing.geofencingEventEmitter.addListener).toHaveBeenCalledWith(Events.Exit, callback); }); it('should remove geofence enter listener', () => { - NativeModules.Geofencing.Geofence.removeOnEnterListener(); - expect( - NativeModules.Geofencing.Geofence.removeOnEnterListener - ).toHaveBeenCalled(); + Geofencing.removeOnEnterListener(); + expect(Geofencing.geofencingEventEmitter.removeAllListeners).toHaveBeenCalledWith(Events.Enter); }); it('should remove geofence exit listener', () => { - NativeModules.Geofencing.Geofence.removeOnExitListener(); - expect( - NativeModules.Geofencing.Geofence.removeOnExitListener - ).toHaveBeenCalled(); + Geofencing.removeOnExitListener(); + expect(Geofencing.geofencingEventEmitter.removeAllListeners).toHaveBeenCalledWith(Events.Exit); }); }); diff --git a/src/index.tsx b/src/index.tsx index 863f72f..1d55577 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -16,13 +16,13 @@ const LINKING_ERROR = const Geofencing = NativeModules.Geofencing ? NativeModules.Geofencing : new Proxy( - {}, - { - get() { - throw new Error(LINKING_ERROR); - } + {}, + { + get() { + throw new Error(LINKING_ERROR); } - ); + } + ); export const Events = { Enter: 'onEnter', @@ -46,7 +46,7 @@ async function delay(duration: number): Promise { } async function onGeofenceTransition(params: { event: string; ids: string[] }) { - if (!Geofence.isOnEnterListenerAdded() || !Geofence.isOnExitListenerAdded()) { + if (!isOnEnterListenerAdded() || !isOnExitListenerAdded()) { console.log('Listeners not added, waiting for 5sec...'); await delay(5000); } @@ -92,7 +92,7 @@ async function requestAndroidPermissions( }; } -export async function requestLocation( +async function requestLocation( params: requestLocationParamsType = {} ): Promise { const requestParams = { @@ -135,14 +135,14 @@ async function getLocationAuthorizationStatusAndroid(): Promise { return location; } -export async function getLocationAuthorizationStatus(): Promise { +async function getLocationAuthorizationStatus(): Promise { if (Platform.OS === 'android') { return await getLocationAuthorizationStatusAndroid(); } return await Geofencing.getLocationAuthorizationStatus(); } -type locationType = { +export type locationType = { latitude: number; longitude: number; altitude: number; @@ -155,7 +155,7 @@ type locationType = { timeZone: string; }; -export async function getCurrentLocation(): Promise { +async function getCurrentLocation(): Promise { return await Geofencing.getCurrentLocation(); } @@ -172,7 +172,7 @@ type returnType = { error: string; }; -export async function addGeofence( +async function addGeofence( params: paramsType = {} as paramsType ): Promise { if (!params.id || !params.latitude || !params.longitude || !params.radius) { @@ -181,14 +181,14 @@ export async function addGeofence( return await Geofencing.addGeofence(params); } -export async function removeGeofence(id: string): Promise { +async function removeGeofence(id: string): Promise { if (!id) { return Promise.reject('id cannot be null or undefined'); } return await Geofencing.removeGeofence(id); } -export async function getRegisteredGeofences(): Promise { +async function getRegisteredGeofences(): Promise { return await Geofencing.getRegisteredGeofences(); } @@ -197,30 +197,48 @@ type removeAllGeofenceReturnType = { type: string; }; -export async function removeAllGeofence(): Promise { +async function removeAllGeofence(): Promise { return await Geofencing.removeAllGeofence(); } -export const Geofence = { - onEnter: (callback: (ids: string[]) => void): EventSubscription => { - return geofencingEventEmitter.addListener(Events.Enter, callback); - }, +function onEnter(callback: (ids: string[]) => void): EventSubscription { + return geofencingEventEmitter.addListener(Events.Enter, callback); +} - onExit: (callback: (ids: string[]) => void): EventSubscription => { - return geofencingEventEmitter.addListener(Events.Exit, callback); - }, +function onExit(callback: (ids: string[]) => void): EventSubscription { + return geofencingEventEmitter.addListener(Events.Exit, callback); +} - removeOnEnterListener: (): void => { - geofencingEventEmitter.removeAllListeners(Events.Enter); - }, +function removeOnEnterListener(): void { + geofencingEventEmitter.removeAllListeners(Events.Enter); +} - removeOnExitListener: (): void => { - geofencingEventEmitter.removeAllListeners(Events.Exit); - }, - isOnEnterListenerAdded: (): boolean => { - return geofencingEventEmitter.listenerCount(Events.Enter) > 0; - }, - isOnExitListenerAdded: (): boolean => { - return geofencingEventEmitter.listenerCount(Events.Exit) > 0; - } -}; +function removeOnExitListener(): void { + geofencingEventEmitter.removeAllListeners(Events.Exit); +} + +function isOnEnterListenerAdded(): boolean { + return geofencingEventEmitter.listenerCount(Events.Enter) > 0; +} + +function isOnExitListenerAdded(): boolean { + return geofencingEventEmitter.listenerCount(Events.Exit) > 0; +} + + +export default { + requestLocation, + getLocationAuthorizationStatus, + getCurrentLocation, + addGeofence, + removeGeofence, + getRegisteredGeofences, + removeAllGeofence, + onEnter, + onExit, + removeOnEnterListener, + removeOnExitListener, + isOnEnterListenerAdded, + isOnExitListenerAdded, + geofencingEventEmitter +} \ No newline at end of file diff --git a/src/types/index.d.ts b/src/types/index.d.ts index bde3b2e..54f8444 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,67 +1,78 @@ -import { type EventSubscription } from 'react-native'; +import { NativeEventEmitter, type EventSubscription } from 'react-native'; export declare const Events: { - Enter: string; - Exit: string; + Enter: string; + Exit: string; }; export declare const Authorization: { - Always: string; - WhenInUse: string; - Restricted: string; - Denied: string; - NotDetermined: string; - Unknown: string; + Always: string; + WhenInUse: string; + Restricted: string; + Denied: string; + NotDetermined: string; + Unknown: string; }; type requestLocationParamsType = { - allowWhileUsing?: boolean; - allowAlways?: boolean; + allowWhileUsing?: boolean; + allowAlways?: boolean; }; type requestLocationResponseType = { - success: boolean; - location: string; + success: boolean; + location: string; }; -export declare function requestLocation( - params?: requestLocationParamsType -): Promise; -export declare function getLocationAuthorizationStatus(): Promise; -type locationType = { - latitude: number; - longitude: number; - altitude: number; - name: string; - city: string; - state: string; - country: string; - postalCode: string; - isoCountryCode: string; - timeZone: string; +declare function requestLocation(params?: requestLocationParamsType): Promise; +declare function getLocationAuthorizationStatus(): Promise; +export type locationType = { + latitude: number; + longitude: number; + altitude: number; + name: string; + city: string; + state: string; + country: string; + postalCode: string; + isoCountryCode: string; + timeZone: string; }; -export declare function getCurrentLocation(): Promise; +declare function getCurrentLocation(): Promise; type paramsType = { - id: string; - latitude: number; - longitude: number; - radius: number; + id: string; + latitude: number; + longitude: number; + radius: number; }; type returnType = { - success: boolean; - id: string; - error: string; + success: boolean; + id: string; + error: string; }; -export declare function addGeofence(params?: paramsType): Promise; -export declare function removeGeofence(id: string): Promise; -export declare function getRegisteredGeofences(): Promise; +declare function addGeofence(params?: paramsType): Promise; +declare function removeGeofence(id: string): Promise; +declare function getRegisteredGeofences(): Promise; type removeAllGeofenceReturnType = { - success: boolean; - type: string; + success: boolean; + type: string; }; -export declare function removeAllGeofence(): Promise; -export declare const Geofence: { - onEnter: (callback: (ids: string[]) => void) => EventSubscription; - onExit: (callback: (ids: string[]) => void) => EventSubscription; - removeOnEnterListener: () => void; - removeOnExitListener: () => void; - isOnEnterListenerAdded: () => boolean; - isOnExitListenerAdded: () => boolean; +declare function removeAllGeofence(): Promise; +declare function onEnter(callback: (ids: string[]) => void): EventSubscription; +declare function onExit(callback: (ids: string[]) => void): EventSubscription; +declare function removeOnEnterListener(): void; +declare function removeOnExitListener(): void; +declare function isOnEnterListenerAdded(): boolean; +declare function isOnExitListenerAdded(): boolean; +declare const _default: { + requestLocation: typeof requestLocation; + getLocationAuthorizationStatus: typeof getLocationAuthorizationStatus; + getCurrentLocation: typeof getCurrentLocation; + addGeofence: typeof addGeofence; + removeGeofence: typeof removeGeofence; + getRegisteredGeofences: typeof getRegisteredGeofences; + removeAllGeofence: typeof removeAllGeofence; + onEnter: typeof onEnter; + onExit: typeof onExit; + removeOnEnterListener: typeof removeOnEnterListener; + removeOnExitListener: typeof removeOnExitListener; + isOnEnterListenerAdded: typeof isOnEnterListenerAdded; + isOnExitListenerAdded: typeof isOnExitListenerAdded; + geofencingEventEmitter: NativeEventEmitter; }; -export {}; -//# sourceMappingURL=index.d.ts.map +export default _default; \ No newline at end of file