@chem-po/firebase-native 0.0.51 → 0.0.53

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 (109) hide show
  1. package/lib/commonjs/adapter/auth.js +12 -5
  2. package/lib/commonjs/adapter/auth.js.map +1 -1
  3. package/lib/commonjs/adapter/db.js.map +1 -1
  4. package/lib/commonjs/adapter/index.js.map +1 -1
  5. package/lib/commonjs/adapter/storage.js.map +1 -1
  6. package/lib/commonjs/auth/functions.js.map +1 -1
  7. package/lib/commonjs/auth/index.js.map +1 -1
  8. package/lib/commonjs/components/AuthenticatorVerify.js +4 -2
  9. package/lib/commonjs/components/AuthenticatorVerify.js.map +1 -1
  10. package/lib/commonjs/components/FirebaseSignIn.js.map +1 -1
  11. package/lib/commonjs/components/PhoneVerify.js.map +1 -1
  12. package/lib/commonjs/components/TwoFactorAuthModal.js +3 -1
  13. package/lib/commonjs/components/TwoFactorAuthModal.js.map +1 -1
  14. package/lib/commonjs/components/index.js.map +1 -1
  15. package/lib/commonjs/contexts/FirebaseContext.js.map +1 -1
  16. package/lib/commonjs/contexts/index.js.map +1 -1
  17. package/lib/commonjs/db/index.js.map +1 -1
  18. package/lib/commonjs/db/utils.js.map +1 -1
  19. package/lib/commonjs/hooks/backend.js.map +1 -1
  20. package/lib/commonjs/hooks/index.js.map +1 -1
  21. package/lib/commonjs/hooks/useAuthenticatorVerify.js +19 -13
  22. package/lib/commonjs/hooks/useAuthenticatorVerify.js.map +1 -1
  23. package/lib/commonjs/hooks/usePhoneVerify.js +1 -1
  24. package/lib/commonjs/hooks/usePhoneVerify.js.map +1 -1
  25. package/lib/commonjs/icons/Apple.js.map +1 -1
  26. package/lib/commonjs/icons/Google.js.map +1 -1
  27. package/lib/commonjs/index.js.map +1 -1
  28. package/lib/commonjs/storage/index.js.map +1 -1
  29. package/lib/commonjs/storage/utils.js.map +1 -1
  30. package/lib/commonjs/types/adapter.js.map +1 -1
  31. package/lib/commonjs/types/auth.js.map +1 -1
  32. package/lib/commonjs/types/db.js.map +1 -1
  33. package/lib/commonjs/types/functions.js.map +1 -1
  34. package/lib/commonjs/types/index.js.map +1 -1
  35. package/lib/commonjs/types/storage.js.map +1 -1
  36. package/lib/commonjs/utils/validation.js.map +1 -1
  37. package/lib/module/adapter/auth.js +13 -6
  38. package/lib/module/adapter/auth.js.map +1 -1
  39. package/lib/module/adapter/db.js.map +1 -1
  40. package/lib/module/adapter/index.js.map +1 -1
  41. package/lib/module/adapter/storage.js.map +1 -1
  42. package/lib/module/auth/functions.js.map +1 -1
  43. package/lib/module/auth/index.js.map +1 -1
  44. package/lib/module/components/AuthenticatorVerify.js +4 -2
  45. package/lib/module/components/AuthenticatorVerify.js.map +1 -1
  46. package/lib/module/components/FirebaseSignIn.js.map +1 -1
  47. package/lib/module/components/PhoneVerify.js.map +1 -1
  48. package/lib/module/components/TwoFactorAuthModal.js +3 -1
  49. package/lib/module/components/TwoFactorAuthModal.js.map +1 -1
  50. package/lib/module/components/index.js.map +1 -1
  51. package/lib/module/contexts/FirebaseContext.js.map +1 -1
  52. package/lib/module/contexts/index.js.map +1 -1
  53. package/lib/module/db/index.js.map +1 -1
  54. package/lib/module/db/utils.js.map +1 -1
  55. package/lib/module/hooks/backend.js.map +1 -1
  56. package/lib/module/hooks/index.js.map +1 -1
  57. package/lib/module/hooks/useAuthenticatorVerify.js +20 -14
  58. package/lib/module/hooks/useAuthenticatorVerify.js.map +1 -1
  59. package/lib/module/hooks/usePhoneVerify.js +1 -1
  60. package/lib/module/hooks/usePhoneVerify.js.map +1 -1
  61. package/lib/module/icons/Apple.js.map +1 -1
  62. package/lib/module/icons/Google.js.map +1 -1
  63. package/lib/module/index.js.map +1 -1
  64. package/lib/module/storage/index.js.map +1 -1
  65. package/lib/module/storage/utils.js.map +1 -1
  66. package/lib/module/types/adapter.js.map +1 -1
  67. package/lib/module/types/auth.js.map +1 -1
  68. package/lib/module/types/db.js.map +1 -1
  69. package/lib/module/types/functions.js.map +1 -1
  70. package/lib/module/types/index.js.map +1 -1
  71. package/lib/module/types/storage.js.map +1 -1
  72. package/lib/module/utils/validation.js.map +1 -1
  73. package/lib/typescript/adapter/auth.d.ts.map +1 -1
  74. package/lib/typescript/components/AuthenticatorVerify.d.ts +4 -1
  75. package/lib/typescript/components/AuthenticatorVerify.d.ts.map +1 -1
  76. package/lib/typescript/hooks/useAuthenticatorVerify.d.ts +2 -1
  77. package/lib/typescript/hooks/useAuthenticatorVerify.d.ts.map +1 -1
  78. package/package.json +6 -21
  79. package/src/adapter/auth.ts +0 -556
  80. package/src/adapter/db.ts +0 -146
  81. package/src/adapter/index.ts +0 -32
  82. package/src/adapter/storage.ts +0 -58
  83. package/src/auth/functions.ts +0 -7
  84. package/src/auth/index.ts +0 -1
  85. package/src/components/AuthenticatorVerify.tsx +0 -75
  86. package/src/components/FirebaseSignIn.tsx +0 -234
  87. package/src/components/PhoneVerify.tsx +0 -115
  88. package/src/components/TwoFactorAuthModal.tsx +0 -198
  89. package/src/components/index.ts +0 -2
  90. package/src/contexts/FirebaseContext.tsx +0 -50
  91. package/src/contexts/index.ts +0 -1
  92. package/src/db/index.ts +0 -1
  93. package/src/db/utils.ts +0 -142
  94. package/src/hooks/backend.ts +0 -4
  95. package/src/hooks/index.ts +0 -1
  96. package/src/hooks/useAuthenticatorVerify.ts +0 -45
  97. package/src/hooks/usePhoneVerify.ts +0 -87
  98. package/src/icons/Apple.tsx +0 -12
  99. package/src/icons/Google.tsx +0 -24
  100. package/src/index.ts +0 -9
  101. package/src/storage/index.ts +0 -1
  102. package/src/storage/utils.ts +0 -29
  103. package/src/types/adapter.ts +0 -13
  104. package/src/types/auth.ts +0 -13
  105. package/src/types/db.ts +0 -10
  106. package/src/types/functions.ts +0 -3
  107. package/src/types/index.ts +0 -29
  108. package/src/types/storage.ts +0 -3
  109. package/src/utils/validation.ts +0 -92
