@react-native-kakao/user 3.1.0 → 3.2.0

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.
@@ -5,8 +5,11 @@ import com.facebook.react.bridge.Promise
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.bridge.ReactMethod
7
7
  import com.facebook.react.bridge.ReadableArray
8
+ import com.facebook.react.bridge.ReadableMap
8
9
  import com.kakao.sdk.auth.AuthApiClient
10
+ import com.kakao.sdk.auth.AuthCodeClient
9
11
  import com.kakao.sdk.auth.model.OAuthToken
12
+ import com.kakao.sdk.auth.model.Prompt
10
13
  import com.kakao.sdk.auth.model.Prompt.CERT
11
14
  import com.kakao.sdk.auth.model.Prompt.CREATE
12
15
  import com.kakao.sdk.auth.model.Prompt.LOGIN
@@ -14,7 +17,15 @@ import com.kakao.sdk.auth.model.Prompt.SELECT_ACCOUNT
14
17
  import com.kakao.sdk.common.model.ClientError
15
18
  import com.kakao.sdk.common.model.ClientErrorCause
16
19
  import com.kakao.sdk.user.UserApiClient
20
+ import com.kakao.sdk.user.model.AccountLoginParams
21
+ import com.kakao.sdk.user.model.AgeRange
22
+ import com.kakao.sdk.user.model.BirthdayType
23
+ import com.kakao.sdk.user.model.Gender
24
+ import com.kakao.sdk.user.model.LoginUiMode
25
+ import com.kakao.sdk.user.model.Scope
26
+ import com.kakao.sdk.user.model.UserShippingAddresses
17
27
  import net.mjstudio.rnkakao.core.util.RNCKakaoResponseNotFoundException
28
+ import net.mjstudio.rnkakao.core.util.RNCKakaoUnsupportedPlatformException
18
29
  import net.mjstudio.rnkakao.core.util.RNCKakaoUtil
19
30
  import net.mjstudio.rnkakao.core.util.argArr
20
31
  import net.mjstudio.rnkakao.core.util.argMap
@@ -27,9 +38,12 @@ import net.mjstudio.rnkakao.core.util.putD
27
38
  import net.mjstudio.rnkakao.core.util.putI
28
39
  import net.mjstudio.rnkakao.core.util.putL
29
40
  import net.mjstudio.rnkakao.core.util.rejectWith
41
+ import net.mjstudio.rnkakao.core.util.toStringMap
30
42
  import net.mjstudio.rnkakao.core.util.unix
31
43
  import java.util.Date
32
44
 
