react-native-nitro-auth 0.5.1 → 0.5.4

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.
Files changed (126) hide show
  1. package/README.md +362 -190
  2. package/android/build.gradle +2 -5
  3. package/android/src/main/cpp/PlatformAuth+Android.cpp +84 -18
  4. package/android/src/main/java/com/auth/AuthAdapter.kt +82 -182
  5. package/android/src/main/java/com/auth/NitroAuthPackage.kt +1 -1
  6. package/app.plugin.js +2 -9
  7. package/cpp/AuthCache.cpp +0 -134
  8. package/cpp/AuthCache.hpp +0 -7
  9. package/cpp/HybridAuth.cpp +57 -63
  10. package/cpp/HybridAuth.hpp +3 -4
  11. package/ios/AuthAdapter.swift +23 -25
  12. package/lib/commonjs/Auth.web.js +523 -201
  13. package/lib/commonjs/Auth.web.js.map +1 -1
  14. package/lib/commonjs/index.js +0 -12
  15. package/lib/commonjs/index.js.map +1 -1
  16. package/lib/commonjs/index.web.js +0 -12
  17. package/lib/commonjs/index.web.js.map +1 -1
  18. package/lib/commonjs/js-storage-adapter.js +2 -0
  19. package/lib/commonjs/js-storage-adapter.js.map +1 -0
  20. package/lib/commonjs/service.js +9 -86
  21. package/lib/commonjs/service.js.map +1 -1
  22. package/lib/commonjs/service.web.js +1 -5
  23. package/lib/commonjs/service.web.js.map +1 -1
  24. package/lib/commonjs/ui/social-button.js +44 -29
  25. package/lib/commonjs/ui/social-button.js.map +1 -1
  26. package/lib/commonjs/ui/social-button.web.js +44 -29
  27. package/lib/commonjs/ui/social-button.web.js.map +1 -1
  28. package/lib/commonjs/use-auth.js +56 -42
  29. package/lib/commonjs/use-auth.js.map +1 -1
  30. package/lib/commonjs/utils/logger.js +12 -4
  31. package/lib/commonjs/utils/logger.js.map +1 -1
  32. package/lib/module/Auth.web.js +523 -201
  33. package/lib/module/Auth.web.js.map +1 -1
  34. package/lib/module/index.js +0 -1
  35. package/lib/module/index.js.map +1 -1
  36. package/lib/module/index.web.js +0 -1
  37. package/lib/module/index.web.js.map +1 -1
  38. package/lib/module/js-storage-adapter.js +2 -0
  39. package/lib/module/js-storage-adapter.js.map +1 -0
  40. package/lib/module/service.js +9 -86
  41. package/lib/module/service.js.map +1 -1
  42. package/lib/module/service.web.js +1 -5
  43. package/lib/module/service.web.js.map +1 -1
  44. package/lib/module/ui/social-button.js +44 -29
  45. package/lib/module/ui/social-button.js.map +1 -1
  46. package/lib/module/ui/social-button.web.js +44 -29
  47. package/lib/module/ui/social-button.web.js.map +1 -1
  48. package/lib/module/use-auth.js +56 -42
  49. package/lib/module/use-auth.js.map +1 -1
  50. package/lib/module/utils/logger.js +12 -4
  51. package/lib/module/utils/logger.js.map +1 -1
  52. package/lib/typescript/commonjs/Auth.nitro.d.ts +3 -3
  53. package/lib/typescript/commonjs/Auth.nitro.d.ts.map +1 -1
  54. package/lib/typescript/commonjs/Auth.web.d.ts +25 -6
  55. package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/index.d.ts +1 -2
  57. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/index.web.d.ts +0 -1
  59. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/js-storage-adapter.d.ts +6 -0
  61. package/lib/typescript/commonjs/js-storage-adapter.d.ts.map +1 -0
  62. package/lib/typescript/commonjs/service.d.ts +1 -8
  63. package/lib/typescript/commonjs/service.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/service.web.d.ts +1 -8
  65. package/lib/typescript/commonjs/service.web.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/ui/social-button.d.ts +6 -6
  67. package/lib/typescript/commonjs/ui/social-button.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/ui/social-button.web.d.ts +6 -6
  69. package/lib/typescript/commonjs/ui/social-button.web.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/use-auth.d.ts +4 -4
  71. package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
  72. package/lib/typescript/commonjs/utils/logger.d.ts +4 -4
  73. package/lib/typescript/commonjs/utils/logger.d.ts.map +1 -1
  74. package/lib/typescript/module/Auth.nitro.d.ts +3 -3
  75. package/lib/typescript/module/Auth.nitro.d.ts.map +1 -1
  76. package/lib/typescript/module/Auth.web.d.ts +25 -6
  77. package/lib/typescript/module/Auth.web.d.ts.map +1 -1
  78. package/lib/typescript/module/index.d.ts +1 -2
  79. package/lib/typescript/module/index.d.ts.map +1 -1
  80. package/lib/typescript/module/index.web.d.ts +0 -1
  81. package/lib/typescript/module/index.web.d.ts.map +1 -1
  82. package/lib/typescript/module/js-storage-adapter.d.ts +6 -0
  83. package/lib/typescript/module/js-storage-adapter.d.ts.map +1 -0
  84. package/lib/typescript/module/service.d.ts +1 -8
  85. package/lib/typescript/module/service.d.ts.map +1 -1
  86. package/lib/typescript/module/service.web.d.ts +1 -8
  87. package/lib/typescript/module/service.web.d.ts.map +1 -1
  88. package/lib/typescript/module/ui/social-button.d.ts +6 -6
  89. package/lib/typescript/module/ui/social-button.d.ts.map +1 -1
  90. package/lib/typescript/module/ui/social-button.web.d.ts +6 -6
  91. package/lib/typescript/module/ui/social-button.web.d.ts.map +1 -1
  92. package/lib/typescript/module/use-auth.d.ts +4 -4
  93. package/lib/typescript/module/use-auth.d.ts.map +1 -1
  94. package/lib/typescript/module/utils/logger.d.ts +4 -4
  95. package/lib/typescript/module/utils/logger.d.ts.map +1 -1
  96. package/nitrogen/generated/android/NitroAuth+autolinking.cmake +0 -1
  97. package/nitrogen/generated/shared/c++/AuthTokens.hpp +5 -1
  98. package/nitrogen/generated/shared/c++/AuthUser.hpp +5 -1
  99. package/nitrogen/generated/shared/c++/HybridAuthSpec.cpp +0 -1
  100. package/nitrogen/generated/shared/c++/HybridAuthSpec.hpp +0 -5
  101. package/package.json +11 -8
  102. package/react-native-nitro-auth.podspec +1 -1
  103. package/src/Auth.nitro.ts +4 -3
  104. package/src/Auth.web.ts +700 -246
  105. package/src/global.d.ts +0 -1
  106. package/src/index.ts +1 -2
  107. package/src/index.web.ts +0 -1
  108. package/src/js-storage-adapter.ts +5 -0
  109. package/src/service.ts +13 -106
  110. package/src/service.web.ts +0 -7
  111. package/src/ui/social-button.tsx +66 -43
  112. package/src/ui/social-button.web.tsx +67 -44
  113. package/src/use-auth.ts +116 -72
  114. package/src/utils/logger.ts +12 -4
  115. package/ios/KeychainStore.swift +0 -43
  116. package/lib/commonjs/AuthStorage.nitro.js +0 -6
  117. package/lib/commonjs/AuthStorage.nitro.js.map +0 -1
  118. package/lib/module/AuthStorage.nitro.js +0 -4
  119. package/lib/module/AuthStorage.nitro.js.map +0 -1
  120. package/lib/typescript/commonjs/AuthStorage.nitro.d.ts +0 -26
  121. package/lib/typescript/commonjs/AuthStorage.nitro.d.ts.map +0 -1
  122. package/lib/typescript/module/AuthStorage.nitro.d.ts +0 -26
  123. package/lib/typescript/module/AuthStorage.nitro.d.ts.map +0 -1
  124. package/nitrogen/generated/shared/c++/HybridAuthStorageAdapterSpec.cpp +0 -23
  125. package/nitrogen/generated/shared/c++/HybridAuthStorageAdapterSpec.hpp +0 -65
  126. package/src/AuthStorage.nitro.ts +0 -26