@@ -1,32 +0,0 @@
1
- import { BackendAdapter, BaseAuthProvider } from '@chem-po/core'
2
- import { FirebaseStorageTypes } from '@react-native-firebase/storage'
3
- import { Auth, EmailPasswordLogin, User } from '../types/auth'
4
- import { Firestore, FirestoreCursor } from '../types/db'
5
- import { Functions } from '../types/functions'
6
- import { Storage } from '../types/storage'
7
- import { getFirebaseAuthAdapter } from './auth'
8
- import { getFirebaseDatabaseAdapter } from './db'
9
- import { getFirebaseStorageAdapter } from './storage'
10
-
11
- export type FirebaseAdapter<AuthProvider extends BaseAuthProvider> = BackendAdapter<
12
- AuthProvider,
13
- User,
14
- EmailPasswordLogin,
15
- FirestoreCursor,
16
- Blob,
17
- FirebaseStorageTypes.FullMetadata
18
- >
19
-
20
- export const getFirebaseAdapter = <AuthProvider extends BaseAuthProvider>(
21
- auth: Auth,
22
- db: Firestore,
23
- storage: Storage,
24
- functions: Functions,
25
- twoFactorRequired: boolean,
26
- ): FirebaseAdapter<AuthProvider> => {
27
- return {
28
- auth: getFirebaseAuthAdapter(auth, twoFactorRequired),
29
- db: getFirebaseDatabaseAdapter(db, functions),
30
- storage: getFirebaseStorageAdapter(storage),
31
- }
32
- }
@@ -1,58 +0,0 @@
1
- import { StorageAdapter, UploadedFileValue } from '@chem-po/core'
2
- import {
3
- deleteObject,
4
- getDownloadURL,
5
- getMetadata,
6
- ref,
7
- uploadBytesResumable,
8
- } from '@react-native-firebase/storage'
9
- import { Storage } from '../types/storage'
10
-
11
- export const getFirebaseStorageAdapter = (storage: Storage): StorageAdapter<Blob, any> => ({
12
- delete: async path => {
13
- const storageRef = ref(storage, path)
14
- await deleteObject(storageRef)
15
- },
16
- fetchObject: async path => {
17
- const storageRef = ref(storage, path)
18
- const url = await getDownloadURL(storageRef)
19
- const response = await fetch(url)
20
- return await response.blob()
21
- },
22
- fetchMetadata: async path => {
23
- const storageRef = ref(storage, path)
24
- return await getMetadata(storageRef)
25
- },
26
- getObjectUrl: async path => {
27
- const storageRef = ref(storage, path)
28
- return await getDownloadURL(storageRef)
29
- },
30
- upload: async (path, data, onUploadProgress) => {
31
- const storageRef = ref(storage, path)
32
- // Convert dataUrl to Blob
33
- const blob = await fetch(data.dataUrl).then(res => res.blob())
34
- const uploadTask = uploadBytesResumable(storageRef, blob)
35
- return new Promise<UploadedFileValue>((resolve, reject) => {
36
- uploadTask.on(
37
- 'state_changed',
38
- snapshot => {
39
- const progress = snapshot.bytesTransferred / snapshot.totalBytes
40
- onUploadProgress({
41
- loaded: snapshot.bytesTransferred,
42
- total: snapshot.totalBytes,
43
- percent: progress,
44
- })
45
- },
46
- error => reject(error),
47
- () => {
48
- const fileValue: UploadedFileValue = {
49
- filename: data.filename,
50
- type: data.type,
51
- storagePath: path,
52
- }
53
- resolve(fileValue)
54
- },
55
- )
56
- })
57
- },
58
- })
@@ -1,7 +0,0 @@
1
- import { FirebaseFunctionsTypes } from '@react-native-firebase/functions'
2
-
3
- export const getThirdPartyAuthUrl = (functions: FirebaseFunctionsTypes.Module) =>
4
- functions.httpsCallable('getThirdPartyAuthUrl')
5
-
6
- export const getThirdPartyAuthToken = (functions: FirebaseFunctionsTypes.Module) =>
7
- functions.httpsCallable('getThirdPartyAuthToken')
package/src/auth/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from './functions'
@@ -1,75 +0,0 @@
1
- import { LoadingButton, Txt } from '@chem-po/react-native'
2
- import React from 'react'
3
- import { StyleSheet, TextInput, View } from 'react-native'
4
- import { useAuthenticatorVerify } from '../hooks/useAuthenticatorVerify'
5
-
6
- export const AuthenticatorVerify = () => {
7
- const { code, setCode, verifying, error, handleVerify } = useAuthenticatorVerify()
8
-
9
- return (
10
- <View style={styles.wrapper}>
11
- <View style={styles.container}>
12
- <Txt style={styles.text}>Enter the code on your authenticator app:</Txt>
13
- <TextInput
14
- style={styles.input}
15
- value={code}
16
- onChangeText={setCode}
17
- placeholder="Verification Code"
18
- keyboardType="number-pad"
19
- maxLength={6}
20
- autoFocus
21
- />
22
- {error ? <Txt style={styles.errorText}>{error}</Txt> : null}
23
- <LoadingButton style={styles.button} onPress={handleVerify} disabled={verifying}>
24
- <Txt style={styles.buttonText}>{verifying ? 'Verifying...' : 'Verify'}</Txt>
25
- </LoadingButton>
26
- </View>
27
- </View>
28
- )
29
- }
30
-
31
- const styles = StyleSheet.create({
32
- wrapper: {
33
- flex: 1,
34
- padding: 16,
35
- },
36
- container: {
37
- flex: 1,
38
- alignItems: 'center',
39
- justifyContent: 'center',
40
- gap: 16,
41
- },
42
- text: {
43
- fontSize: 16,
44
- textAlign: 'center',
45
- marginBottom: 8,
46
- },
47
- input: {
48
- width: '100%',
49
- height: 48,
50
- borderWidth: 1,
51
- borderColor: '#ccc',
52
- borderRadius: 8,
53
- paddingHorizontal: 16,
54
- fontSize: 16,
55
- marginBottom: 8,
56
- },
57
- button: {
58
- backgroundColor: '#007AFF',
59
- paddingHorizontal: 24,
60
- paddingVertical: 12,
61
- borderRadius: 8,
62
- minWidth: 200,
63
- alignItems: 'center',
64
- },
65
- buttonText: {
66
- color: 'white',
67
- fontSize: 16,
68
- fontWeight: '600',
69
- },
70
- errorText: {
71
- color: 'red',
72
- fontSize: 14,
73
- marginBottom: 8,
74
- },
75
- })
@@ -1,234 +0,0 @@
1
- import { useBackend } from '../hooks'
2
-
3
- import { AppleAuthProvider, GoogleAuthProvider, ThirdPartyAuthProvider } from '@chem-po/core'
4
- import { TextField, useBorderColor, useTextColor, useToast } from '@chem-po/react'
5
- import { LoadingButton, StandaloneInput, Txt } from '@chem-po/react-native'
6
- import { ButtonText } from '@chem-po/react-native/src/components/button/ButtonText'
7
- import appleAuth from '@invertase/react-native-apple-authentication'
8
- import React, { useCallback, useState } from 'react'
9
- import { StyleSheet, View } from 'react-native'
10
- import { Divider } from 'react-native-paper'
11
- import SvgApple from '../icons/Apple'
12
- import SvgGoogle from '../icons/Google'
13
-
14
- const emailField: TextField = {
15
- _type: 'text',
16
- type: 'email',
17
- placeholder: 'Email',
18
- }
19
-
20
- const passwordField: TextField = {
21
- _type: 'text',
22
- type: 'password',
23
- placeholder: 'Password',
24
- }
25
-
26
- const thirdPartyInfo: Record<
27
- ThirdPartyAuthProvider['name'],
28
- { icon: React.ReactNode; name: string }
29
- > = {
30
- google: { icon: <SvgGoogle width={24} />, name: 'Google' },
31
- apple: { icon: <SvgApple width={24} />, name: 'Apple' },
32
- }
33
-
34
- const ThirdPartyLogin = ({ provider }: { provider: GoogleAuthProvider | AppleAuthProvider }) => {
35
- const { auth } = useBackend()
36
- const { showError } = useToast()
37
-
38
- const handleSignIn = useCallback(() => {
39
- return auth.loginWithPopup(provider).catch(error => {
40
- showError(error instanceof Error ? error.message : 'An unknown error occurred')
41
- })
42
- }, [auth, provider, showError])
43
-
44
- const textColor = useTextColor(400)
45
- return (
46
- <View style={styles.row}>
47
- <LoadingButton
48
- color={textColor}
49
- variant="outline"
50
- style={[styles.googleLoginButton]}
51
- onPress={handleSignIn}>
52
- <View style={styles.googleLogin}>
53
- {thirdPartyInfo[provider.name].icon}
54
- <ButtonText
55
- variant="outline"
56
- color={textColor}>{`Log In with ${thirdPartyInfo[provider.name].name}`}</ButtonText>
57
- </View>
58
- </LoadingButton>
59
- </View>
60
- )
61
- }
62
-
63
- const EmailPasswordLogin = () => {
64
- const [email, setEmail] = useState('')
65
- const [password, setPassword] = useState('')
66
- const [error, setError] = useState<string | null>(null)
67
- const forgotPasswordTextColor = useTextColor(400)
68
-
69
- const { auth } = useBackend()
70
- const { showInfo } = useToast()
71
-
72
- const handleLogin = async () => {
73
- try {
74
- await auth.loginWithPassword({ name: 'email' }, { email, password })
75
- } catch (error) {
76
- setError(error instanceof Error ? error.message : 'An unknown error occurred')
77
- }
78
- }
79
-
80
- return (
81
- <View style={styles.column}>
82
- <StandaloneInput field={emailField} onChange={setEmail} value={email} />
83
- <StandaloneInput field={passwordField} onChange={setPassword} value={password} />
84
- {error && (
85
- <View style={styles.error}>
86
- <Txt style={styles.errorText}>{error}</Txt>
87
- </View>
88
- )}
89
- <View style={styles.row}>
90
- <View style={styles.forgotPassword}>
91
- <LoadingButton
92
- color={forgotPasswordTextColor}
93
- textStyle={styles.forgotPasswordButtonText}
94
- style={styles.forgotPasswordButton}
95
- size="sm"
96
- variant="outline"
97
- onPress={async () => {
98
- // console.log('press')
99
- showInfo('Visit our website to reset your password')
100
- }}>
101
- Forgot Password?
102
- </LoadingButton>
103
- </View>
104
- <LoadingButton onPress={() => handleLogin()}>Sign In</LoadingButton>
105
- </View>
106
- </View>
107
- )
108
- }
109
-
110
- const ThirdPartyLogins = ({
111
- appleProvider,
112
- googleProvider,
113
- }: {
114
- appleProvider?: AppleAuthProvider
115
- googleProvider?: GoogleAuthProvider
116
- }) => {
117
- const borderColor = useBorderColor()
118
- const hasApple = appleProvider && appleAuth.isSupported
119
- if (!googleProvider && !hasApple) return null
120
- return (
121
- <>
122
- <Divider style={{ backgroundColor: borderColor, width: '100%' }} />
123
- <View style={styles.thirdPartyLogins}>
124
- {googleProvider ? <ThirdPartyLogin provider={googleProvider} /> : null}
125
- {appleProvider && appleAuth.isSupported ? (
126
- <ThirdPartyLogin provider={appleProvider} />
127
- ) : null}
128
- </View>
129
- </>
130
- )
131
- }
132
-
133
- export const FirebaseSignIn = ({
134
- googleProvider,
135
- appleProvider,
136
- }: {
137
- googleProvider?: GoogleAuthProvider
138
- appleProvider?: AppleAuthProvider
139
- }) => {
140
- return (
141
- <View style={styles.signInContent}>
142
- <EmailPasswordLogin />
143
- <ThirdPartyLogins appleProvider={appleProvider} googleProvider={googleProvider} />
144
- </View>
145
- )
146
- }
147
-
148
- const styles = StyleSheet.create({
149
- container: {
150
- flex: 1,
151
- width: '100%',
152
- justifyContent: 'center',
153
- alignItems: 'center',
154
- },
155
- column: {
156
- flexDirection: 'column',
157
- gap: 10,
158
- flex: 1,
159
- width: '100%',
160
- alignItems: 'center',
161
- justifyContent: 'center',
162
- },
163
- thirdPartyLogins: {
164
- flexDirection: 'column',
165
- gap: 10,
166
- flex: 1,
167
- width: '100%',
168
- alignItems: 'center',
169
- justifyContent: 'center',
170
- },
171
- colorModeToggle: {
172
- paddingVertical: 20,
173
- },
174
- signInContent: {
175
- paddingVertical: 20,
176
- paddingHorizontal: 20,
177
- gap: 12,
178
- justifyContent: 'center',
179
- alignItems: 'center',
180
- width: '100%',
181
- },
182
- forgotPasswordButton: {
183
- borderWidth: 0,
184
- backgroundColor: 'transparent',
185
- },
186
- forgotPasswordButtonText: {
187
- fontSize: 14,
188
- },
189
- row: {
190
- flexDirection: 'row',
191
- justifyContent: 'space-between',
192
- alignItems: 'center',
193
- width: '100%',
194
- },
195
- forgotPassword: {
196
- // flex: 1,
197
- },
198
- header: {
199
- fontSize: 16,
200
- opacity: 0.7,
201
- fontWeight: 'bold',
202
- },
203
- infoText: {
204
- fontSize: 16,
205
- textAlign: 'center',
206
- // fontFamily: fontFamilies.body.regular,
207
- paddingBottom: 20,
208
- },
209
- logo: {
210
- height: 50,
211
- resizeMode: 'contain',
212
- },
213
- link: {
214
- fontSize: 14,
215
- // fontFamily: fontFamilies.body.regular,
216
- textDecorationLine: 'underline',
217
- fontWeight: 'semibold',
218
- },
219
- googleLogin: {
220
- flexDirection: 'row',
221
- alignItems: 'center',
222
- justifyContent: 'center',
223
- gap: 10,
224
- width: '100%',
225
- },
226
- googleLoginButton: {
227
- width: '100%',
228
- },
229
- error: {},
230
- errorText: {
231
- fontSize: 12,
232
- color: 'red',
233
- },
234
- })
@@ -1,115 +0,0 @@
1
- import { formatPhoneNumber, PhoneEnrollmentFactor } from '@chem-po/core'
2
- import { useAuth, useBorderColor, useButtonColor, usePlaceholderColor, useTextColor } from '@chem-po/react'
3
- import { CircularProgress, LoadingButton, Txt } from '@chem-po/react-native'
4
- import React, { useMemo } from 'react'
5
- import { StyleSheet, TextInput, View } from 'react-native'
6
- import { usePhoneVerify } from '../hooks/usePhoneVerify'
7
-
8
- // UI to send code and verify code
9
- export const PhoneVerify = ({ factor }: { factor: PhoneEnrollmentFactor }) => {
10
- const { handleVerify, verifying, error, code, setCode, sendCode, sendingCode } = usePhoneVerify(factor, true)
11
- const { multiFactorVerification: twoFactorVerification, multiFactorLoading: loading } = useAuth()
12
- const buttonBackgroundColor = useButtonColor()
13
- const borderColor = useBorderColor()
14
- const textColor = useTextColor()
15
- const placeholderColor = usePlaceholderColor()
16
-
17
- const verificationId = twoFactorVerification?.verificationId
18
- const formattedPhoneNumber = useMemo(
19
- () =>
20
- Number.isNaN(Number(factor.phoneNumber))
21
- ? factor.phoneNumber
22
- : formatPhoneNumber(factor.phoneNumber),
23
- [factor.phoneNumber]
24
- )
25
-
26
- let body: React.ReactNode = null
27
-
28
- if (sendingCode) {
29
- body = (
30
- <View style={styles.container}>
31
- <CircularProgress size='large' />
32
- <Txt style={styles.text}>Sending verification code...</Txt>
33
- </View>
34
- )
35
- } else if (verificationId || verifying) {
36
- body = (
37
- <View style={styles.container}>
38
- <Txt style={styles.text}>Enter the code sent to your phone:</Txt>
39
- <TextInput
40
- style={[styles.input, { borderColor, color: textColor }]}
41
- value={code}
42
- placeholderTextColor={placeholderColor}
43
- onChangeText={setCode}
44
- placeholder='Verification Code'
45
- keyboardType='number-pad'
46
- maxLength={6}
47
- />
48
- {error ? <Txt style={styles.errorText}>{error}</Txt> : null}
49
- <LoadingButton variant='solid' onPress={handleVerify} color={buttonBackgroundColor}>
50
- Verify
51
- </LoadingButton>
52
- </View>
53
- )
54
- } else {
55
- body = (
56
- <View style={styles.container}>
57
- <View style={styles.textContainer}>
58
- <Txt style={styles.infoText}>We'll send a verification code to:</Txt>
59
- <Txt style={styles.text}>{formattedPhoneNumber}</Txt>
60
- </View>
61
- <LoadingButton variant='solid' onPress={sendCode} disabled={loading} color={buttonBackgroundColor}>
62
- Send Verification Code
63
- </LoadingButton>
64
- </View>
65
- )
66
- }
67
-
68
- return <View style={styles.wrapper}>{body}</View>
69
- }
70
-
71
- const styles = StyleSheet.create({
72
- wrapper: {
73
- flex: 1,
74
- padding: 16,
75
- },
76
- container: {
77
- flex: 1,
78
- alignItems: 'center',
79
- justifyContent: 'center',
80
- gap: 8,
81
- },
82
- textContainer: {
83
- alignItems: 'center',
84
- justifyContent: 'center',
85
- gap: 4,
86
- },
87
- infoText: {
88
- fontSize: 15,
89
- opacity: 0.8,
90
- textAlign: 'center',
91
- },
92
- text: {
93
- fontSize: 16,
94
- textAlign: 'center',
95
- marginBottom: 8,
96
- },
97
- input: {
98
- width: '100%',
99
- height: 48,
100
- borderWidth: 1,
101
- borderRadius: 8,
102
- paddingHorizontal: 16,
103
- fontSize: 16,
104
- marginBottom: 8,
105
- },
106
- buttonText: {
107
- fontSize: 16,
108
- fontWeight: '600',
109
- },
110
- errorText: {
111
- color: 'red',
112
- fontSize: 14,
113
- marginBottom: 8,
114
- },
115
- })