45
+ private const val MILLISECONDS_PER_SECOND = 1000.0
46
+
33
47
  class RNCKakaoUserModule internal constructor(
34
48
  context: ReactApplicationContext,
35
49
  ) : NativeKakaoUserSpec(context) {
@@ -38,8 +52,12 @@ class RNCKakaoUserModule internal constructor(
38
52
  serviceTerms: ReadableArray?,
39
53
  prompts: ReadableArray?,
40
54
  useKakaoAccountLogin: Boolean,
55
+ iosLaunchMethod: String,
41
56
  scopes: ReadableArray?,
42
57
  nonce: String?,
58
+ loginHint: String?,
59
+ channelPublicIds: ReadableArray?,
60
+ androidRequestCode: Double?,
43
61
  promise: Promise,
44
62
  ) = onMain {
45
63
  val context =
@@ -47,63 +65,18 @@ class RNCKakaoUserModule internal constructor(
47
65
  promise.rejectWith(ActivityNotFoundException())
48
66
  return@onMain
49
67
  }
50
- val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
51
- if (error != null) {
52
- promise.rejectWith(error)
53
- } else if (token == null) {
54
- promise.rejectWith(RNCKakaoResponseNotFoundException("token"))
55
- } else {
56
- promise.resolve(
57
- argMap().apply {
58
- putString("accessToken", token.accessToken)
59
- putString("refreshToken", token.refreshToken)
60
- putString("tokenType", null)
61
- putString("idToken", token.idToken)
62
- putDouble(
63
- "accessTokenExpiresAt",
64
- token.accessTokenExpiresAt.unix.toDouble(),
65
- )
66
- putDouble(
67
- "refreshTokenExpiresAt",
68
- token.refreshTokenExpiresAt.unix.toDouble(),
69
- )
70
- putDouble(
71
- "accessTokenExpiresIn",
72
- RNCKakaoUtil.diffSec(token.accessTokenExpiresAt, Date()).toDouble(),
73
- )
74
- putDouble(
75
- "refreshTokenExpiresIn",
76
- RNCKakaoUtil.diffSec(token.refreshTokenExpiresAt, Date()).toDouble(),
77
- )
78
- putArray(
79
- "scopes",
80
- argArr().apply {
81
- pushStringList(token.scopes ?: listOf())
82
- },
83
- )
84
- },
85
- )
86
- }
87
- }
68
+ val callback = tokenCallback(promise)
88
69
  val requestedServiceTerms = serviceTerms?.filterIsInstance<String>()?.ifEmpty { null }
89
- val requestedPrompts =
90
- prompts
91
- ?.filterIsInstance<String>()
92
- ?.mapNotNull {
93
- when (it) {
94
- "Login" -> LOGIN
95
- "Create" -> CREATE
96
- "Cert" -> CERT
97
- "SelectAccount" -> SELECT_ACCOUNT
98
- else -> null
99
- }
100
- }?.ifEmpty { null }
70
+ val requestedChannelPublicIds = channelPublicIds?.filterIsInstance<String>()?.ifEmpty { null }
71
+ val requestedPrompts = loginPrompts(prompts)
101
72
  val accountLogin = {
102
73
  UserApiClient.instance.loginWithKakaoAccount(
103
74
  context,
104
75
  prompts = requestedPrompts,
76
+ loginHint = loginHint,
105
77
  nonce = nonce,
106
78
  serviceTerms = requestedServiceTerms,
79
+ channelPublicIds = requestedChannelPublicIds,
107
80
  callback = callback,
108
81
  )
109
82
  }
@@ -133,8 +106,10 @@ class RNCKakaoUserModule internal constructor(
133
106
 
134
107
  UserApiClient.instance.loginWithKakaoTalk(
135
108
  context,
109
+ requestCode = androidRequestCode?.toInt() ?: AuthCodeClient.DEFAULT_REQUEST_CODE,
136
110
  nonce = nonce,
137
111
  serviceTerms = requestedServiceTerms,
112
+ channelPublicIds = requestedChannelPublicIds,
138
113
  callback = talkCallback,
139
114
  )
140
115
  } else {
@@ -142,12 +117,92 @@ class RNCKakaoUserModule internal constructor(
142
117
  }
143
118
  }
144
119
 
120
+ @ReactMethod
121
+ override fun loginWithKakao(
122
+ uiMode: String,
123
+ orientation: String,
124
+ launchMethod: String,
125
+ prompts: ReadableArray,
126
+ loginHint: String?,
127
+ nonce: String?,
128
+ channelPublicIds: ReadableArray?,
129
+ serviceTerms: ReadableArray?,
130
+ promise: Promise,
131
+ ) = onMain {
132
+ val context =
133
+ reactApplicationContext.currentActivity ?: run {
134
+ promise.rejectWith(ActivityNotFoundException())
135
+ return@onMain
136
+ }
137
+ UserApiClient.instance.loginWithKakao(
138
+ context,
139
+ uiMode = LoginUiMode.entries.firstOrNull { it.name.equals(uiMode, ignoreCase = true) } ?: LoginUiMode.AUTO,
140
+ accountParams = AccountLoginParams(prompts = loginPrompts(prompts), loginHint = loginHint),
141
+ nonce = nonce,
142
+ channelPublicIds = channelPublicIds?.filterIsInstance<String>()?.ifEmpty { null },
143
+ serviceTerms = serviceTerms?.filterIsInstance<String>()?.ifEmpty { null },
144
+ callback = tokenCallback(promise),
145
+ )
146
+ }
147
+
148
+ @ReactMethod
149
+ override fun issueAccessTokenWithCode(
150
+ code: String,
151
+ codeVerifier: String?,
152
+ redirectUri: String?,
153
+ promise: Promise,
154
+ ) {
155
+ promise.rejectWith(RNCKakaoUnsupportedPlatformException("issueAccessTokenWithCode", "iOS and web"))
156
+ }
157
+
158
+ @ReactMethod
159
+ override fun refreshToken(
160
+ token: ReadableMap?,
161
+ iosLoggingEnabled: Boolean?,
162
+ promise: Promise,
163
+ ) = onMain {
164
+ try {
165
+ val oldToken =
166
+ token?.let {
167
+ OAuthToken(
168
+ accessToken = requireNotNull(it.getString("accessToken")),
169
+ accessTokenExpiresAt = Date((it.getDouble("accessTokenExpiresAt") * MILLISECONDS_PER_SECOND).toLong()),
170
+ refreshToken = requireNotNull(it.getString("refreshToken")),
171
+ refreshTokenExpiresAt = Date((it.getDouble("refreshTokenExpiresAt") * MILLISECONDS_PER_SECOND).toLong()),
172
+ idToken = it.getString("idToken"),
173
+ scopes = it.getArray("scopes")?.filterIsInstance<String>(),
174
+ )
175
+ }
176
+ if (oldToken == null) {
177
+ AuthApiClient.instance.refreshToken(callback = tokenCallback(promise))
178
+ } else {
179
+ AuthApiClient.instance.refreshToken(oldToken = oldToken, callback = tokenCallback(promise))
180
+ }
181
+ } catch (error: Exception) {
182
+ promise.rejectWith(error)
183
+ }
184
+ }
185
+
145
186
  @ReactMethod
146
187
  override fun isKakaoTalkLoginAvailable(promise: Promise) =
147
188
  onMain {
148
189
  promise.resolve(UserApiClient.instance.isKakaoTalkLoginAvailable(reactApplicationContext))
149
190
  }
150
191
 
192
+ @ReactMethod
193
+ override fun signup(
194
+ properties: ReadableMap?,
195
+ promise: Promise,
196
+ ) = onMain {
197
+ UserApiClient.instance.signup(properties?.toStringMap()) { error ->
198
+ if (error != null) {
199
+ promise.rejectWith(error)
200
+ } else {
201
+ promise.resolve(null)
202
+ }
203
+ }
204
+ }
205
+
151
206
  @ReactMethod
152
207
  override fun logout(promise: Promise) =
153
208
  onMain {
@@ -155,7 +210,7 @@ class RNCKakaoUserModule internal constructor(
155
210
  if (it != null) {
156
211
  promise.rejectWith(it)
157
212
  } else {
158
- promise.resolve(42)
213
+ promise.resolve(null)
159
214
  }
160
215
  }
161
216
  }
@@ -167,7 +222,7 @@ class RNCKakaoUserModule internal constructor(
167
222
  if (it != null) {
168
223
  promise.rejectWith(it)
169
224
  } else {
170
- promise.resolve(42)
225
+ promise.resolve(null)
171
226
  }
172
227
  }
173
228
  }