package/src/global.d.ts CHANGED
@@ -35,4 +35,3 @@ declare global {
35
35
  }
36
36
 
37
37
  export {};
38
-
package/src/index.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./Auth.nitro";
2
- export * from "./AuthStorage.nitro";
3
2
  export * from "./ui/social-button";
4
3
  export { useAuth, type UseAuthReturn } from "./use-auth";
5
- export { AuthService, type JSStorageAdapter } from "./service";
4
+ export { AuthService } from "./service";
package/src/index.web.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./Auth.nitro";
2
- export * from "./AuthStorage.nitro";
3
2
  export * from "./ui/social-button.web";
4
3
  export * from "./use-auth";
5
4
  export { AuthService } from "./service.web";
@@ -0,0 +1,5 @@
1
+ export type JSStorageAdapter = {
2
+ save(key: string, value: string): void | Promise<void>;
3
+ load(key: string): string | undefined | Promise<string | undefined>;
4
+ remove(key: string): void | Promise<void>;
5
+ };
package/src/service.ts CHANGED
@@ -3,66 +3,22 @@ import type {
3
3
  Auth,
4
4
  AuthProvider,
5
5
  AuthTokens,
6
- AuthUser,
7
6
  LoginOptions,
7
+ AuthUser,
8
8
  } from "./Auth.nitro";
