@xouteiro/auth_npm 1.0.13 → 1.0.17

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.
@@ -1,156 +1,14 @@
1
1
  import React, { useState } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TextInput,
6
+ TouchableOpacity,
7
+ StyleSheet,
8
+ } from 'react-native';
2
9
  import { signInWithEmail } from '../login';
3
10
  import { registerWithEmail } from '../register';
4
11
 
5
- // SVG Eye Icon
6
- const EyeIcon = ({ open }) => (
7
- <svg
8
- width="22"
9
- height="22"
10
- viewBox="0 0 22 22"
11
- fill="none"
12
- style={{ verticalAlign: 'middle' }}
13
- xmlns="http://www.w3.org/2000/svg"
14
- >
15
- {open ? (
16
- <>
17
- <path
18
- d="M1 11C3.5 5.5 11 2 21 11C18.5 16.5 11 20 1 11Z"
19
- stroke="#667eea"
20
- strokeWidth="2"
21
- fill="none"
22
- />
23
- <circle
24
- cx="11"
25
- cy="11"
26
- r="3"
27
- stroke="#667eea"
28
- strokeWidth="2"
29
- fill="none"
30
- />
31
- </>
32
- ) : (
33
- <>
34
- <path
35
- d="M1 11C3.5 5.5 11 2 21 11C18.5 16.5 11 20 1 11Z"
36
- stroke="#667eea"
37
- strokeWidth="2"
38
- fill="none"
39
- />
40
- <circle
41
- cx="11"
42
- cy="11"
43
- r="3"
44
- stroke="#667eea"
45
- strokeWidth="2"
46
- fill="none"
47
- />
48
- <line
49
- x1="4"
50
- y1="18"
51
- x2="18"
52
- y2="4"
53
- stroke="#d32f2f"
54
- strokeWidth="2"
55
- />
56
- </>
57
- )}
58
- </svg>
59
- );
60
-
61
- const boxStyle = {
62
- maxWidth: 400,
63
- margin: '0 auto',
64
- padding: 32,
65
- borderRadius: 20,
66
- boxShadow: '0 8px 32px rgba(102, 126, 234, 0.15)',
67
- background: 'rgba(255, 255, 255, 0.98)',
68
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
69
- backdropFilter: 'blur(10px)',
70
- border: '1px solid rgba(255, 255, 255, 0.2)',
71
- };
72
-
73
- const tabStyle = (active) => ({
74
- flex: 1,
75
- padding: 16,
76
- border: 'none',
77
- borderBottom: active ? '3px solid #667eea' : '3px solid rgba(255, 255, 255, 0.3)',
78
- background: 'none',
79
- fontWeight: active ? 700 : 500,
80
- color: active ? '#667eea' : 'rgba(0, 0, 0, 0.6)',
81
- cursor: 'pointer',
82
- outline: 'none',
83
- fontSize: 16,
84
- transition: 'all 0.3s ease',
85
- letterSpacing: '0.5px',
86
- });
87
-
88
- const inputStyle = {
89
- width: '100%',
90
- padding: '16px 44px 16px 16px',
91
- margin: '12px 0',
92
- borderRadius: 12,
93
- border: '2px solid rgba(102, 126, 234, 0.2)',
94
- fontSize: 16,
95
- background: 'rgba(248, 250, 252, 0.8)',
96
- boxSizing: 'border-box',
97
- outline: 'none',
98
- transition: 'all 0.3s ease',
99
- fontWeight: '500',
100
- };
101
-
102
- const buttonStyle = {
103
- width: '100%',
104
- padding: 16,
105
- borderRadius: 12,
106
- border: 'none',
107
- background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
108
- color: '#fff',
109
- fontWeight: 700,
110
- fontSize: 16,
111
- marginTop: 20,
112
- cursor: 'pointer',
113
- letterSpacing: '0.5px',
114
- boxShadow: '0 8px 24px rgba(102, 126, 234, 0.3)',
115
- transition: 'all 0.3s ease',
116
- transform: 'translateY(0)',
117
- };
118
-
119
- const toggleButtonStyle = {
120
- position: 'absolute',
121
- right: 12,
122
- top: '50%',
123
- transform: 'translateY(-50%)',
124
- background: 'none',
125
- border: 'none',
126
- color: '#667eea',
127
- cursor: 'pointer',
128
- fontSize: 18,
129
- padding: 4,
130
- display: 'flex',
131
- alignItems: 'center',
132
- borderRadius: 6,
133
- transition: 'all 0.2s ease',
134
- };
135
-
136
- const inputWrapperStyle = {
137
- position: 'relative',
138
- width: '100%',
139
- };
140
-
141
- const messageStyle = (success) => ({
142
- margin: '16px 0 0 0',
143
- color: success ? '#22c55e' : '#ef4444',
144
- background: success ? 'rgba(34, 197, 94, 0.1)' : 'rgba(239, 68, 68, 0.1)',
145
- padding: 12,
146
- borderRadius: 12,
147
- textAlign: 'center',
148
- fontSize: 14,
149
- fontWeight: 600,
150
- letterSpacing: '0.5px',
151
- border: success ? '1px solid rgba(34, 197, 94, 0.2)' : '1px solid rgba(239, 68, 68, 0.2)',
152
- });
153
-
154
12
  export default function LoginRegisterFlow({ onLoginSuccess, onRegisterSuccess }) {
155
13
  const [mode, setMode] = useState('login');
156
14
  const [identifier, setIdentifier] = useState('');
@@ -159,8 +17,6 @@ export default function LoginRegisterFlow({ onLoginSuccess, onRegisterSuccess })
159
17
  const [displayName, setDisplayName] = useState('');
160
18
  const [message, setMessage] = useState(null);
161
19
  const [success, setSuccess] = useState(false);
162
- const [showPassword, setShowPassword] = useState(false);
163
- const [showConfirmPassword, setShowConfirmPassword] = useState(false);
164
20
 
165
21
  const resetFields = () => {
166
22
  setIdentifier('');
@@ -169,14 +25,9 @@ export default function LoginRegisterFlow({ onLoginSuccess, onRegisterSuccess })
169
25
  setDisplayName('');
170
26
  setMessage(null);
171
27
  setSuccess(false);
172
- setShowPassword(false);
173
- setShowConfirmPassword(false);
174
28
  };
175
29
 
176
- const handleLogin = async (e) => {
177
- e.preventDefault();
178
- setMessage(null);
179
- setSuccess(false);
30
+ const handleLogin = async () => {
180
31
  const { session, error } = await signInWithEmail(identifier, password);
181
32
  if (error) {
182
33
  setMessage(error.message || 'Login failed');
@@ -184,15 +35,12 @@ export default function LoginRegisterFlow({ onLoginSuccess, onRegisterSuccess })
184
35
  } else {
185
36
  setMessage('Login successful!');
186
37
  setSuccess(true);
187
- if (onLoginSuccess) onLoginSuccess(session);
38
+ onLoginSuccess?.(session);
188
39
  setTimeout(resetFields, 1200);
189
40
  }
190
41
  };
191
42
 
192
- const handleRegister = async (e) => {
193
- e.preventDefault();
194
- setMessage(null);
195
- setSuccess(false);
43
+ const handleRegister = async () => {
196
44
  if (password !== confirmPassword) {
197
45
  setMessage("Passwords do not match");
198
46
  setSuccess(false);
@@ -203,116 +51,142 @@ export default function LoginRegisterFlow({ onLoginSuccess, onRegisterSuccess })
203
51
  setMessage(error.message || 'Registration failed');
204
52
  setSuccess(false);
205
53
  } else {
206
- setMessage('Registration successful! Please check your email to confirm.');
54
+ setMessage('Registration successful! Please check your email.');
207
55
  setSuccess(true);
208
- if (onRegisterSuccess) onRegisterSuccess(user);
56
+ onRegisterSuccess?.(user);
209
57
  setTimeout(resetFields, 2000);
210
58
  }
211
59
  };
212
60
 
213
61
  return (
214
- <div style={boxStyle}>
215
- <div style={{ display: 'flex', marginBottom: 28 }}>
216
- <button style={tabStyle(mode === 'login')} onClick={() => { setMode('login'); setMessage(null); }}>Login</button>
217
- <button style={tabStyle(mode === 'register')} onClick={() => { setMode('register'); setMessage(null); }}>Register</button>
218
- </div>
62
+ <View style={styles.container}>
63
+ <View style={styles.tabContainer}>
64
+ <TouchableOpacity onPress={() => setMode('login')} style={[styles.tab, mode === 'login' && styles.activeTab]}>
65
+ <Text style={styles.tabText}>Login</Text>
66
+ </TouchableOpacity>
67
+ <TouchableOpacity onPress={() => setMode('register')} style={[styles.tab, mode === 'register' && styles.activeTab]}>
68
+ <Text style={styles.tabText}>Register</Text>
69
+ </TouchableOpacity>
70
+ </View>
71
+
219
72
  {mode === 'login' ? (
220
- <form onSubmit={handleLogin} autoComplete="off">
221
- <input
222
- style={inputStyle}
223
- type="text"
73
+ <View>
74
+ <TextInput
75
+ style={styles.input}
224
76
  placeholder="Email"
225
77
  value={identifier}
226
- onChange={e => setIdentifier(e.target.value)}
227
- required
228
- autoComplete="username"
78
+ onChangeText={setIdentifier}
79
+ />
80
+ <TextInput
81
+ style={styles.input}
82
+ placeholder="Password"
83
+ value={password}
84
+ onChangeText={setPassword}
85
+ secureTextEntry
229
86
  />
230
- <div style={inputWrapperStyle}>
231
- <input
232
- style={inputStyle}
233
- type={showPassword ? "text" : "password"}
234
- placeholder="Password"
235
- value={password}
236
- onChange={e => setPassword(e.target.value)}
237
- required
238
- autoComplete="current-password"
239
- />
240
- <button
241
- type="button"
242
- style={toggleButtonStyle}
243
- tabIndex={-1}
244
- aria-label={showPassword ? "Hide password" : "Show password"}
245
- onClick={() => setShowPassword(v => !v)}
246
- >
247
- <EyeIcon open={showPassword} />
248
- </button>
249
- </div>
250
- <button style={buttonStyle} type="submit">Login</button>
251
- </form>
87
+ <TouchableOpacity style={styles.button} onPress={handleLogin}>
88
+ <Text style={styles.buttonText}>Login</Text>
89
+ </TouchableOpacity>
90
+ </View>
252
91
  ) : (
253
- <form onSubmit={handleRegister} autoComplete="off">
254
- <input
255
- style={inputStyle}
256
- type="text"
92
+ <View>
93
+ <TextInput
94
+ style={styles.input}
257
95
  placeholder="Display Name"
258
96
  value={displayName}
259
- onChange={e => setDisplayName(e.target.value)}
260
- required
261
- autoComplete="name"
97
+ onChangeText={setDisplayName}
262
98
  />
263
- <input
264
- style={inputStyle}
265
- type="text"
99
+ <TextInput
100
+ style={styles.input}
266
101
  placeholder="Email"
267
102
  value={identifier}
268
- onChange={e => setIdentifier(e.target.value)}
269
- required
270
- autoComplete="username"
103
+ onChangeText={setIdentifier}
104
+ />
105
+ <TextInput
106
+ style={styles.input}
107
+ placeholder="Password"
108
+ value={password}
109
+ onChangeText={setPassword}
110
+ secureTextEntry
271
111
  />
272
- <div style={inputWrapperStyle}>
273
- <input
274
- style={inputStyle}
275
- type={showPassword ? "text" : "password"}
276
- placeholder="Password"
277
- value={password}
278
- onChange={e => setPassword(e.target.value)}
279
- required
280
- autoComplete="new-password"
281
- />
282
- <button
283
- type="button"
284
- style={toggleButtonStyle}
285
- tabIndex={-1}
286
- aria-label={showPassword ? "Hide password" : "Show password"}
287
- onClick={() => setShowPassword(v => !v)}
288
- >
289
- <EyeIcon open={showPassword} />
290
- </button>
291
- </div>
292
- <div style={inputWrapperStyle}>
293
- <input
294
- style={inputStyle}
295
- type={showConfirmPassword ? "text" : "password"}
296
- placeholder="Confirm Password"
297
- value={confirmPassword}
298
- onChange={e => setConfirmPassword(e.target.value)}
299
- required
300
- autoComplete="new-password"
301
- />
302
- <button
303
- type="button"
304
- style={toggleButtonStyle}
305
- tabIndex={-1}
306
- aria-label={showConfirmPassword ? "Hide confirm password" : "Show confirm password"}
307
- onClick={() => setShowConfirmPassword(v => !v)}
308
- >
309
- <EyeIcon open={showConfirmPassword} />
310
- </button>
311
- </div>
312
- <button style={buttonStyle} type="submit">Register</button>
313
- </form>
112
+ <TextInput
113
+ style={styles.input}
114
+ placeholder="Confirm Password"
115
+ value={confirmPassword}
116
+ onChangeText={setConfirmPassword}
117
+ secureTextEntry
118
+ />
119
+ <TouchableOpacity style={styles.button} onPress={handleRegister}>
120
+ <Text style={styles.buttonText}>Register</Text>
121
+ </TouchableOpacity>
122
+ </View>
123
+ )}
124
+
125
+ {message && (
126
+ <View style={[styles.message, success ? styles.success : styles.error]}>
127
+ <Text style={styles.messageText}>{message}</Text>
128
+ </View>
314
129
  )}
315
- {message && <div style={messageStyle(success)}>{message}</div>}
316
- </div>
130
+ </View>
317
131
  );
318
- }
132
+ }
133
+
134
+ const styles = StyleSheet.create({
135
+ container: {
136
+ padding: 24,
137
+ borderRadius: 12,
138
+ backgroundColor: '#fff',
139
+ margin: 16,
140
+ },
141
+ tabContainer: {
142
+ flexDirection: 'row',
143
+ marginBottom: 16,
144
+ },
145
+ tab: {
146
+ flex: 1,
147
+ padding: 12,
148
+ borderBottomWidth: 2,
149
+ borderColor: '#ccc',
150
+ alignItems: 'center',
151
+ },
152
+ activeTab: {
153
+ borderColor: '#667eea',
154
+ },
155
+ tabText: {
156
+ fontWeight: 'bold',
157
+ color: '#667eea',
158
+ },
159
+ input: {
160
+ borderWidth: 1,
161
+ borderColor: '#ccc',
162
+ borderRadius: 8,
163
+ padding: 12,
164
+ marginBottom: 12,
165
+ },
166
+ button: {
167
+ backgroundColor: '#667eea',
168
+ padding: 14,
169
+ borderRadius: 8,
170
+ alignItems: 'center',
171
+ marginTop: 8,
172
+ },
173
+ buttonText: {
174
+ color: '#fff',
175
+ fontWeight: 'bold',
176
+ },
177
+ message: {
178
+ padding: 12,
179
+ borderRadius: 8,
180
+ marginTop: 16,
181
+ },
182
+ success: {
183
+ backgroundColor: '#eafbe7',
184
+ },
185
+ error: {
186
+ backgroundColor: '#fdeaea',
187
+ },
188
+ messageText: {
189
+ textAlign: 'center',
190
+ color: '#333',
191
+ },
192
+ });
@@ -1,64 +1,78 @@
1
1
  import React, { useState } from 'react';
2
+ import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
2
3
  import { logout } from '../logout';
3
4
 
4
- const boxStyle = {
5
- maxWidth: 350,
6
- margin: '24px auto',
7
- padding: 20,
8
- borderRadius: 10,
9
- boxShadow: '0 2px 12px rgba(0,0,0,0.08)',
10
- background: '#fff',
11
- fontFamily: 'sans-serif',
12
- textAlign: 'center',
13
- };
14
-
15
- const buttonStyle = {
16
- padding: '10px 28px',
17
- borderRadius: 6,
18
- border: 'none',
19
- background: '#0070f3',
20
- color: '#fff',
21
- fontWeight: 600,
22
- fontSize: 16,
23
- cursor: 'pointer',
24
- };
25
-
26
- const messageStyle = (success) => ({
27
- margin: '12px 0',
28
- color: success ? '#0a0' : '#d32f2f',
29
- background: success ? '#eafbe7' : '#fdeaea',
30
- padding: 8,
31
- borderRadius: 6,
32
- textAlign: 'center',
33
- fontSize: 15,
34
- });
35
-
36
5
  export default function LogoutButton({ onLogout }) {
37
- const [message, setMessage] = useState(null);
38
- const [success, setSuccess] = useState(false);
39
-
40
- const handleLogout = async () => {
41
- setMessage(null);
6
+ const [message, setMessage] = useState(null);
7
+ const [success, setSuccess] = useState(false);
8
+
9
+ const handleLogout = async () => {
10
+ setMessage(null);
11
+ setSuccess(false);
12
+ const { error } = await logout();
13
+ if (error) {
14
+ setMessage(error.message || 'Logout failed');
42
15
  setSuccess(false);
43
- const { error } = await logout();
44
- if (error) {
45
- setMessage(error.message || 'Logout failed');
16
+ } else {
17
+ setMessage('Logout successful!');
18
+ setSuccess(true);
19
+ setTimeout(() => {
20
+ setMessage(null);
46
21
  setSuccess(false);
47
- } else {
48
- setMessage('Logout successful!');
49
- setSuccess(true);
50
- setTimeout(() => {
51
- setMessage(null);
52
- setSuccess(false);
53
- if (onLogout) onLogout(); // Call the callback after logout
54
- }, 1500);
55
- }
56
- };
57
-
58
- return (
59
- <div style={boxStyle}>
60
- <button style={buttonStyle} onClick={handleLogout}>Logout</button>
61
- {message && <div style={messageStyle(success)}>{message}</div>}
62
- </div>
63
- );
64
- }
22
+ if (onLogout) onLogout();
23
+ }, 1500);
24
+ }
25
+ };
26
+
27
+ return (
28
+ <View style={styles.box}>
29
+ <TouchableOpacity style={styles.button} onPress={handleLogout}>
30
+ <Text style={styles.buttonText}>Logout</Text>
31
+ </TouchableOpacity>
32
+ {message && (
33
+ <View style={[styles.message, success ? styles.success : styles.error]}>
34
+ <Text style={styles.messageText}>{message}</Text>
35
+ </View>
36
+ )}
37
+ </View>
38
+ );
39
+ }
40
+
41
+ const styles = StyleSheet.create({
42
+ box: {
43
+ maxWidth: 350,
44
+ marginVertical: 24,
45
+ padding: 20,
46
+ borderRadius: 10,
47
+ backgroundColor: '#fff',
48
+ alignSelf: 'center',
49
+ alignItems: 'center',
50
+ },
51
+ button: {
52
+ paddingVertical: 10,
53
+ paddingHorizontal: 28,
54
+ borderRadius: 6,
55
+ backgroundColor: '#0070f3',
56
+ },
57
+ buttonText: {
58
+ color: '#fff',
59
+ fontWeight: '600',
60
+ fontSize: 16,
61
+ },
62
+ message: {
63
+ marginTop: 12,
64
+ padding: 8,
65
+ borderRadius: 6,
66
+ },
67
+ success: {
68
+ backgroundColor: '#eafbe7',
69
+ },
70
+ error: {
71
+ backgroundColor: '#fdeaea',
72
+ },
73
+ messageText: {
74
+ fontSize: 15,
75
+ textAlign: 'center',
76
+ color: '#333',
77
+ },
78
+ });