@@ -188,34 +243,24 @@ class RNCKakaoUserModule internal constructor(
188
243
  }
189
244
  }
190
245
 
246
+ @ReactMethod
247
+ override fun hasToken(promise: Promise) =
248
+ onMain {
249
+ promise.resolve(AuthApiClient.instance.hasToken())
250
+ }
251
+
191
252
  @ReactMethod
192
253
  override fun scopes(
193
254
  scopes: ReadableArray?,
194
255
  promise: Promise,
195
256
  ) = onMain {
196
- UserApiClient.instance.scopes { scopeInfo, error ->
257
+ UserApiClient.instance.scopes(scopes = scopes?.filterIsInstance<String>()?.ifEmpty { null }) { scopeInfo, error ->
197
258
  if (error != null) {
198
259
  promise.rejectWith(error)
199
- } else if (scopeInfo?.scopes == null) {
260
+ } else if (scopeInfo == null) {
200
261
  promise.rejectWith(RNCKakaoResponseNotFoundException("scopes"))
201
262
  } else {
202
- promise.resolve(
203
- argArr().also { arr ->
204
- scopeInfo.scopes!!.forEach { scope ->
205
- arr.pushMap(
206
- argMap().also { map ->
207
- map.putString("id", scope.id)
208
- map.putString("displayName", scope.displayName)
209
- map.putString("type", scope.type.name)
210
- map.putBoolean("using", scope.using)
211
- map.putB("delegated", scope.delegated)
212
- map.putBoolean("agreed", scope.agreed)
213
- map.putB("revocable", scope.revocable)
214
- },
215
- )
216
- }
217
- },
218
- )
263
+ promise.resolve(mapScopes(scopeInfo.scopes))
219
264
  }
220
265
  }
221
266
  }
@@ -233,161 +278,264 @@ class RNCKakaoUserModule internal constructor(
233
278
  } else if (scopeInfo == null) {
234
279
  promise.rejectWith(RNCKakaoResponseNotFoundException("scopeInfo"))
235
280
  } else {
236
- promise.resolve(42)
281
+ promise.resolve(mapScopes(scopeInfo.scopes))
237
282
  }
238
283
  }