9
- import type { AuthStorageAdapter } from "./AuthStorage.nitro";
10
-
11
- const STORAGE_KEY = "nitro_auth_user";
12
- const SCOPES_KEY = "nitro_auth_scopes";
13
-
14
- export interface JSStorageAdapter {
15
- save(key: string, value: string): void | Promise<void>;
16
- load(key: string): string | undefined | Promise<string | undefined>;
17
- remove(key: string): void | Promise<void>;
18
- }
19
9
 
20
10
  const nitroAuth = NitroModules.createHybridObject<Auth>("Auth");
21
-
22
- let jsStorageAdapter: JSStorageAdapter | undefined;
23
- let cachedUser: AuthUser | undefined;
24
- let cachedScopes: string[] = [];
25
-
26
- async function loadFromJSStorage() {
27
- if (!jsStorageAdapter) return;
28
- const json = await jsStorageAdapter.load(STORAGE_KEY);
29
- if (json) {
30
- try {
31
- cachedUser = JSON.parse(json);
32
- } catch {}
33
- }
34
- const scopesJson = await jsStorageAdapter.load(SCOPES_KEY);
35
- if (scopesJson) {
36
- try {
37
- cachedScopes = JSON.parse(scopesJson);
38
- } catch {}
39
- }
40
- }
41
-
42
- async function saveToJSStorage(user: AuthUser | undefined) {
43
- if (!jsStorageAdapter) return;
44
- if (user) {
45
- await jsStorageAdapter.save(STORAGE_KEY, JSON.stringify(user));
46
- await jsStorageAdapter.save(SCOPES_KEY, JSON.stringify(cachedScopes));
47
- } else {
48
- await jsStorageAdapter.remove(STORAGE_KEY);
49
- await jsStorageAdapter.remove(SCOPES_KEY);
50
- }
51
- }
52
-
53
- export const AuthService: Auth & {
54
- setJSStorageAdapter(adapter: JSStorageAdapter | undefined): void;
55
- } = {
11
+ export const AuthService: Auth = {
56
12
  get name() {
57
13
  return nitroAuth.name;
58
14
  },
59
15
 
60
16
  get currentUser() {
61
- return jsStorageAdapter ? cachedUser : nitroAuth.currentUser;
17
+ return nitroAuth.currentUser;
62
18
  },
63
19
 
64
20
  get grantedScopes() {
65
- return jsStorageAdapter ? cachedScopes : nitroAuth.grantedScopes;
21
+ return nitroAuth.grantedScopes;
66
22
  },
67
23
 
68
24
  get hasPlayServices() {
@@ -70,34 +26,15 @@ export const AuthService: Auth & {
70
26
  },
71
27
 
72
28
  async login(provider: AuthProvider, options?: LoginOptions) {
73
- await nitroAuth.login(provider, options);
74
- if (jsStorageAdapter) {
75
- cachedUser = nitroAuth.currentUser;
76
- cachedScopes = options?.scopes ?? nitroAuth.grantedScopes;
77
- if (cachedUser) cachedUser.scopes = cachedScopes;
78
- await saveToJSStorage(cachedUser);
79
- }
29
+ return nitroAuth.login(provider, options);
80
30
  },
81
31
 
82
32
  async requestScopes(scopes: string[]) {
83
- await nitroAuth.requestScopes(scopes);
84
- if (jsStorageAdapter) {
85
- cachedUser = nitroAuth.currentUser;
86
- for (const s of scopes) {
87
- if (!cachedScopes.includes(s)) cachedScopes.push(s);
88
- }
89
- if (cachedUser) cachedUser.scopes = cachedScopes;
90
- await saveToJSStorage(cachedUser);
91
- }
33
+ return nitroAuth.requestScopes(scopes);
92
34
  },
93
35
 
94
36
  async revokeScopes(scopes: string[]) {
95
- await nitroAuth.revokeScopes(scopes);
96
- if (jsStorageAdapter) {
97
- cachedScopes = cachedScopes.filter((s) => !scopes.includes(s));
98
- if (cachedUser) cachedUser.scopes = cachedScopes;
99
- await saveToJSStorage(cachedUser);
100
- }
37
+ return nitroAuth.revokeScopes(scopes);
101
38
  },
102
39
 
103
40
  async getAccessToken() {
@@ -105,36 +42,20 @@ export const AuthService: Auth & {
105
42
  },
106
43
 
107
44
  async refreshToken() {
108
- const tokens = await nitroAuth.refreshToken();
109
- if (jsStorageAdapter && cachedUser) {
110
- cachedUser.accessToken = tokens.accessToken;
111
- cachedUser.idToken = tokens.idToken;
112
- await saveToJSStorage(cachedUser);
113
- }
114
- return tokens;
45
+ return nitroAuth.refreshToken();
115
46
  },
116
47
 
117
48
  logout() {
118
49
  nitroAuth.logout();
119
- if (jsStorageAdapter) {
120
- cachedUser = undefined;
121
- cachedScopes = [];
122
- saveToJSStorage(undefined);
123
- }
124
50
  },
125
51
 
126
52
  async silentRestore() {
127
- await nitroAuth.silentRestore();
128
- if (jsStorageAdapter) {
129
- cachedUser = nitroAuth.currentUser;
130
- cachedScopes = nitroAuth.grantedScopes;
131
- await saveToJSStorage(cachedUser);
132
- }
53
+ return nitroAuth.silentRestore();
133
54
  },
134
55
 
135
56
  onAuthStateChanged(callback: (user: AuthUser | undefined) => void) {
136
- return nitroAuth.onAuthStateChanged(() => {
137
- callback(AuthService.currentUser);
57
+ return nitroAuth.onAuthStateChanged((user) => {
58
+ callback(user);
138
59
  });
139
60
  },
140
61
 
@@ -146,25 +67,11 @@ export const AuthService: Auth & {
146
67
  nitroAuth.setLoggingEnabled(enabled);
147
68
  },
148
69
 
149
- setStorageAdapter(adapter: AuthStorageAdapter | undefined): void {
150
- nitroAuth.setStorageAdapter(adapter);
151
- },
152
-
153
- async setJSStorageAdapter(adapter: JSStorageAdapter | undefined) {
154
- jsStorageAdapter = adapter;
155
- if (adapter) {
156
- await loadFromJSStorage();
157
- } else {
158
- cachedUser = undefined;
159
- cachedScopes = [];
160
- }
161
- },
162
-
163
70
  dispose() {
164
71
  nitroAuth.dispose();
165
72
  },
166
73
 
167
- equals(other: unknown): boolean {
168
- return (nitroAuth as { equals(o: unknown): boolean }).equals(other);
74
+ equals(other: Parameters<Auth["equals"]>[0]): boolean {
75
+ return nitroAuth.equals(other);
169
76
  },
170
77
  };
@@ -1,6 +1,4 @@
1
1
  import { AuthModule } from "./Auth.web";
2
- import type { AuthStorageAdapter } from "./AuthStorage.nitro";
3
- import type { JSStorageAdapter } from "./service";
4
2
 
5
3
  export const AuthService = {
6
4
  ...AuthModule,
@@ -31,11 +29,6 @@ export const AuthService = {
31
29
  onAuthStateChanged: AuthModule.onAuthStateChanged.bind(AuthModule),
32
30
  onTokensRefreshed: AuthModule.onTokensRefreshed.bind(AuthModule),
33
31
  setLoggingEnabled: AuthModule.setLoggingEnabled.bind(AuthModule),
34
- setStorageAdapter: AuthModule.setStorageAdapter.bind(AuthModule),
35
32
  dispose: AuthModule.dispose.bind(AuthModule),
36
33
  equals: AuthModule.equals.bind(AuthModule),
37
-
38
- setJSStorageAdapter(adapter: JSStorageAdapter | undefined): void {
39
- AuthModule.setStorageAdapter(adapter as AuthStorageAdapter | undefined);
40
- },
41
34
  };
@@ -1,19 +1,20 @@
1
1
  import React, { useState } from "react";
2
+ import type { ViewStyle, TextStyle } from "react-native";
2
3
  import {
3
4
  Pressable,
4
5
  Text,
5
6
  StyleSheet,
6
7
  View,
7
- ViewStyle,
8
- TextStyle,
9
8
  ActivityIndicator,
10
9
  } from "react-native";
11
10
  import { NitroModules } from "react-native-nitro-modules";
12
11
  import type { Auth, AuthProvider, AuthUser } from "../Auth.nitro";
13
12
 
14
- interface SocialButtonProps {
13
+ export type SocialButtonVariant = "primary" | "outline" | "white" | "black";
14
+
15
+ export type SocialButtonProps = {
15
16
  provider: AuthProvider;
16
- variant?: "primary" | "outline" | "white" | "black";
17
+ variant?: SocialButtonVariant;
17
18
  borderRadius?: number;
18
19
  style?: ViewStyle;
19
20
  textStyle?: TextStyle;
@@ -21,14 +22,45 @@ interface SocialButtonProps {
21
22
  onSuccess?: (user: AuthUser) => void;
22
23
  onError?: (error: unknown) => void;
23
24
  onPress?: () => void;
24
- }
25
+ };
26
+
27
+ const PROVIDER_LABELS: Record<AuthProvider, string> = {
28
+ google: "Google",
29
+ apple: "Apple",
30
+ microsoft: "Microsoft",
31
+ };
32
+
33
+ const PROVIDER_PRIMARY_BACKGROUND: Record<AuthProvider, string> = {
34
+ google: "#4285F4",
35
+ apple: "#000000",
36
+ microsoft: "#2F2F2F",
37
+ };
38
+
39
+ const getBackgroundColor = ({
40
+ disabled,
41
+ variant,
42
+ provider,
43
+ }: {
44
+ disabled: boolean;
45
+ variant: SocialButtonVariant;
46
+ provider: AuthProvider;
47
+ }): string => {
48
+ if (disabled) return "#CCCCCC";
49
+ if (variant === "black") return "#000000";
50
+ if (variant === "white") return "#FFFFFF";
51
+ if (variant === "outline") return "transparent";
52
+ return PROVIDER_PRIMARY_BACKGROUND[provider];
53
+ };
54
+
55
+ const getTextColor = (variant: SocialButtonVariant): string =>
56
+ variant === "white" || variant === "outline" ? "#000000" : "#FFFFFF";
25
57
 
26
58
  async function performLogin(provider: AuthProvider): Promise<void> {
27
59
  const auth = NitroModules.createHybridObject<Auth>("Auth");
28
60
  await auth.login(provider);
29
61
  }
30
62
 
31
- export const SocialButton: React.FC<SocialButtonProps> = ({
63
+ export const SocialButton = ({
32
64
  provider,
33
65
  variant = "primary",
34
66
  borderRadius = 8,
@@ -38,46 +70,30 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
38
70
  onSuccess,
39
71
  onError,
40
72
  onPress,
41
- }) => {
73
+ }: SocialButtonProps) => {
42
74
  const [loading, setLoading] = useState(false);
43
75
 
44
- const handleLogin = () => {
76
+ const handleLogin = async () => {
45
77
  if (loading || disabled) return;
46
78
  if (onPress) {
47
79
  onPress();
48
80
  return;
49
81
  }
50
- setLoading(true);
51
- performLogin(provider)
52
- .then(() => {
53
- setLoading(false);
54
- const user = NitroModules.createHybridObject<Auth>("Auth").currentUser;
55
- if (user) onSuccess?.(user);
56
- })
57
- .catch((e) => {
58
- setLoading(false);
59
- onError?.(e);
60
- });
61
- };
62
82
 
63
- const isGoogle = provider === "google";
64
- const isMicrosoft = provider === "microsoft";
65
- const isDisabled = loading || disabled;
66
-
67
- const getBackgroundColor = () => {
68
- if (isDisabled) return "#CCCCCC";
69
- if (variant === "black") return "#000000";
70
- if (variant === "white") return "#FFFFFF";
71
- if (variant === "outline") return "transparent";
72
- if (isGoogle) return "#4285F4";
73
- if (isMicrosoft) return "#2F2F2F";
74
- return "#000000";
75
- };
76
-
77
- const getTextColor = () => {
78
- if (variant === "white" || variant === "outline") return "#000000";
79
- return "#FFFFFF";
83
+ setLoading(true);
84
+ try {
85
+ await performLogin(provider);
86
+ const user = NitroModules.createHybridObject<Auth>("Auth").currentUser;
87
+ if (user) {
88
+ onSuccess?.(user);
89
+ }
90
+ } catch (error) {
91
+ onError?.(error);
92
+ } finally {
93
+ setLoading(false);
94
+ }
80
95
  };
96
+ const isDisabled = loading || disabled === true;
81
97
 
82
98
  const getBorderColor = () => {
83
99
  if (variant === "outline") return "#DDDDDD";
@@ -89,7 +105,11 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
89
105
  style={[
90
106
  styles.button,
91
107
  {
92
- backgroundColor: getBackgroundColor(),
108
+ backgroundColor: getBackgroundColor({
109
+ disabled: isDisabled,
110
+ variant,
111
+ provider,
112
+ }),
93
113
  borderRadius,
94
114
  borderColor: getBorderColor(),
95
115
  borderWidth: variant === "outline" ? 1 : 0,
@@ -101,7 +121,7 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
101
121
  >
102
122
  <View style={styles.content}>
103
123
  {loading ? (
104
- <ActivityIndicator size="small" color={getTextColor()} />
124
+ <ActivityIndicator size="small" color={getTextColor(variant)} />
105
125
  ) : (
106
126
  <>
107
127
  {provider === "google" && variant !== "primary" && (
@@ -111,7 +131,9 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
111
131
  )}
112
132
  {provider === "apple" && variant !== "primary" && (
113
133
  <View style={styles.iconPlaceholder}>
114
- <Text style={{ fontSize: 18, color: getTextColor() }}></Text>
134
+ <Text style={{ fontSize: 18, color: getTextColor(variant) }}>
135
+
136
+ </Text>
115
137
  </View>
116
138
  )}
117
139
  {provider === "microsoft" && variant !== "primary" && (
@@ -119,9 +141,10 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
119
141
  <Text style={{ fontSize: 16 }}>⊞</Text>
120
142
  </View>
121
143
  )}
122
- <Text style={[styles.text, { color: getTextColor() }, textStyle]}>
123
- Sign in with{" "}
124
- {provider.charAt(0).toUpperCase() + provider.slice(1)}
144
+ <Text
145
+ style={[styles.text, { color: getTextColor(variant) }, textStyle]}
146
+ >
147
+ Sign in with {PROVIDER_LABELS[provider]}
125
148
  </Text>
126
149
  </>
127
150
  )}
@@ -1,19 +1,20 @@
1
1
  import React, { useState } from "react";
2
+ import type { ViewStyle, TextStyle } from "react-native";
2
3
  import {
3
4
  Pressable,
4
5
  Text,
5
6
  StyleSheet,
6
7
  View,
7
- ViewStyle,
8
- TextStyle,
9
8
  ActivityIndicator,
10
9
  } from "react-native";
11
- import type { AuthProvider, AuthUser } from "../Auth.nitro";
12
10
  import { AuthModule } from "../Auth.web";
11
+ import type { AuthProvider, AuthUser } from "../Auth.nitro";
12
+
13
+ export type SocialButtonVariant = "primary" | "outline" | "white" | "black";
13
14
 
14
- interface SocialButtonProps {
15
+ export type SocialButtonProps = {
15
16
  provider: AuthProvider;
16
- variant?: "primary" | "outline" | "white" | "black";
17
+ variant?: SocialButtonVariant;
17
18
  borderRadius?: number;
18
19
  style?: ViewStyle;
19
20
  textStyle?: TextStyle;
@@ -21,13 +22,44 @@ interface SocialButtonProps {
21
22
  onSuccess?: (user: AuthUser) => void;
22
23
  onError?: (error: unknown) => void;
23
24
  onPress?: () => void;
24
- }
25
+ };
26
+
27
+ const PROVIDER_LABELS: Record<AuthProvider, string> = {
28
+ google: "Google",
29
+ apple: "Apple",
30
+ microsoft: "Microsoft",
31
+ };
32
+
33
+ const PROVIDER_PRIMARY_BACKGROUND: Record<AuthProvider, string> = {
34
+ google: "#4285F4",
35
+ apple: "#000000",
36
+ microsoft: "#2F2F2F",
37
+ };
38
+
39
+ const getBackgroundColor = ({
40
+ disabled,
41
+ variant,
42
+ provider,
43
+ }: {
44
+ disabled: boolean;
45
+ variant: SocialButtonVariant;
46
+ provider: AuthProvider;
47
+ }): string => {
48
+ if (disabled) return "#CCCCCC";
49
+ if (variant === "black") return "#000000";
50
+ if (variant === "white") return "#FFFFFF";
51
+ if (variant === "outline") return "transparent";
52
+ return PROVIDER_PRIMARY_BACKGROUND[provider];
53
+ };
54
+
55
+ const getTextColor = (variant: SocialButtonVariant): string =>
56
+ variant === "white" || variant === "outline" ? "#000000" : "#FFFFFF";
25
57
 
26
58
  async function performLogin(provider: AuthProvider): Promise<void> {
27
59
  await AuthModule.login(provider);
28
60
  }
29
61
 
30
- export const SocialButton: React.FC<SocialButtonProps> = ({
62
+ export const SocialButton = ({
31
63
  provider,
32
64
  variant = "primary",
33
65
  borderRadius = 8,
@@ -37,46 +69,30 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
37
69
  onSuccess,
38
70
  onError,
39
71
  onPress,
40
- }) => {
72
+ }: SocialButtonProps) => {
41
73
  const [loading, setLoading] = useState(false);
42
74
 
43
- const handleLogin = () => {
75
+ const handleLogin = async () => {
44
76
  if (loading || disabled) return;
45
77
  if (onPress) {
46
78
  onPress();
47
79
  return;
48
80
  }
49
- setLoading(true);
50
- performLogin(provider)
51
- .then(() => {
52
- setLoading(false);
53
- const user = AuthModule.currentUser;
54
- if (user) onSuccess?.(user);
55
- })
56
- .catch((e) => {
57
- setLoading(false);
58
- onError?.(e);
59
- });
60
- };
61
81
 
62
- const isGoogle = provider === "google";
63
- const isMicrosoft = provider === "microsoft";
64
- const isDisabled = loading || disabled;
65
-
66
- const getBackgroundColor = () => {
67
- if (isDisabled) return "#CCCCCC";
68
- if (variant === "black") return "#000000";
69
- if (variant === "white") return "#FFFFFF";
70
- if (variant === "outline") return "transparent";
71
- if (isGoogle) return "#4285F4";
72
- if (isMicrosoft) return "#2F2F2F";
73
- return "#000000";
74
- };
75
-
76
- const getTextColor = () => {
77
- if (variant === "white" || variant === "outline") return "#000000";
78
- return "#FFFFFF";
82
+ setLoading(true);
83
+ try {
84
+ await performLogin(provider);
85
+ const user = AuthModule.currentUser;
86
+ if (user) {
87
+ onSuccess?.(user);
88
+ }
89
+ } catch (error) {
90
+ onError?.(error);
91
+ } finally {
92
+ setLoading(false);
93
+ }
79
94
  };
95
+ const isDisabled = loading || disabled === true;
80
96
 
81
97
  const getBorderColor = () => {
82
98
  if (variant === "outline") return "#DDDDDD";
@@ -88,7 +104,11 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
88
104
  style={[
89
105
  styles.button,
90
106
  {
91
- backgroundColor: getBackgroundColor(),
107
+ backgroundColor: getBackgroundColor({
108
+ disabled: isDisabled,
109
+ variant,
110
+ provider,
111
+ }),
92
112
  borderRadius,
93
113
  borderColor: getBorderColor(),
94
114
  borderWidth: variant === "outline" ? 1 : 0,
@@ -100,7 +120,7 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
100
120
  >
101
121
  <View style={styles.content}>
102
122
  {loading ? (
103
- <ActivityIndicator size="small" color={getTextColor()} />
123
+ <ActivityIndicator size="small" color={getTextColor(variant)} />
104
124
  ) : (
105
125
  <>
106
126
  {provider === "google" && variant !== "primary" && (
@@ -110,7 +130,9 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
110
130
  )}
111
131
  {provider === "apple" && variant !== "primary" && (
112
132
  <View style={styles.iconPlaceholder}>
113
- <Text style={{ fontSize: 18, color: getTextColor() }}></Text>
133
+ <Text style={{ fontSize: 18, color: getTextColor(variant) }}>
134
+
135
+ </Text>
114
136
  </View>
115
137
  )}
116
138
  {provider === "microsoft" && variant !== "primary" && (
@@ -118,9 +140,10 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
118
140
  <Text style={{ fontSize: 16 }}>⊞</Text>
119
141
  </View>
120
142
  )}
121
- <Text style={[styles.text, { color: getTextColor() }, textStyle]}>
122
- Sign in with{" "}
123
- {provider.charAt(0).toUpperCase() + provider.slice(1)}
143
+ <Text
144
+ style={[styles.text, { color: getTextColor(variant) }, textStyle]}
145
+ >
146
+ Sign in with {PROVIDER_LABELS[provider]}
124
147
  </Text>
125
148
  </>
126
149
  )}