@react-native-kakao/user 3.0.0 → 3.1.0-next.1

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