239
284
  }
240
285
 
241
286
  @ReactMethod
242
- override fun serviceTerms(promise: Promise) =
243
- onMain {
244
- UserApiClient.instance.serviceTerms { serviceTerms, error ->
245
- if (error != null) {
246
- promise.rejectWith(error)
247
- } else if (serviceTerms?.serviceTerms == null) {
248
- promise.rejectWith(RNCKakaoResponseNotFoundException("serviceTerms"))
249
- } else {
250
- promise.resolve(
251
- argArr().pushMapList(
252
- serviceTerms.serviceTerms?.map { term ->
253
- argMap().apply {
254
- putString("tag", term.tag)
255
- putD("agreedAt", term.agreedAt?.unix?.toDouble())
256
- putBoolean("agreed", term.agreed)
257
- putBoolean("required", term.required)
258
- putBoolean("revocable", term.revocable)
287
+ override fun serviceTerms(
288
+ result: String?,
289
+ tags: ReadableArray?,
290
+ promise: Promise,
291
+ ) = onMain {
292
+ UserApiClient.instance.serviceTerms(
293
+ result = result,
294
+ tags = tags?.filterIsInstance<String>(),
295
+ ) { serviceTerms, error ->
296
+ if (error != null) {
297
+ promise.rejectWith(error)
298
+ } else if (serviceTerms == null) {
299
+ promise.rejectWith(RNCKakaoResponseNotFoundException("serviceTerms"))
300
+ } else {
301
+ promise.resolve(
302
+ argArr().pushMapList(
303
+ serviceTerms.serviceTerms?.map { term ->
304
+ argMap().apply {
305
+ putString("tag", term.tag)
306
+ term.agreedAt?.let { putDouble("agreedAt", it.unix.toDouble()) }
307
+ putBoolean("agreed", term.agreed)
308
+ putBoolean("required", term.required)
309
+ putBoolean("revocable", term.revocable)
310
+ term.referer?.let {
311
+ putString("agreedBy", if (it.name == "KAUTH" || it.name == "KAPI") it.name else "unknown")
259
312
  }
260
- } ?: listOf(),
261
- ),
262
- )
263
- }
313
+ }
314
+ } ?: listOf(),
315
+ ),
316
+ )
317
+ }
318
+ }
319
+ }
320
+
321
+ @ReactMethod
322
+ override fun revokeServiceTerms(
323
+ tags: ReadableArray,
324
+ promise: Promise,
325
+ ) = onMain {
326
+ UserApiClient.instance.revokeServiceTerms(tags.filterIsInstance<String>()) { response, error ->
327
+ if (error != null) {
328
+ promise.rejectWith(error)
329
+ } else if (response == null) {
330
+ promise.rejectWith(RNCKakaoResponseNotFoundException("revokeServiceTerms"))
331
+ } else {
332
+ promise.resolve(
333
+ argArr().pushMapList(
334
+ response.revokedServiceTerms?.map { term ->
335
+ argMap().apply {
336
+ putString("tag", term.tag)
337
+ putBoolean("agreed", term.agreed)
338
+ }
339
+ } ?: listOf(),
340
+ ),
341
+ )
342
+ }
343
+ }
344
+ }
345
+
346
+ @ReactMethod
347
+ override fun shippingAddresses(
348
+ addressId: Double?,
349
+ fromUpdatedAt: Double?,
350
+ pageSize: Double?,
351
+ promise: Promise,
352
+ ) = onMain {
353
+ val callback: (UserShippingAddresses?, Throwable?) -> Unit = { addrs, error ->
354
+ if (error != null) {
355
+ promise.rejectWith(error)
356
+ } else if (addrs == null) {
357
+ promise.rejectWith(RNCKakaoResponseNotFoundException("shippingAddresses"))
358
+ } else {
359
+ promise.resolve(
360
+ argMap().apply {
361
+ putD("userId", addrs.userId?.toDouble())
362
+ putB("needsAgreement", addrs.needsAgreement)
363
+ putArray(
364
+ "shippingAddresses",
365
+ argArr().apply {
366
+ pushMapList(
367
+ addrs.shippingAddresses?.map { addr ->
368
+ argMap().apply {
369
+ putDouble("id", addr.id.toDouble())
370
+ putString("name", addr.name)
371
+ putBoolean("isDefault", addr.isDefault)
372
+ putD("updatedAt", addr.updatedAt?.unix?.toDouble())
373
+ putString("type", addr.type?.name)
374
+ putString("baseAddress", addr.baseAddress)
375
+ putString("detailAddress", addr.detailAddress)
376
+ putString("receiverName", addr.receiverName)
377
+ putString("receiverPhoneNumber1", addr.receiverPhoneNumber1)
378
+ putString("receiverPhoneNumber2", addr.receiverPhoneNumber2)
379
+ putString("zoneNumber", addr.zoneNumber)
380
+ putString("zipCode", addr.zipCode)
381
+ }
382
+ } ?: listOf(),
383
+ )
384
+ },
385
+ )
386
+ },
387
+ )
264
388
  }
265
389
  }
390
+ if (addressId != null) {
391
+ UserApiClient.instance.shippingAddresses(addressId.toLong(), callback)
392
+ } else {
393
+ UserApiClient.instance.shippingAddresses(
394
+ fromUpdatedAt = fromUpdatedAt?.let { Date((it * 1000).toLong()) },
395
+ pageSize = pageSize?.toInt(),
396
+ callback = callback,
397
+ )
398
+ }
399
+ }
266
400
 
267
401
  @ReactMethod
268
- override fun shippingAddresses(promise: Promise) =
402
+ override fun selectShippingAddress(promise: Promise) =
269
403
  onMain {
270
- UserApiClient.instance.shippingAddresses { addrs, error ->
404
+ val context =
405
+ reactApplicationContext.currentActivity ?: run {
406
+ promise.rejectWith(ActivityNotFoundException())
407
+ return@onMain
408
+ }
409
+
410
+ UserApiClient.instance.selectShippingAddress(context) { addressId, error ->
271
411
  if (error != null) {
272
412
  promise.rejectWith(error)
273
- } else if (addrs == null) {
274
- promise.rejectWith(RNCKakaoResponseNotFoundException("shippingAddresses"))
413
+ } else if (addressId == null) {
414
+ promise.rejectWith(RNCKakaoResponseNotFoundException("addressId"))
275
415
  } else {
276
- promise.resolve(
277
- argMap().apply {
278
- putD("userId", addrs.userId?.toDouble())
279
- putB("needsAgreement", addrs.needsAgreement)
280
- putArray(
281
- "shippingAddresses",
282
- argArr().apply {
283
- pushMapList(
284
- addrs.shippingAddresses?.map { addr ->
285
- argMap().apply {
286
- putDouble("id", addr.id.toDouble())
287
- putString("name", addr.name)
288
- putBoolean("isDefault", addr.isDefault)
289
- putD("updatedAt", addr.updatedAt?.unix?.toDouble())
290
- putString("type", addr.type?.name)
291
- putString("baseAddress", addr.baseAddress)
292
- putString("detailAddress", addr.detailAddress)
293
- putString("receiverName", addr.receiverName)
294
- putString("receiverPhoneNumber1", addr.receiverPhoneNumber1)
295
- putString("receiverPhoneNumber2", addr.receiverPhoneNumber2)
296
- putString("zoneNumber", addr.zoneNumber)
297
- putString("zipCode", addr.zipCode)
298
- }
299
- } ?: listOf(),
300
- )
301
- },
302
- )
303
- },
304
- )
416
+ promise.resolve(addressId.toDouble())
305
417
  }
306
418
  }
307
419
  }
308
420
 
309
421
  @ReactMethod
310
- override fun me(promise: Promise) =
311
- onMain {
312
- UserApiClient.instance.me { user, error ->
313
- if (error != null) {
314
- promise.rejectWith(error)
315
- } else if (user == null) {
316
- promise.rejectWith(RNCKakaoResponseNotFoundException("user"))
317
- } else {
318
- promise.resolve(
319
- argMap().apply {
320
- putD("id", user.id?.toDouble())
321
- putL("connectedAt", user.connectedAt?.unix)
322
- putL("synchedAt", user.synchedAt?.unix)
323
- putString("name", user.kakaoAccount?.name)
422
+ override fun updateProfile(
423
+ properties: ReadableMap,
424
+ promise: Promise,
425
+ ) = onMain {
426
+ UserApiClient.instance.updateProfile(properties.toStringMap()) { error ->
427
+ if (error != null) {
428
+ promise.rejectWith(error)
429
+ } else {
430
+ promise.resolve(null)
431
+ }
432
+ }
433
+ }
324
434
 
325
- putString("email", user.kakaoAccount?.email)
326
- putString("nickname", user.kakaoAccount?.profile?.nickname)
327
- putString("profileImageUrl", user.kakaoAccount?.profile?.profileImageUrl)
328
- putString("thumbnailImageUrl", user.kakaoAccount?.profile?.thumbnailImageUrl)
329
- putString("phoneNumber", user.kakaoAccount?.phoneNumber)
330
- putString("ageRange", user.kakaoAccount?.ageRange?.name)
331
- putString("birthday", user.kakaoAccount?.birthday)
332
- putString("birthdayType", user.kakaoAccount?.birthdayType?.name)
333
- putString("birthyear", user.kakaoAccount?.birthyear)
334
- putString("gender", user.kakaoAccount?.gender?.name)
335
- putB("isEmailValid", user.kakaoAccount?.isEmailValid)
336
- putB("isEmailVerified", user.kakaoAccount?.isEmailVerified)
337
- putB("isKorean", user.kakaoAccount?.isKorean)
338
- putB(
339
- "ageRangeNeedsAgreement",
340
- user.kakaoAccount?.ageRangeNeedsAgreement,
341
- )
342
- putB(
343
- "birthdayNeedsAgreement",
344
- user.kakaoAccount?.birthdayNeedsAgreement,
345
- )
346
- putB(
347
- "birthyearNeedsAgreement",
348
- user.kakaoAccount?.birthyearNeedsAgreement,
349
- )
350
- putB(
351
- "emailNeedsAgreement",
352
- user.kakaoAccount?.emailNeedsAgreement,
353
- )
354
- putB(
355
- "genderNeedsAgreement",
356
- user.kakaoAccount?.genderNeedsAgreement,
357
- )
358
- putB(
359
- "isKoreanNeedsAgreement",
360
- user.kakaoAccount?.isKoreanNeedsAgreement,
361
- )
362
- putB(
363
- "phoneNumberNeedsAgreement",
364
- user.kakaoAccount?.phoneNumberNeedsAgreement,
365
- )
366
- putB(
367
- "profileNeedsAgreement",
368
- user.kakaoAccount?.profileNeedsAgreement,
369
- )
370
- putB(
371
- "nameNeedsAgreement",
372
- user.kakaoAccount?.nameNeedsAgreement,
373
- )
374
- putB(
375
- "profileImageNeedsAgreement",
376
- user.kakaoAccount?.profileImageNeedsAgreement,
377
- )
378
- putB(
379
- "profileNicknameNeedsAgreement",
380
- user.kakaoAccount?.profileNicknameNeedsAgreement,
381
- )
382
- putB(
383
- "legalBirthDateNeedsAgreement",
384
- user.kakaoAccount?.legalBirthDateNeedsAgreement,
385
- )
386
- },
387
- )
388
- }
435
+ @ReactMethod
436
+ override fun me(
437
+ propertyKeys: ReadableArray?,
438
+ secureResource: Boolean?,
439
+ promise: Promise,
440
+ ) = onMain {
441
+ UserApiClient.instance.me(
442
+ propertyKeys?.filterIsInstance<String>(),
443
+ secureResource = secureResource ?: true,
444
+ ) { user, error ->
445
+ if (error != null) {
446
+ promise.rejectWith(error)
447
+ } else if (user == null) {
448
+ promise.rejectWith(RNCKakaoResponseNotFoundException("user"))
449
+ } else {
450
+ promise.resolve(
451
+ argMap().apply {
452
+ putD("id", user.id?.toDouble())
453
+ putMap(
454
+ "properties",
455
+ argMap().apply {
456
+ user.properties?.forEach { (key, value) -> putString(key, value) }
457
+ },
458
+ )
459
+ putB("hasSignedUp", user.hasSignedUp)
460
+ putString("uuid", user.uuid)
461
+ putString("groupUserToken", user.groupUserToken)
462
+ putL("connectedAt", user.connectedAt?.unix)
463
+ putL("synchedAt", user.synchedAt?.unix)
464
+ putString("name", user.kakaoAccount?.name)
465
+
466
+ putString("email", user.kakaoAccount?.email)
467
+ putString("nickname", user.kakaoAccount?.profile?.nickname)
468
+ putString("profileImageUrl", user.kakaoAccount?.profile?.profileImageUrl)
469
+ putString("thumbnailImageUrl", user.kakaoAccount?.profile?.thumbnailImageUrl)
470
+ putB("isDefaultImage", user.kakaoAccount?.profile?.isDefaultImage)
471
+ putString("phoneNumber", user.kakaoAccount?.phoneNumber)
472
+ putString("ageRange", user.kakaoAccount?.ageRange.toBridgeValue())
473
+ putString("birthday", user.kakaoAccount?.birthday)
474
+ putString("birthdayType", user.kakaoAccount?.birthdayType.toBridgeValue())
475
+ putB("isLeapMonth", user.kakaoAccount?.isLeapMonth)
476
+ putString("birthyear", user.kakaoAccount?.birthyear)
477
+ putString("gender", user.kakaoAccount?.gender.toBridgeValue())
478
+ putB("isEmailValid", user.kakaoAccount?.isEmailValid)
479
+ putB("isEmailVerified", user.kakaoAccount?.isEmailVerified)
480
+ putB("isKorean", user.kakaoAccount?.isKorean)
481
+ putB(
482
+ "ageRangeNeedsAgreement",
483
+ user.kakaoAccount?.ageRangeNeedsAgreement,
484
+ )
485
+ putB(
486
+ "birthdayNeedsAgreement",
487
+ user.kakaoAccount?.birthdayNeedsAgreement,
488
+ )
489
+ putB(
490
+ "birthyearNeedsAgreement",
491
+ user.kakaoAccount?.birthyearNeedsAgreement,
492
+ )
493
+ putB(
494
+ "emailNeedsAgreement",
495
+ user.kakaoAccount?.emailNeedsAgreement,
496
+ )
497
+ putB(
498
+ "genderNeedsAgreement",
499
+ user.kakaoAccount?.genderNeedsAgreement,
500
+ )
501
+ putB(
502
+ "isKoreanNeedsAgreement",
503
+ user.kakaoAccount?.isKoreanNeedsAgreement,
504
+ )
505
+ putB(
506
+ "phoneNumberNeedsAgreement",
507
+ user.kakaoAccount?.phoneNumberNeedsAgreement,
508
+ )
509
+ putB(
510
+ "profileNeedsAgreement",
511
+ user.kakaoAccount?.profileNeedsAgreement,
512
+ )
513
+ putB(
514
+ "nameNeedsAgreement",
515
+ user.kakaoAccount?.nameNeedsAgreement,
516
+ )
517
+ putB(
518
+ "profileImageNeedsAgreement",
519
+ user.kakaoAccount?.profileImageNeedsAgreement,
520
+ )
521
+ putB(
522
+ "profileNicknameNeedsAgreement",
523
+ user.kakaoAccount?.profileNicknameNeedsAgreement,
524
+ )
525
+ putB(
526
+ "legalBirthDateNeedsAgreement",
527
+ user.kakaoAccount?.legalBirthDateNeedsAgreement,
528
+ )
529
+ putString("legalName", user.kakaoAccount?.legalName)
530
+ putB("legalNameNeedsAgreement", user.kakaoAccount?.legalNameNeedsAgreement)
531
+ putString("legalBirthDate", user.kakaoAccount?.legalBirthDate)
532
+ putString("legalGender", user.kakaoAccount?.legalGender.toBridgeValue())
533
+ putB("legalGenderNeedsAgreement", user.kakaoAccount?.legalGenderNeedsAgreement)
534
+ },
535
+ )
389
536
  }
390
537
  }
538
+ }
391
539
 
392
540
  @ReactMethod
393
541
  override fun getAccessToken(promise: Promise) =
@@ -408,4 +556,102 @@ class RNCKakaoUserModule internal constructor(
408
556
  }
409
557
  }
410
558
  }
559
+
560
+ private fun mapScopes(scopes: List<Scope>?) =
561
+ argArr().pushMapList(
562
+ scopes.orEmpty().map { scope ->
563
+ argMap().apply {
564
+ putString("id", scope.id)
565
+ putString("displayName", scope.displayName)
566
+ putString("type", scope.type.name)
567
+ putBoolean("using", scope.using)
568
+ putB("delegated", scope.delegated)
569
+ putBoolean("agreed", scope.agreed)
570
+ putB("revocable", scope.revocable)
571
+ }
572
+ },
573
+ )
574
+
575
+ private fun tokenCallback(promise: Promise): (OAuthToken?, Throwable?) -> Unit =
576
+ { token, error ->
577
+ if (error != null) {
578
+ promise.rejectWith(error)
579
+ } else if (token == null) {
580
+ promise.rejectWith(RNCKakaoResponseNotFoundException("token"))
581
+ } else {
582
+ promise.resolve(
583
+ argMap().apply {
584
+ putString("accessToken", token.accessToken)
585
+ putString("refreshToken", token.refreshToken)
586
+ putString("tokenType", null)
587
+ putString("idToken", token.idToken)
588
+ putDouble(
589
+ "accessTokenExpiresAt",
590
+ token.accessTokenExpiresAt.unix.toDouble(),
591
+ )
592
+ putDouble(
593
+ "refreshTokenExpiresAt",
594
+ token.refreshTokenExpiresAt.unix.toDouble(),
595
+ )
596
+ putDouble(
597
+ "accessTokenExpiresIn",
598
+ RNCKakaoUtil.diffSec(token.accessTokenExpiresAt, Date()).toDouble(),
599
+ )
600
+ putDouble(
601
+ "refreshTokenExpiresIn",
602
+ RNCKakaoUtil.diffSec(token.refreshTokenExpiresAt, Date()).toDouble(),
603
+ )
604
+ putArray(
605
+ "scopes",
606
+ argArr().apply {
607
+ pushStringList(token.scopes ?: listOf())
608
+ },
609
+ )
610
+ },
611
+ )
612
+ }
613
+ }
614
+
615
+ private fun loginPrompts(prompts: ReadableArray?): List<Prompt>? =
616
+ prompts
617
+ ?.filterIsInstance<String>()
618
+ ?.mapNotNull {
619
+ when (it) {
620
+ "Login" -> LOGIN
621
+ "Create" -> CREATE
622
+ "Cert" -> CERT
623
+ "SelectAccount" -> SELECT_ACCOUNT
624
+ else -> null
625
+ }
626
+ }?.ifEmpty { null }
411
627
  }
628
+
629
+ private fun AgeRange?.toBridgeValue(): String? =
630
+ when (this) {
631
+ AgeRange.AGE_0_9 -> "0~9"
632
+ AgeRange.AGE_10_14 -> "10~14"
633
+ AgeRange.AGE_15_19 -> "15~19"
634
+ AgeRange.AGE_20_29 -> "20~29"
635
+ AgeRange.AGE_30_39 -> "30~39"
636
+ AgeRange.AGE_40_49 -> "40~49"
637
+ AgeRange.AGE_50_59 -> "50~59"
638
+ AgeRange.AGE_60_69 -> "60~69"
639
+ AgeRange.AGE_70_79 -> "70~79"
640
+ AgeRange.AGE_80_89 -> "80~89"
641
+ AgeRange.AGE_90_ABOVE -> "90~"
642
+ AgeRange.UNKNOWN, null -> null
643
+ }
644
+
645
+ private fun Gender?.toBridgeValue(): String? =
646
+ when (this) {
647
+ Gender.FEMALE -> "female"
648
+ Gender.MALE -> "male"
649
+ Gender.UNKNOWN, null -> null
650
+ }
651
+
652
+ private fun BirthdayType?.toBridgeValue(): String? =
653
+ when (this) {
654
+ BirthdayType.SOLAR -> "SOLAR"
655
+ BirthdayType.LUNAR -> "LUNAR"
656
+ BirthdayType.UNKNOWN, null -> null
657
+ }