@pinwheel/react-native-pinwheel 2.3.17 → 2.5.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,64 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## 2.4.x Releases
6
+
7
+ ### [2.4.0](https://github.com/underdog-tech/react-native-pinwheel/releases/tag/2.4.0)
8
+
9
+ - Removing `overrides` from main package.
10
+ - Updating example app to use newest ReactNative versions.
11
+ - Changing devDependencies to use newest React Native Webview (for typing).
12
+
13
+ ## 2.3.x Releases
14
+
15
+ - `2.3.x` Releases - [2.3.4](#234) | [2.3.5](#235) | [2.3.6](#236) | [2.3.10](#2310) | [2.3.12](#2312) | [2.3.13](#2313) | [2.3.14](#2314) | [2.3.17](#2317)
16
+
17
+ ---
18
+
19
+ ### [2.3.17](https://github.com/underdog-tech/react-native-pinwheel/releases/tag/2.3.17)
20
+
21
+ Export `ScreenTransition` event payload type for the `screen_transition` event.
22
+
23
+
24
+ ### [2.3.14](https://github.com/underdog-tech/react-native-pinwheel/releases/tag/2.3.14)
25
+
26
+ Remove `hermes-engine` and `shell-quote` sub-dependencies from package-lock files.
27
+
28
+ ### [2.3.13](https://github.com/underdog-tech/react-native-pinwheel/releases/tag/2.3.13)
29
+
30
+ Bump `hermes-engine` and `shell-quote` sub-dependency package.
31
+
32
+ ### [2.3.12](https://github.com/underdog-tech/react-native-pinwheel/releases/tag/2.3.12)
33
+
34
+ Add CircleCI scripting and local scripts.
35
+ - Add `npm run dev` script.
36
+ - Remove need for hardcoding api secret in code to run locally.
37
+
38
+ ### [2.3.10](https://github.com/underdog-tech/react-native-pinwheel/releases/tag/2.3.10)
39
+
40
+ Use node 16.7.0 instead of 12.16.1 to install dependencies.
41
+
42
+ ### [2.3.6](https://github.com/underdog-tech/react-native-pinwheel/releases/tag/2.3.6)
43
+
44
+ N/A
45
+
46
+ ### [2.3.5](https://github.com/underdog-tech/react-native-pinwheel/releases/tag/2.3.5)
47
+
48
+ N/A
49
+
50
+ ### [2.3.4](https://github.com/underdog-tech/react-native-pinwheel/releases/tag/2.3.4)
51
+
52
+ #### Added
53
+
54
+ - Export `EventPayload` type.
55
+ - Export `PinwheelError` type.
56
+ - Export `PinwheelErrorType` type.
57
+ - Export `EmptyPayloadObject` type as `Record<string, never>`.
58
+
59
+ ##### Updated
60
+
61
+ - `EventPayload` is no longer a union containing `{}`. It now contains `Record<string, never>` instead due to [this behavior](https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-all-types-assignable-to-empty-interfaces).
62
+ - Mark exported `Error` type as **@deprecated** because it collides with the built-in javascript `Error` object. Replaced with `PinwheelError`.
63
+ - Mark exported `ErrorType` type as **@deprecated** because the new naming convention is prefixing with "`PinwheelError`". Replaced with `PinwheelErrorType`.
64
+ - Update `onExit` type to be `(error: PinwheelError | Record<string, never>)` to be accurate with current functionality.
package/README.md CHANGED
@@ -28,17 +28,14 @@ You may want to run the example app locally to get started.
28
28
  ###### Failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65
29
29
  - Try downloading Xcode 14.2 from https://developer.apple.com/download/all/?q=xcode
30
30
 
31
+ ###### Failed to locate 'git', requesting installation of command line developer tools
32
+ For this or other errors related to command line developer tools:
33
+ - Make sure you have Command Line Tools for Xcode 14.2 installed
34
+ - Open Xcode > Click Xcode in the app menu > Settings > Locations > Command Line Tools dropdown and set the correct location
31
35
 
32
36
  ## Installation
33
37
 
34
- 1. Install [`react-native-webview`](https://www.npmjs.com/package/react-native-webview) peer dependency.
35
-
36
- ```bash
37
- $ npm install --save react-native-webview
38
- $ cd ios && pod install
39
- ```
40
-
41
- 2. Install Pinwheel React Native SDK
38
+ 1. Install Pinwheel React Native SDK
42
39
 
43
40
  ```bash
44
41
  $ npm install --save @pinwheel/react-native-pinwheel
@@ -50,7 +47,7 @@ $ npm install --save @pinwheel/react-native-pinwheel
50
47
 
51
48
  To initialize Link Modal, a short-lived link token will need to be generated first. Your server can generate the link token by sending a POST request to the /v1/link_tokens endpoint. DO NOT ever send this request from the client side and publicly expose your api_secret.
52
49
 
53
- The link token returned is valid for 15 minutes, after which it expires and can no longer be used to initialize Link. The expiration time is returned as a unix timestamp.
50
+ The link token returned is valid for one hour, after which it expires and can no longer be used to initialize Link. The expiration time is returned as a unix timestamp.
54
51
 
55
52
  ### Pinwheel Component
56
53
 
@@ -0,0 +1,18 @@
1
+ Pod::Spec.new do |s|
2
+ s.name = "RNPinwheelSDK"
3
+ s.version = "2.5.0-alpha"
4
+ s.summary = "React Native plugin for Pinwheel's SDK"
5
+ s.description = <<-DESC
6
+ An open source React Native plugin for calling Pinwheel's native SDKs to manage payroll data.
7
+ DESC
8
+ s.homepage = "https://github.com/underdog-tech/react-native-pinwheel"
9
+ s.license = { :file => 'LICENSE' }
10
+ s.author = { 'Pinwheel' => 'info@pinwheelapi.com' }
11
+ s.platform = :ios, "12.0"
12
+ s.source = { :path => 'ios' }
13
+ s.source_files = "ios/**/*.{h,m}"
14
+ s.public_header_files = 'ios/**/*.h'
15
+ s.requires_arc = true
16
+ s.dependency "React"
17
+ s.dependency 'PinwheelSDK', '2.4.3'
18
+ end
@@ -0,0 +1,50 @@
1
+ buildscript {
2
+ def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : '1.7.22'
3
+
4
+ repositories {
5
+ google()
6
+ mavenCentral()
7
+ }
8
+
9
+ dependencies {
10
+ classpath 'com.android.tools.build:gradle:7.2.2'
11
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12
+ }
13
+ }
14
+
15
+ apply plugin: 'com.android.library'
16
+ apply plugin: 'kotlin-android'
17
+
18
+ def MIN_PW_SDK_VERSION = '2.4.1'
19
+
20
+ android {
21
+ compileSdkVersion 33
22
+
23
+ defaultConfig {
24
+ minSdkVersion 24
25
+ targetSdkVersion 33
26
+ versionCode 1
27
+ versionName "1.0"
28
+ }
29
+ compileOptions {
30
+ sourceCompatibility = 1.8
31
+ targetCompatibility = 1.8
32
+ }
33
+
34
+ sourceSets {
35
+ main.java.srcDirs += 'src/main/java'
36
+ }
37
+ }
38
+
39
+ rootProject.allprojects {
40
+ repositories {
41
+ google()
42
+ mavenCentral()
43
+ }
44
+ }
45
+
46
+ dependencies {
47
+ def pwVersion = rootProject.hasProperty('pwVersion') ? rootProject.pwVersion : MIN_PW_SDK_VERSION
48
+ implementation 'com.facebook.react:react-native:+'
49
+ implementation "com.getpinwheel:pinwheel-android:$pwVersion"
50
+ }
@@ -0,0 +1,6 @@
1
+
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+ package="com.underdog_tech.react">
4
+
5
+ </manifest>
6
+
@@ -0,0 +1,16 @@
1
+ package com.underdog_tech.react
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.NativeModule
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ class PinwheelPackage : ReactPackage {
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
+ return listOf(RNTPinwheelEvents(reactContext)).toMutableList()
11
+ }
12
+
13
+ override fun createViewManagers(
14
+ reactContext: ReactApplicationContext
15
+ ) = listOf(PinwheelViewManager(reactContext))
16
+ }
@@ -0,0 +1,213 @@
1
+ package com.underdog_tech.react
2
+
3
+ import android.view.Choreographer
4
+ import android.view.View
5
+ import android.view.ViewGroup
6
+ import android.widget.FrameLayout
7
+ import androidx.fragment.app.FragmentActivity
8
+ import com.facebook.react.bridge.Arguments
9
+ import com.facebook.react.bridge.ReactApplicationContext
10
+ import com.facebook.react.bridge.ReadableArray
11
+ import com.facebook.react.bridge.WritableMap
12
+ import com.facebook.react.bridge.WritableNativeMap
13
+ import com.facebook.react.modules.core.DeviceEventManagerModule
14
+ import com.facebook.react.uimanager.ThemedReactContext
15
+ import com.facebook.react.uimanager.ViewGroupManager
16
+ import com.facebook.react.uimanager.annotations.ReactPropGroup
17
+ import com.facebook.react.uimanager.annotations.ReactProp
18
+ import com.underdog_tech.pinwheel_android.PinwheelFragment
19
+ import com.underdog_tech.pinwheel_android.PinwheelEventListener
20
+ import com.underdog_tech.pinwheel_android.model.PinwheelEventType
21
+ import com.underdog_tech.pinwheel_android.model.PinwheelEventPayload
22
+ import com.underdog_tech.pinwheel_android.model.PinwheelAmount
23
+ import com.underdog_tech.pinwheel_android.model.PinwheelTarget
24
+ import com.underdog_tech.pinwheel_android.model.PinwheelAllocation
25
+ import com.underdog_tech.pinwheel_android.model.PinwheelParams
26
+ import com.underdog_tech.pinwheel_android.model.PinwheelResult
27
+ import com.underdog_tech.pinwheel_android.model.PinwheelError
28
+ import com.underdog_tech.pinwheel_android.model.PinwheelSelectedEmployerPayload
29
+ import com.underdog_tech.pinwheel_android.model.PinwheelSelectedPlatformPayload
30
+ import com.underdog_tech.pinwheel_android.model.PinwheelLoginPayload
31
+ import com.underdog_tech.pinwheel_android.model.PinwheelLoginAttemptPayload
32
+ import com.underdog_tech.pinwheel_android.model.PinwheelDDFormCreatePayload
33
+ import com.underdog_tech.pinwheel_android.model.PinwheelScreenTransitionPayload
34
+ import com.underdog_tech.pinwheel_android.model.PinwheelInputAmountPayload
35
+
36
+ fun PinwheelTarget.toWritableMap(): WritableMap {
37
+ return Arguments.createMap().apply {
38
+ putString("accountType", this@toWritableMap.accountType)
39
+ putString("accountName", this@toWritableMap.accountName)
40
+ }
41
+ }
42
+
43
+ fun PinwheelAllocation.toWritableMap(): WritableMap {
44
+ return Arguments.createMap().apply {
45
+ putString("type", this@toWritableMap.type)
46
+ this@toWritableMap.value?.let { putDouble("value", it.toDouble()) }
47
+ putMap("target", this@toWritableMap.target?.toWritableMap())
48
+ }
49
+ }
50
+
51
+ fun PinwheelParams.toWritableMap(): WritableMap {
52
+ return Arguments.createMap().apply {
53
+ putMap("amount", this@toWritableMap.amount?.toWritableMap())
54
+ }
55
+ }
56
+
57
+ fun PinwheelEventPayload.toWritableMap(): WritableMap = when (this) {
58
+ is PinwheelAmount -> Arguments.createMap().apply {
59
+ putDouble("value", this@toWritableMap.value.toDouble())
60
+ putString("unit", this@toWritableMap.unit)
61
+ }
62
+
63
+ is PinwheelInputAmountPayload -> Arguments.createMap().apply {
64
+ putString("action", this@toWritableMap.action)
65
+ putMap("allocation", this@toWritableMap.allocation?.toWritableMap())
66
+ }
67
+
68
+ is PinwheelResult -> Arguments.createMap().apply {
69
+ putString("accountId", this@toWritableMap.accountId)
70
+ putString("platformId", this@toWritableMap.platformId)
71
+ putString("job", this@toWritableMap.job)
72
+ putMap("params", this@toWritableMap.params?.toWritableMap())
73
+ }
74
+ is PinwheelError -> Arguments.createMap().apply {
75
+ putString("type", this@toWritableMap.type)
76
+ putString("code", this@toWritableMap.code)
77
+ putString("message", this@toWritableMap.message)
78
+ putBoolean("pendingRetry", this@toWritableMap.pendingRetry)
79
+ }
80
+ is PinwheelSelectedEmployerPayload -> Arguments.createMap().apply {
81
+ putString("selectedEmployerId", this@toWritableMap.selectedEmployerId)
82
+ putString("selectedEmployerName", this@toWritableMap.selectedEmployerName)
83
+ }
84
+ is PinwheelSelectedPlatformPayload -> Arguments.createMap().apply {
85
+ putString("selectedPlatformId", this@toWritableMap.selectedPlatformId)
86
+ putString("selectedPlatformName", this@toWritableMap.selectedPlatformName)
87
+ }
88
+ is PinwheelLoginPayload -> Arguments.createMap().apply {
89
+ putString("accountId", this@toWritableMap.accountId)
90
+ putString("platformId", this@toWritableMap.platformId)
91
+ }
92
+ is PinwheelLoginAttemptPayload -> Arguments.createMap().apply {
93
+ putString("platformId", this@toWritableMap.platformId)
94
+ }
95
+ is PinwheelDDFormCreatePayload -> Arguments.createMap().apply {
96
+ putString("url", this@toWritableMap.url)
97
+ }
98
+ is PinwheelScreenTransitionPayload -> Arguments.createMap().apply {
99
+ putString("screenName", this@toWritableMap.screenName)
100
+ putString("selectedEmployerId", this@toWritableMap.selectedEmployerId)
101
+ putString("selectedEmployerName", this@toWritableMap.selectedEmployerName)
102
+ putString("selectedPlatformId", this@toWritableMap.selectedPlatformId)
103
+ putString("selectedPlatformName", this@toWritableMap.selectedPlatformName)
104
+ }
105
+ else -> throw IllegalArgumentException("Unsupported PinwheelEventPayload type")
106
+ }
107
+
108
+ class PinwheelViewManager(
109
+ private val reactContext: ReactApplicationContext
110
+ ) : ViewGroupManager<FrameLayout>(), PinwheelEventListener {
111
+ private var propWidth: Int? = reactContext.resources.displayMetrics.widthPixels
112
+ private var propHeight: Int? = reactContext.resources.displayMetrics.heightPixels
113
+ private var token: String? = null
114
+
115
+ override fun getName() = REACT_CLASS
116
+
117
+ /**
118
+ * Return a FrameLayout which will later hold the Fragment
119
+ */
120
+ override fun createViewInstance(reactContext: ThemedReactContext): FrameLayout {
121
+ return FrameLayout(reactContext)
122
+ }
123
+
124
+ /**
125
+ * Map the "create" command to an integer
126
+ */
127
+ override fun getCommandsMap() = mapOf("create" to COMMAND_CREATE)
128
+
129
+ /**
130
+ * Handle "create" command (called from JS) and call createFragment method
131
+ */
132
+ override fun receiveCommand(
133
+ root: FrameLayout,
134
+ commandId: String,
135
+ args: ReadableArray?
136
+ ) {
137
+ super.receiveCommand(root, commandId, args)
138
+ val reactNativeViewId = requireNotNull(args).getInt(0)
139
+
140
+ when (commandId.toInt()) {
141
+ COMMAND_CREATE -> createFragment(root, reactNativeViewId)
142
+ }
143
+ }
144
+
145
+ @ReactPropGroup(names = ["width", "height"], customType = "Style")
146
+ fun setStyle(view: FrameLayout, index: Int, value: Int) {
147
+ if (index == 0) propWidth = value
148
+ if (index == 1) propHeight = value
149
+ }
150
+
151
+ @ReactProp(name="token")
152
+ fun setToken(view: FrameLayout, token: String) {
153
+ this.token = token
154
+ }
155
+
156
+ /**
157
+ * Replace your React Native view with a custom fragment
158
+ */
159
+ fun createFragment(root: FrameLayout, reactNativeViewId: Int) {
160
+ val parentView = root.findViewById<ViewGroup>(reactNativeViewId)
161
+ setupLayout(parentView)
162
+
163
+
164
+ this.token?.let {
165
+ val pinwheelFragment = PinwheelFragment.newInstance(it, "react native")
166
+ pinwheelFragment.pinwheelEventListener = this
167
+ val activity = reactContext.currentActivity as FragmentActivity
168
+ activity.supportFragmentManager
169
+ .beginTransaction()
170
+ .replace(reactNativeViewId, pinwheelFragment, reactNativeViewId.toString())
171
+ .commit()
172
+ }
173
+ }
174
+
175
+ fun setupLayout(view: View) {
176
+ Choreographer.getInstance().postFrameCallback(object: Choreographer.FrameCallback {
177
+ override fun doFrame(frameTimeNanos: Long) {
178
+ manuallyLayoutChildren(view)
179
+ view.viewTreeObserver.dispatchOnGlobalLayout()
180
+ Choreographer.getInstance().postFrameCallback(this)
181
+ }
182
+ })
183
+ }
184
+
185
+ override fun onEvent(eventName: PinwheelEventType, payload: PinwheelEventPayload?) {
186
+ val params = WritableNativeMap()
187
+ params.putString("name", eventName.toString())
188
+ params.putMap("payload", payload?.toWritableMap())
189
+ reactContext
190
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
191
+ .emit("PINWHEEL_EVENT", params)
192
+ }
193
+
194
+ /**
195
+ * Layout all children properly
196
+ */
197
+ private fun manuallyLayoutChildren(view: View) {
198
+ // propWidth and propHeight coming from react-native props
199
+ val width = requireNotNull(propWidth)
200
+ val height = requireNotNull(propHeight)
201
+
202
+ view.measure(
203
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
204
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY))
205
+
206
+ view.layout(0, 0, width, height)
207
+ }
208
+
209
+ companion object {
210
+ private const val REACT_CLASS = "RNTPinwheel"
211
+ private const val COMMAND_CREATE = 1
212
+ }
213
+ }
@@ -0,0 +1,51 @@
1
+ package com.underdog_tech.react
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
6
+ import com.facebook.react.bridge.ReactMethod
7
+ import com.facebook.react.bridge.WritableMap
8
+ import com.facebook.react.modules.core.DeviceEventManagerModule
9
+
10
+ class RNTPinwheelEvents(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
11
+ companion object {
12
+ private const val EVENT_KEY = "PINWHEEL_EVENT"
13
+ }
14
+
15
+ override fun getName(): String {
16
+ return "RNTPinwheelEvents"
17
+ }
18
+
19
+ @ReactMethod
20
+ fun anExposedMethod() {
21
+ val currentContext = reactApplicationContext
22
+ val eventName = "PINWHEEL_EVENT"
23
+ val params: WritableMap = Arguments.createMap().apply {
24
+ putString("type", "myEventType")
25
+ }
26
+ sendEvent(currentContext, eventName, params)
27
+ }
28
+
29
+ fun sendEvent(reactContext: ReactApplicationContext, eventName: String, params: WritableMap?) {
30
+ reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java).emit(eventName, params)
31
+ }
32
+
33
+ private var listenerCount = 0
34
+
35
+ @ReactMethod
36
+ fun addListener(eventName: String) {
37
+ if (listenerCount == 0) {
38
+ // Set up any upstream listeners or background tasks as necessary
39
+ }
40
+
41
+ listenerCount += 1
42
+ }
43
+
44
+ @ReactMethod
45
+ fun removeListeners(count: Int) {
46
+ listenerCount -= count
47
+ if (listenerCount == 0) {
48
+ // Remove upstream listeners, stop unnecessary background tasks
49
+ }
50
+ }
51
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Importing package.json here causes a problem with the folder structure when we npm pack and publish.
3
3
  */
4
- export declare const VERSION = "2.3.17";
4
+ export declare const VERSION = "2.5.0-alpha";
5
5
  export declare const LINK_PAGE_URL = "https://cdn.getpinwheel.com/link-v2.3.0.html";
6
6
  export declare const PINWHEEL_DOMAIN = "getpinwheel.com";
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Importing package.json here causes a problem with the folder structure when we npm pack and publish.
3
3
  */
4
- export const VERSION = '2.3.17';
4
+ export const VERSION = '2.5.0-alpha';
5
5
  export const LINK_PAGE_URL = 'https://cdn.getpinwheel.com/link-v2.3.0.html';
6
6
  export const PINWHEEL_DOMAIN = 'getpinwheel.com';
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import React from 'react';
2
2
  export declare const PINWHEEL_MESSAGE_TYPES: {
3
3
  PINWHEEL_EXIT: string;
4
4
  PINWHEEL_MODAL_CLOSE: string;
@@ -6,7 +6,7 @@ export declare const PINWHEEL_MESSAGE_TYPES: {
6
6
  PINWHEEL_SUCCESS: string;
7
7
  PINWHEEL_EVENT: string;
8
8
  };
9
- export declare type LinkResult = {
9
+ export type LinkResult = {
10
10
  accountId: string;
11
11
  platformId: string;
12
12
  job: string;
@@ -17,7 +17,7 @@ export declare type LinkResult = {
17
17
  };
18
18
  };
19
19
  };
20
- export declare type ScreenTransition = {
20
+ export type ScreenTransition = {
21
21
  screenName: string;
22
22
  selectedEmployerId?: string;
23
23
  selectedEmployerName?: string;
@@ -28,21 +28,21 @@ export declare type ScreenTransition = {
28
28
  * @deprecated This type will be removed in version 2.4. Use the renamed type `PinwheelErrorType`
29
29
  * instead.
30
30
  */
31
- export declare type ErrorType = 'clientError' | 'systemError' | 'userActionRequired' | 'platformError' | 'invalidAccountsConfiguration' | 'invalidUserInput' | 'invalidLinkToken';
32
- export declare type PinwheelErrorType = ErrorType;
31
+ export type ErrorType = 'clientError' | 'systemError' | 'userActionRequired' | 'platformError' | 'invalidAccountsConfiguration' | 'invalidUserInput' | 'invalidLinkToken';
32
+ export type PinwheelErrorType = ErrorType;
33
33
  /**
34
34
  * @deprecated The type should not be used as it clashes with the native JS `Error` object.
35
35
  * You should use `PinwheelError` instead. `Error` will be removed in version 2.4
36
36
  */
37
- export declare type Error = {
37
+ export type Error = {
38
38
  type: PinwheelErrorType;
39
39
  code: string;
40
40
  message: string;
41
41
  pendingRetry: boolean;
42
42
  };
43
- export declare type PinwheelError = Error;
44
- export declare type EmptyPayloadObject = Record<string, never>;
45
- export declare type EventPayload = {
43
+ export type PinwheelError = Error;
44
+ export type EmptyPayloadObject = Record<string, never>;
45
+ export type EventPayload = {
46
46
  selectedEmployerId: string;
47
47
  selectedEmployerName: string;
48
48
  } | {
@@ -55,7 +55,7 @@ export declare type EventPayload = {
55
55
  accountId: string;
56
56
  platformId: string;
57
57
  } | ScreenTransition | PinwheelError | EmptyPayloadObject | undefined;
58
- declare type PinwheelProps = {
58
+ type PinwheelProps = {
59
59
  linkToken: string;
60
60
  onLogin?: (result: {
61
61
  accountId: string;
@@ -69,5 +69,5 @@ declare type PinwheelProps = {
69
69
  onExit?: (error: PinwheelError | EmptyPayloadObject) => void;
70
70
  onEvent?: (eventName: string, payload: EventPayload) => void;
71
71
  };
72
- declare const _default: ({ linkToken, onLogin, onLoginAttempt, onSuccess, onError, onExit, onEvent }: PinwheelProps) => JSX.Element;
72
+ declare const _default: ({ linkToken, onLogin, onLoginAttempt, onSuccess, onError, onExit, onEvent }: PinwheelProps) => React.JSX.Element;
73
73
  export default _default;
package/index.js ADDED
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ // @ts-ignore-next-line
3
+ import Pinwheel from './pinwheel-wrapper';
4
+ import { SafeAreaView, StyleSheet } from 'react-native';
5
+ const styles = StyleSheet.create({
6
+ container: {
7
+ flex: 1,
8
+ },
9
+ });
10
+ export const PINWHEEL_MESSAGE_TYPES = {
11
+ PINWHEEL_EXIT: 'PINWHEEL_EXIT',
12
+ PINWHEEL_MODAL_CLOSE: 'PINWHEEL_MODAL_CLOSE',
13
+ PINWHEEL_LOAD_COMPLETE: 'PINWHEEL_LOAD_COMPLETE',
14
+ PINWHEEL_SUCCESS: 'PINWHEEL_SUCCESS',
15
+ PINWHEEL_EVENT: 'PINWHEEL_EVENT',
16
+ };
17
+ export default ({ linkToken, onLogin, onLoginAttempt, onSuccess, onError, onExit, onEvent }) => {
18
+ const handleEvent = (event) => {
19
+ if (!event) {
20
+ // first event is always an empty string
21
+ return;
22
+ }
23
+ const { name, payload } = event;
24
+ onEvent && onEvent(name, payload);
25
+ switch (name.toLowerCase()) {
26
+ case 'exit':
27
+ // console.log(`case: exit, onExit: ${onExit}`);
28
+ onExit && onExit(payload);
29
+ break;
30
+ case 'success':
31
+ // console.log(`case: success, onSuccess: ${onSuccess}`);
32
+ onSuccess && onSuccess(payload);
33
+ break;
34
+ case 'login':
35
+ // console.log(`case: login, onLogin: ${onLogin}`);
36
+ onLogin && onLogin(payload);
37
+ break;
38
+ case 'login_attempt':
39
+ // console.log(`case: login_attempt, onLoginAttempt: ${onLoginAttempt}`);
40
+ onLoginAttempt && onLoginAttempt(payload);
41
+ break;
42
+ case 'error':
43
+ // console.log(`case: error, onError: ${onError}`);
44
+ onError && onError(payload);
45
+ break;
46
+ default:
47
+ }
48
+ };
49
+ return (<SafeAreaView style={styles.container}>
50
+ {linkToken && <Pinwheel token={linkToken} style={{ flex: 1 }} onEvent={handleEvent}/>}
51
+ </SafeAreaView>);
52
+ };
@@ -0,0 +1,9 @@
1
+ #import <React/RCTBridgeModule.h>
2
+ #import <React/RCTEventEmitter.h>
3
+
4
+ @interface RNTPinwheelEvents : RCTEventEmitter <RCTBridgeModule>
5
+
6
+ + (instancetype)sharedInstance;
7
+ - (void)handlePinwheelEvent:(NSDictionary<NSString *, id> *)payload;
8
+
9
+ @end
@@ -0,0 +1,62 @@
1
+ #import "RNTPinwheelEvents.h"
2
+
3
+ @implementation RNTPinwheelEvents
4
+ {
5
+ bool hasListeners; // This is an instance variable declaration.
6
+ }
7
+
8
+ RCT_EXPORT_MODULE();
9
+ + (BOOL)requiresMainQueueSetup {
10
+ return NO; // change this to NO if you don't need the main thread
11
+ }
12
+
13
+ + (instancetype)sharedInstance {
14
+ static RNTPinwheelEvents *sharedInstance = nil;
15
+ static dispatch_once_t onceToken;
16
+ dispatch_once(&onceToken, ^{
17
+ sharedInstance = [[super allocWithZone:NULL] init];
18
+ });
19
+ return sharedInstance;
20
+ }
21
+
22
+ + (id)allocWithZone:(struct _NSZone *)zone {
23
+ return [self sharedInstance];
24
+ }
25
+
26
+ - (id)copyWithZone:(NSZone *)zone {
27
+ return self;
28
+ }
29
+ // Overriding the default init to make sure it's not used directly
30
+ - (instancetype)init {
31
+ if (self = [super init]) {
32
+ // Custom initialization if needed
33
+ }
34
+ return self;
35
+ }
36
+
37
+ // Will be called when this module's first listener is added.
38
+ -(void)startObserving {
39
+ NSLog(@"startObserving called");
40
+ hasListeners = YES;
41
+ // Set up any upstream listeners or background tasks as necessary
42
+ }
43
+
44
+ // Will be called when this module's last listener is removed, or on dealloc.
45
+ -(void)stopObserving {
46
+ NSLog(@"stopObserving called");
47
+ hasListeners = NO;
48
+ // Remove upstream listeners, stop unnecessary background tasks
49
+ }
50
+
51
+ - (void)handlePinwheelEvent:(NSDictionary<NSString *, id> *)payload
52
+ {
53
+ if (hasListeners) {// Only send events if anyone is listening
54
+ [self sendEventWithName:@"PINWHEEL_EVENT" body:payload];
55
+ }
56
+ }
57
+
58
+ - (NSArray<NSString *> *)supportedEvents {
59
+ return @[@"PINWHEEL_EVENT"]; // Add more event names here.
60
+ }
61
+
62
+ @end
@@ -0,0 +1,21 @@
1
+ #import <React/RCTViewManager.h>
2
+ #import "RNTPinwheelView.h"
3
+
4
+ @interface RNTPinwheelManager : RCTViewManager
5
+
6
+ @end
7
+
8
+ @implementation RNTPinwheelManager : RCTViewManager
9
+
10
+ RCT_EXPORT_MODULE(RNTPinwheelManager);
11
+
12
+ - (UIView *)view
13
+ {
14
+ RNTPinwheelView *pv = [[RNTPinwheelView alloc] init];
15
+ return pv;
16
+ }
17
+
18
+ RCT_EXPORT_VIEW_PROPERTY(token, NSString);
19
+
20
+ @end
21
+
@@ -0,0 +1,12 @@
1
+ #import <UIKit/UIKit.h>
2
+ #import <PinwheelSDK/PinwheelSDK-Swift.h>
3
+ #import "RNTPinwheelEvents.h"
4
+
5
+ @interface RNTPinwheelView : UIView <PinwheelWrapperDelegate>
6
+
7
+ @property (nonatomic, strong) PinwheelWrapperVC *pinwheelWrapperVC;
8
+ @property (nonatomic, assign) NSString *token;
9
+
10
+ - (instancetype)initWithFrame:(CGRect)frame token:(NSString *)token;
11
+
12
+ @end
@@ -0,0 +1,65 @@
1
+ #import "RNTPinwheelView.h"
2
+
3
+ @implementation RNTPinwheelView
4
+
5
+ - (instancetype)initWithFrame:(CGRect)frame {
6
+ if ((self = [super initWithFrame:frame])) {
7
+ [self initPinwheelWrapperVC];
8
+ }
9
+ return self;
10
+ }
11
+
12
+ - (instancetype)initWithFrame:(CGRect)frame token:(NSString *)token {
13
+ if ((self = [super initWithFrame:frame])) {
14
+ _token = token;
15
+ }
16
+ return self;
17
+ }
18
+
19
+ - (void)initPinwheelWrapperVC {
20
+ if (self.token != nil && self.pinwheelWrapperVC == nil) {
21
+ self.pinwheelWrapperVC = [[PinwheelWrapperVC alloc] initWithToken:self.token delegate:self sdk:@"react native"];
22
+ [self addSubview:self.pinwheelWrapperVC.view];
23
+ }
24
+ }
25
+
26
+ - (void)setToken:(NSString *)newToken {
27
+ if (![_token isEqualToString:newToken]) {
28
+ _token = newToken;
29
+ [self initPinwheelWrapperVC];
30
+ }
31
+ }
32
+
33
+ - (void)layoutSubviews
34
+ {
35
+ [super layoutSubviews];
36
+ self.pinwheelWrapperVC.view.frame = self.bounds;
37
+ }
38
+
39
+ - (void)onEventWithName:(NSString *)name event:(NSDictionary<NSString *, id> *)event {
40
+ NSLog(@"%@", name);
41
+ NSDictionary *dataToSend = @{@"name": name, @"payload": event};
42
+ [RNTPinwheelEvents.sharedInstance handlePinwheelEvent:dataToSend];
43
+ }
44
+
45
+ - (void)onExit:(NSDictionary<NSString *, id> *)error {
46
+ NSLog(@"%@", error);
47
+ }
48
+
49
+ - (void)onSuccess:(NSDictionary<NSString *, id> *)result {
50
+ NSLog(@"%@", result);
51
+ }
52
+
53
+ - (void)onLogin:(NSDictionary<NSString *, id> *)result {
54
+ NSLog(@"%@", result);
55
+ }
56
+
57
+ - (void)onLoginAttempt:(NSDictionary<NSString *, id> *)result {
58
+ NSLog(@"%@", result);
59
+ }
60
+
61
+ - (void)onError:(NSDictionary<NSString *, id> *)error {
62
+ NSLog(@"%@", error);
63
+ }
64
+
65
+ @end
package/package.json CHANGED
@@ -1,13 +1,10 @@
1
1
  {
2
2
  "name": "@pinwheel/react-native-pinwheel",
3
- "version": "2.3.17",
3
+ "version": "2.5.0-alpha",
4
4
  "type": "module",
5
5
  "description": "Pinwheel React Native SDK",
6
- "main": "lib/index.js",
7
- "types": "lib/index.d.ts",
8
- "files": [
9
- "lib/**/*"
10
- ],
6
+ "main": "index.js",
7
+ "types": "index.d.ts",
11
8
  "scripts": {
12
9
  "build": "tsc",
13
10
  "bump-pkg-version": "./scripts/bump-pkg-version.sh",
@@ -17,20 +14,10 @@
17
14
  "license": "MIT",
18
15
  "peerDependencies": {
19
16
  "react": "^16.13.1 || ^17 || ^18",
20
- "react-native": "*",
21
- "react-native-webview": "^10.10.0 || ^11.0.0"
17
+ "react-native": "*"
22
18
  },
23
19
  "devDependencies": {
24
- "@types/react-native": "^0.63.29",
25
- "react-native-webview": "^11.0.0",
20
+ "@types/react-native": "^0.72.2",
26
21
  "typescript": "^4.0.3"
27
- },
28
- "overrides": {
29
- "react-native": {
30
- "hermes-engine": "0.11.0"
31
- },
32
- "@react-native-community/cli-tools": {
33
- "shell-quote": "^1.7.4"
34
- }
35
22
  }
36
23
  }
@@ -0,0 +1,6 @@
1
+ export interface RNTPinwheelProps {
2
+ token: string;
3
+ style: any;
4
+ onEvent: (event: any) => void;
5
+ }
6
+ export declare const RNTPinwheel: import("react-native").HostComponent<RNTPinwheelProps>;
@@ -0,0 +1,2 @@
1
+ import { requireNativeComponent } from 'react-native';
2
+ export const RNTPinwheel = requireNativeComponent('RNTPinwheel');
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import { RNTPinwheelProps } from './pinwheel-view';
3
+ declare const RNTPinwheelView: (props: RNTPinwheelProps) => React.JSX.Element;
4
+ export default RNTPinwheelView;
@@ -0,0 +1,28 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { UIManager, findNodeHandle, NativeEventEmitter, NativeModules } from 'react-native';
3
+ import { RNTPinwheel } from './pinwheel-view';
4
+ const createFragment = (viewId) => {
5
+ UIManager.dispatchViewManagerCommand(viewId,
6
+ // we are calling the 'create' command
7
+ // @ts-ignore
8
+ UIManager.RNTPinwheel.Commands.create.toString(), [viewId]);
9
+ };
10
+ const RNTPinwheelView = (props) => {
11
+ const ref = useRef(null);
12
+ useEffect(() => {
13
+ setTimeout(() => {
14
+ const viewId = findNodeHandle(ref.current);
15
+ if (viewId) {
16
+ createFragment(viewId);
17
+ }
18
+ // events
19
+ const { RNTPinwheelEvents } = NativeModules;
20
+ const eventEmitter = new NativeEventEmitter(RNTPinwheelEvents);
21
+ const eventListener = eventEmitter.addListener('PINWHEEL_EVENT', (event) => {
22
+ props.onEvent(event);
23
+ });
24
+ }, 10);
25
+ }, []);
26
+ return <RNTPinwheel {...props} onEvent={(event) => { console.log `rawbee: ${JSON.stringify(event)}`; }} ref={ref}/>;
27
+ };
28
+ export default RNTPinwheelView;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import { RNTPinwheelProps } from './pinwheel-view';
3
+ declare const RNTPinwheelView: (props: RNTPinwheelProps) => React.JSX.Element;
4
+ export default RNTPinwheelView;
@@ -0,0 +1,17 @@
1
+ import React, { useEffect } from 'react';
2
+ import { NativeEventEmitter, NativeModules } from 'react-native';
3
+ import { RNTPinwheel } from './pinwheel-view';
4
+ const RNTPinwheelView = (props) => {
5
+ useEffect(() => {
6
+ const { RNTPinwheelEvents } = NativeModules;
7
+ const eventEmitter = new NativeEventEmitter(RNTPinwheelEvents);
8
+ const eventListener = eventEmitter.addListener('PINWHEEL_EVENT', (event) => {
9
+ props.onEvent(event);
10
+ });
11
+ return () => {
12
+ eventListener.remove();
13
+ };
14
+ }, []);
15
+ return <RNTPinwheel {...props}/>;
16
+ };
17
+ export default RNTPinwheelView;
package/lib/index.js DELETED
@@ -1,122 +0,0 @@
1
- import React from 'react';
2
- import { WebView } from 'react-native-webview';
3
- import { Linking, Platform, SafeAreaView, StyleSheet } from 'react-native';
4
- import { LINK_PAGE_URL, PINWHEEL_DOMAIN, VERSION } from './constants';
5
- const styles = StyleSheet.create({
6
- container: {
7
- flex: 1,
8
- },
9
- });
10
- export const PINWHEEL_MESSAGE_TYPES = {
11
- PINWHEEL_EXIT: 'PINWHEEL_EXIT',
12
- PINWHEEL_MODAL_CLOSE: 'PINWHEEL_MODAL_CLOSE',
13
- PINWHEEL_LOAD_COMPLETE: 'PINWHEEL_LOAD_COMPLETE',
14
- PINWHEEL_SUCCESS: 'PINWHEEL_SUCCESS',
15
- PINWHEEL_EVENT: 'PINWHEEL_EVENT',
16
- };
17
- export default ({ linkToken, onLogin, onLoginAttempt, onSuccess, onError, onExit, onEvent }) => {
18
- const handleEvent = (event) => {
19
- if (!event) {
20
- // first event is always an empty string
21
- return;
22
- }
23
- let eventData;
24
- try {
25
- eventData = JSON.parse(event.nativeEvent.data);
26
- }
27
- catch (_error) {
28
- let error = _error;
29
- console.error(error);
30
- onExit && onExit(error);
31
- onError && onError(error);
32
- onEvent && onEvent('error', error);
33
- return;
34
- }
35
- const { type, eventName, payload } = eventData;
36
- if (type === 'PINWHEEL_EVENT') {
37
- onEvent && onEvent(eventName, payload);
38
- switch (eventName) {
39
- case 'exit':
40
- onExit && onExit(payload);
41
- break;
42
- case 'success':
43
- onSuccess && onSuccess(payload);
44
- break;
45
- case 'login':
46
- onLogin && onLogin(payload);
47
- break;
48
- case 'login_attempt':
49
- onLoginAttempt && onLoginAttempt(payload);
50
- break;
51
- case 'error':
52
- onError && onError(payload);
53
- break;
54
- default:
55
- }
56
- }
57
- };
58
- const now = Date.now();
59
- const [major, minor, patch] = VERSION.split('.').map(x => Number(x));
60
- const runFirst = `
61
- const uuidKey = 'pinwheel-uuid';
62
- const localStorage = window.localStorage;
63
- let uuid = localStorage.getItem(uuidKey);
64
- if(!uuid) {
65
- uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
66
- var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
67
- return v.toString(16);
68
- });
69
- localStorage.setItem(uuidKey, uuid);
70
- }
71
- try {
72
- window.addEventListener('message', event => {
73
- window.ReactNativeWebView.postMessage(JSON.stringify(event.data))
74
- });
75
- window.postMessage(
76
- {
77
- type: 'PINWHEEL_INIT',
78
- payload: {
79
- platform: "${Platform.OS}",
80
- sdk: 'react native',
81
- version: {
82
- major: ${major},
83
- minor: ${minor},
84
- patch: ${patch}
85
- },
86
- initializationOptions: {
87
- hasOnSuccess: ${!!onSuccess},
88
- hasOnEvent: ${!!onEvent},
89
- hasOnExit: ${!!onExit},
90
- hasOnError: ${!!onError},
91
- hasOnLogin: ${!!onLogin},
92
- },
93
- linkToken: '${linkToken}',
94
- uniqueUserId: uuid,
95
- initializationTimestamp: ${now}
96
- }
97
- }
98
- );
99
- } catch (err) {
100
- console.error(err);
101
- }
102
- true;
103
- `;
104
- return (<SafeAreaView style={styles.container}>
105
- <WebView source={{ uri: LINK_PAGE_URL }} onMessage={handleEvent} injectedJavaScript={runFirst} onShouldStartLoadWithRequest={(request) => {
106
- const targetURL = request.url;
107
- const isLinkPage = targetURL.includes(PINWHEEL_DOMAIN);
108
- if (!isLinkPage) {
109
- Linking.canOpenURL(targetURL).then(supported => {
110
- if (supported) {
111
- Linking.openURL(targetURL).then(() => { });
112
- }
113
- else {
114
- console.warn('Don\'t know how to open URL: ' + targetURL);
115
- }
116
- return false;
117
- }).catch(err => console.error('An error occurred ', err));
118
- }
119
- return isLinkPage;
120
- }}/>
121
- </SafeAreaView>);
122
- };