@codeleap/mobile 3.21.5 → 3.21.6
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/package.json +1 -1
- package/src/components/InputBase/styles.ts +10 -3
- package/src/utils/NotificationManager/index.ts +231 -0
- package/src/utils/NotificationManager/types.ts +25 -0
- package/src/utils/Subscription.ts +73 -0
- package/src/utils/{notifications.ts → deprecated/notifications.ts} +7 -0
- package/src/utils/index.ts +2 -1
package/package.json
CHANGED
|
@@ -37,14 +37,19 @@ const getIconStyles = (obj, state) => {
|
|
|
37
37
|
state.hasError && obj['icon:error'],
|
|
38
38
|
state.disabled && obj['icon:disabled']
|
|
39
39
|
],
|
|
40
|
+
'icon:disabled': [
|
|
41
|
+
state.disabled && obj['icon:disabled']
|
|
42
|
+
],
|
|
40
43
|
touchableWrapper: [
|
|
41
44
|
obj.touchableWrapper,
|
|
42
45
|
state.focused && obj['touchableWrapper:focus'],
|
|
43
46
|
state.hasError && obj['touchableWrapper:error'],
|
|
44
47
|
state.disabled && obj['touchableWrapper:disabled']
|
|
45
48
|
],
|
|
49
|
+
'touchableWrapper:disabled': [
|
|
50
|
+
state.disabled && obj['touchableWrapper:disabled']
|
|
51
|
+
]
|
|
46
52
|
}
|
|
47
|
-
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
export const useInputBaseStyles = (props: InputBaseProps) => {
|
|
@@ -71,12 +76,14 @@ export const useInputBaseStyles = (props: InputBaseProps) => {
|
|
|
71
76
|
|
|
72
77
|
const leftIconStyles = [
|
|
73
78
|
generalIconStyles,
|
|
74
|
-
|
|
79
|
+
// @ts-ignore
|
|
80
|
+
getIconStyles(_leftIconStyles, { hasError, disabled: disabled || props?.leftIcon?.disabled, focused })
|
|
75
81
|
]
|
|
76
82
|
|
|
77
83
|
const rightIconStyles = [
|
|
78
84
|
generalIconStyles,
|
|
79
|
-
|
|
85
|
+
// @ts-ignore
|
|
86
|
+
getIconStyles(_rightIconStyles, { hasError, disabled: disabled || props?.right?.disabled, focused })
|
|
80
87
|
]
|
|
81
88
|
|
|
82
89
|
const labelStyle = [
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { AnyFunction, silentLogger } from '@codeleap/common' // @ts-ignore
|
|
2
|
+
import messaging from '@react-native-firebase/messaging'
|
|
3
|
+
import { Subscriber, Subscription } from '../Subscription'
|
|
4
|
+
import { Message, NotificationInitializeCallback, NotificationManagerOptions, NotificationType, TNotification } from './types'
|
|
5
|
+
|
|
6
|
+
export * from './types'
|
|
7
|
+
|
|
8
|
+
const MODULE = 'NotificationManager'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Class responsible for the notification system
|
|
12
|
+
*/
|
|
13
|
+
export class NotificationManager<N extends object = Message, E extends string = string> {
|
|
14
|
+
public parser: NotificationManagerOptions<N>['parser'] = (message: Message) => message as N
|
|
15
|
+
|
|
16
|
+
public currentOptions: NotificationManagerOptions<N> = {
|
|
17
|
+
handleInitialNotification: true,
|
|
18
|
+
debug: false,
|
|
19
|
+
slackDebug: false,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public currentToken = null
|
|
23
|
+
|
|
24
|
+
private registeredUnsubscribers: Record<string, AnyFunction> = {}
|
|
25
|
+
|
|
26
|
+
private initialized = false
|
|
27
|
+
|
|
28
|
+
public events = new Subscription<TNotification<N>, E>()
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
private _logger = silentLogger,
|
|
32
|
+
options: NotificationManagerOptions<N> = {}
|
|
33
|
+
) {
|
|
34
|
+
if (typeof options?.parser == 'function') {
|
|
35
|
+
this.parser = options?.parser
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.currentOptions = {
|
|
39
|
+
...this.currentOptions,
|
|
40
|
+
...options
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private invoke(args: {
|
|
45
|
+
data: Message,
|
|
46
|
+
type: NotificationType,
|
|
47
|
+
}) {
|
|
48
|
+
this.log('Invoke this events:', this.events.getSubscribersKeys())
|
|
49
|
+
|
|
50
|
+
this.events.invoke({
|
|
51
|
+
data: this.parser(args?.data),
|
|
52
|
+
type: args?.type
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public log(description: string, data: any = {}) {
|
|
57
|
+
if (!this._logger) return
|
|
58
|
+
|
|
59
|
+
if (this.currentOptions.debug) {
|
|
60
|
+
this._logger.log(description, data, MODULE)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (this.currentOptions.slackDebug) {
|
|
64
|
+
this._logger.slack.echo(description, data, MODULE, {
|
|
65
|
+
'include': ['version'],
|
|
66
|
+
'sendIn': ['release', 'debug']
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Checks if you are authorized for notifications and returns the result
|
|
73
|
+
*
|
|
74
|
+
* @return hasAuthorization (boolean)
|
|
75
|
+
*/
|
|
76
|
+
public async getHasAuthorization() {
|
|
77
|
+
const authStatus = await messaging().hasPermission()
|
|
78
|
+
|
|
79
|
+
const hasAuthorization =
|
|
80
|
+
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
|
|
81
|
+
authStatus === messaging.AuthorizationStatus.PROVISIONAL
|
|
82
|
+
|
|
83
|
+
return hasAuthorization
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Gets and returns the device token
|
|
88
|
+
*
|
|
89
|
+
* @return token (string) or null if an error occurs
|
|
90
|
+
*/
|
|
91
|
+
public async getToken() {
|
|
92
|
+
try {
|
|
93
|
+
const token = await messaging().getToken()
|
|
94
|
+
|
|
95
|
+
this.log('Get token', { token })
|
|
96
|
+
|
|
97
|
+
this.currentToken = token
|
|
98
|
+
|
|
99
|
+
return token
|
|
100
|
+
} catch (err) {
|
|
101
|
+
this.log('Get token error', err)
|
|
102
|
+
return null
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public onTokenRefresh(cb: (token: string) => void) {
|
|
107
|
+
const unsubscribe = messaging().onTokenRefresh(newToken => {
|
|
108
|
+
this.log('Refreshed token', { newToken })
|
|
109
|
+
|
|
110
|
+
this.currentToken = newToken
|
|
111
|
+
|
|
112
|
+
cb(newToken)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
return unsubscribe
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public async invokeForInitialNotification() {
|
|
119
|
+
if (this.initialized) return
|
|
120
|
+
|
|
121
|
+
const initialNotification = await messaging().getInitialNotification()
|
|
122
|
+
|
|
123
|
+
this.log('Initial Notification', initialNotification)
|
|
124
|
+
|
|
125
|
+
if (!!initialNotification && this.currentOptions.handleInitialNotification) {
|
|
126
|
+
this.invoke({
|
|
127
|
+
data: initialNotification,
|
|
128
|
+
type: 'initial'
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public onBackgroundMessage() {
|
|
134
|
+
messaging().setBackgroundMessageHandler(async remoteMessage => {
|
|
135
|
+
this.log('Notification in background:', remoteMessage)
|
|
136
|
+
|
|
137
|
+
this.invoke({
|
|
138
|
+
data: remoteMessage,
|
|
139
|
+
type: 'background'
|
|
140
|
+
})
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
return () => messaging().setBackgroundMessageHandler(() => null)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Responsible for initializing all notification services: token refresh, background, foreground, press and initial notification
|
|
148
|
+
*
|
|
149
|
+
* @param {function} callback Callback that is executed when the services are initialized, returning the device token
|
|
150
|
+
*/
|
|
151
|
+
public async initialize(callback: NotificationInitializeCallback) {
|
|
152
|
+
this.log('Initialize', this.currentOptions)
|
|
153
|
+
|
|
154
|
+
this.unsubscribe()
|
|
155
|
+
|
|
156
|
+
const token = await this.getToken()
|
|
157
|
+
|
|
158
|
+
callback(token)
|
|
159
|
+
|
|
160
|
+
this.invokeForInitialNotification()
|
|
161
|
+
|
|
162
|
+
const unsubscribeOnNotificationOpenedApp = messaging().onNotificationOpenedApp(remoteMessage => {
|
|
163
|
+
this.log('Notification pressed:', remoteMessage)
|
|
164
|
+
|
|
165
|
+
this.invoke({
|
|
166
|
+
data: remoteMessage,
|
|
167
|
+
type: 'press'
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
this.registeredUnsubscribers['openApp'] = unsubscribeOnNotificationOpenedApp
|
|
172
|
+
|
|
173
|
+
const unsubscribeOnBackgroundMessage = this.onBackgroundMessage()
|
|
174
|
+
|
|
175
|
+
this.registeredUnsubscribers['background'] = unsubscribeOnBackgroundMessage
|
|
176
|
+
|
|
177
|
+
const unsubscribeOnMessage = messaging().onMessage(async remoteMessage => {
|
|
178
|
+
this.log('Notification in foreground', remoteMessage)
|
|
179
|
+
|
|
180
|
+
this.invoke({
|
|
181
|
+
data: remoteMessage,
|
|
182
|
+
type: 'foreground'
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
this.registeredUnsubscribers['foreground'] = unsubscribeOnMessage
|
|
187
|
+
|
|
188
|
+
const unsubscribeOnTokenRefresh = this.onTokenRefresh(callback)
|
|
189
|
+
|
|
190
|
+
this.registeredUnsubscribers['refreshToken'] = unsubscribeOnTokenRefresh
|
|
191
|
+
|
|
192
|
+
this.initialized = true
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public async unsubscribe() {
|
|
196
|
+
this.log('Unsubscribe handlers', this.registeredUnsubscribers)
|
|
197
|
+
|
|
198
|
+
for (const unsubscribeKey in this.registeredUnsubscribers) {
|
|
199
|
+
this.registeredUnsubscribers[unsubscribeKey]()
|
|
200
|
+
delete this.registeredUnsubscribers[unsubscribeKey]
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Unsubscribe all services that have been started
|
|
206
|
+
*
|
|
207
|
+
* @param {function} callback Callback that is executed when the services are deinitialized
|
|
208
|
+
*/
|
|
209
|
+
public async deinitialize(callback: AnyFunction = null) {
|
|
210
|
+
if (!this.initialized) return
|
|
211
|
+
|
|
212
|
+
this.log('Deinitialize')
|
|
213
|
+
|
|
214
|
+
this.unsubscribe()
|
|
215
|
+
|
|
216
|
+
if (typeof callback == 'function') {
|
|
217
|
+
callback()
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Registers an event that will be called by all notification services that have been started
|
|
223
|
+
*
|
|
224
|
+
* @param {string} eventName Event name
|
|
225
|
+
* @param {string} handler Function that will be performed
|
|
226
|
+
* @return unsubscribe event (function)
|
|
227
|
+
*/
|
|
228
|
+
public registerEvent(eventName: E, handler: Subscriber<TNotification<N>>) {
|
|
229
|
+
return this.events.subscribe(eventName, handler)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import { FirebaseMessagingTypes } from '@react-native-firebase/messaging'
|
|
3
|
+
import { FunctionType } from '@codeleap/common'
|
|
4
|
+
|
|
5
|
+
export type Message = FirebaseMessagingTypes.RemoteMessage
|
|
6
|
+
|
|
7
|
+
export type NotificationType = 'foreground' | 'background' | 'press' | 'initial'
|
|
8
|
+
|
|
9
|
+
export type NotificationHandler<N extends object = Message> = FunctionType<[notification: N, type: NotificationType], void>
|
|
10
|
+
|
|
11
|
+
export type TNotification<N extends object = Message> = {
|
|
12
|
+
data: N
|
|
13
|
+
type: NotificationType
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type NotificationInitializeCallback = (
|
|
17
|
+
deviceToken: string,
|
|
18
|
+
) => void
|
|
19
|
+
|
|
20
|
+
export type NotificationManagerOptions<N extends object = Message> = {
|
|
21
|
+
debug?: boolean
|
|
22
|
+
slackDebug?: boolean
|
|
23
|
+
handleInitialNotification?: boolean,
|
|
24
|
+
parser?: (message: Message) => N
|
|
25
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
export type Subscriber<T> = (e: T) => any
|
|
4
|
+
|
|
5
|
+
type SubscriptionRecord = Record<string, Subscription<any>>
|
|
6
|
+
|
|
7
|
+
type MultiSubscriptor<T extends SubscriptionRecord> = <K extends keyof T>(
|
|
8
|
+
e: K,
|
|
9
|
+
key: string,
|
|
10
|
+
cb: Subscriber<T[K] extends Subscription<infer ET> ? ET : never>
|
|
11
|
+
) => () => void
|
|
12
|
+
|
|
13
|
+
class Subscription<T, K extends string = string> {
|
|
14
|
+
public subscribers: Record<K, Subscriber<T>> = {} as Record<K, Subscriber<T>>
|
|
15
|
+
|
|
16
|
+
private _history: T[] = []
|
|
17
|
+
|
|
18
|
+
get history(){
|
|
19
|
+
return Object.freeze(this._history)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
subscribe(key: K, cb: Subscriber<T>) {
|
|
23
|
+
this.subscribers[key] = cb
|
|
24
|
+
|
|
25
|
+
return () => {
|
|
26
|
+
delete this.subscribers[key]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getSubscriber(key: K) {
|
|
31
|
+
return this.subscribers[key]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
removerSubscriber(key: K) {
|
|
35
|
+
delete this.subscribers[key]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getSubscribersKeys() {
|
|
39
|
+
return Object.keys(this.subscribers)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
invoke(e: T) {
|
|
43
|
+
this._history.push(e)
|
|
44
|
+
|
|
45
|
+
for (const subscriber in this.subscribers) {
|
|
46
|
+
this.subscribers[subscriber](e)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
removeAllListeners(){
|
|
51
|
+
this.subscribers = {} as Record<K, Subscriber<T>>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static createSubscriptor<SR extends SubscriptionRecord>(events: SR): MultiSubscriptor<SR> {
|
|
55
|
+
return (e, key, cb) => {
|
|
56
|
+
return events[e]!.subscribe(key, cb)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function useSubscriptionHistory<T>(subscription: Subscription<T>){
|
|
62
|
+
const [state, setState] = React.useState(subscription.history)
|
|
63
|
+
|
|
64
|
+
React.useEffect(() => {
|
|
65
|
+
return subscription.subscribe('subscription-history', e => {
|
|
66
|
+
setState([...state, e])
|
|
67
|
+
})
|
|
68
|
+
}, [])
|
|
69
|
+
|
|
70
|
+
return state
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { Subscription, useSubscriptionHistory }
|
|
@@ -17,6 +17,13 @@ export type HandleNotificationParam = {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export type NotificationStateChangeListener = FunctionType<[isInitialized: boolean, token?: string], any>
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Class responsible for the notification system
|
|
23
|
+
*
|
|
24
|
+
* @deprecated Use the most updated version
|
|
25
|
+
* @note check the documentation to make the migration
|
|
26
|
+
*/
|
|
20
27
|
export class NotificationManager {
|
|
21
28
|
|
|
22
29
|
stateChangeListeners:NotificationStateChangeListener[] = []
|
package/src/utils/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './OSAlert'
|
|
2
2
|
export * from './hooks'
|
|
3
3
|
export * from './misc'
|
|
4
|
-
export * from './
|
|
4
|
+
export * from './NotificationManager'
|
|
5
5
|
export * from './ModalManager'
|
|
6
6
|
import * as Permissions from './PermissionManager'
|
|
7
7
|
|
|
@@ -10,3 +10,4 @@ export * from './KeyboardAware'
|
|
|
10
10
|
export * from './input'
|
|
11
11
|
export * from './theme'
|
|
12
12
|
export * from './locale'
|
|
13
|
+
export * from './Subscription'
|