@xouteiro/auth_npm 1.0.13 → 1.0.15

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xouteiro/auth_npm",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Authentication package for Supabase",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -17,7 +17,8 @@
17
17
  "dependencies": {
18
18
  "@supabase/auth-ui-react": "^0.4.7",
19
19
  "@supabase/auth-ui-shared": "^0.1.8",
20
- "@supabase/supabase-js": "^2.52.1"
20
+ "@supabase/supabase-js": "^2.52.1",
21
+ "react-native": "^0.81.4"
21
22
  },
22
23
  "devDependencies": {
23
24
  "@types/react": "^19.1.9",
@@ -1,96 +1,150 @@
1
1
  import React, { useState } from 'react';
2
- import { signInWithEmail } from '../login';
2
+ import {
3
+ View,
4
+ Text,
5
+ TextInput,
6
+ TouchableOpacity,
7
+ StyleSheet,
8
+ KeyboardAvoidingView,
9
+ Platform,
10
+ ScrollView,
11
+ } from 'react-native';
12
+ import { registerWithEmail } from '../register';
3
13
 
4
- const boxStyle = {
5
- maxWidth: 350,
6
- margin: '40px auto',
7
- padding: 28,
8
- borderRadius: 12,
9
- boxShadow: '0 2px 12px rgba(0,0,0,0.08)',
10
- background: '#fff',
11
- fontFamily: 'sans-serif',
12
- };
13
-
14
- const inputStyle = {
15
- width: '100%',
16
- padding: 10,
17
- margin: '10px 0',
18
- borderRadius: 6,
19
- border: '1px solid #ddd',
20
- fontSize: 16,
21
- };
22
-
23
- const buttonStyle = {
24
- width: '100%',
25
- padding: 12,
26
- borderRadius: 6,
27
- border: 'none',
28
- background: '#0070f3',
29
- color: '#fff',
30
- fontWeight: 600,
31
- fontSize: 16,
32
- marginTop: 10,
33
- cursor: 'pointer',
34
- };
35
-
36
- const messageStyle = (success) => ({
37
- margin: '12px 0',
38
- color: success ? '#0a0' : '#d32f2f',
39
- background: success ? '#eafbe7' : '#fdeaea',
40
- padding: 8,
41
- borderRadius: 6,
42
- textAlign: 'center',
43
- fontSize: 15,
44
- });
45
-
46
- export default function LoginOnly() {
47
- const [identifier, setIdentifier] = useState('');
14
+ export default function RegisterOnly() {
15
+ const [email, setEmail] = useState('');
48
16
  const [password, setPassword] = useState('');
17
+ const [username, setUsername] = useState('');
18
+ const [phone, setPhone] = useState('');
49
19
  const [message, setMessage] = useState(null);
50
20
  const [success, setSuccess] = useState(false);
51
21
 
52
- const handleLogin = async (e) => {
53
- e.preventDefault();
22
+ const handleRegister = async () => {
54
23
  setMessage(null);
55
24
  setSuccess(false);
56
- const { error } = await signInWithEmail(identifier, password);
25
+ const { error } = await registerWithEmail(email, password, username, phone);
57
26
  if (error) {
58
- setMessage(error.message || 'Login failed');
27
+ setMessage(error.message || 'Registration failed');
59
28
  setSuccess(false);
60
29
  } else {
61
- setMessage('Login successful!');
30
+ setMessage('Registration successful! Please check your email to confirm.');
62
31
  setSuccess(true);
63
32
  setTimeout(() => {
64
- setIdentifier('');
33
+ setEmail('');
65
34
  setPassword('');
35
+ setUsername('');
36
+ setPhone('');
66
37
  setMessage(null);
67
38
  setSuccess(false);
68
- }, 1500);
39
+ }, 2000);
69
40
  }
70
41
  };
71
42
 
72
43
  return (
73
- <div style={boxStyle}>
74
- <form onSubmit={handleLogin}>
75
- <input
76
- style={inputStyle}
77
- type="text"
78
- placeholder="Email, phone, or username"
79
- value={identifier}
80
- onChange={e => setIdentifier(e.target.value)}
81
- required
82
- />
83
- <input
84
- style={inputStyle}
85
- type="password"
86
- placeholder="Password"
87
- value={password}
88
- onChange={e => setPassword(e.target.value)}
89
- required
90
- />
91
- <button style={buttonStyle} type="submit">Login</button>
92
- </form>
93
- {message && <div style={messageStyle(success)}>{message}</div>}
94
- </div>
44
+ <KeyboardAvoidingView
45
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
46
+ style={styles.container}
47
+ >
48
+ <ScrollView contentContainerStyle={styles.scroll}>
49
+ <View style={styles.box}>
50
+ <TextInput
51
+ style={styles.input}
52
+ placeholder="Email"
53
+ value={email}
54
+ onChangeText={setEmail}
55
+ autoCapitalize="none"
56
+ keyboardType="email-address"
57
+ />
58
+ <TextInput
59
+ style={styles.input}
60
+ placeholder="Password"
61
+ value={password}
62
+ onChangeText={setPassword}
63
+ secureTextEntry
64
+ />
65
+ <TextInput
66
+ style={styles.input}
67
+ placeholder="Username (optional)"
68
+ value={username}
69
+ onChangeText={setUsername}
70
+ />
71
+ <TextInput
72
+ style={styles.input}
73
+ placeholder="Phone (optional)"
74
+ value={phone}
75
+ onChangeText={setPhone}
76
+ keyboardType="phone-pad"
77
+ />
78
+ <TouchableOpacity style={styles.button} onPress={handleRegister}>
79
+ <Text style={styles.buttonText}>Register</Text>
80
+ </TouchableOpacity>
81
+ {message && (
82
+ <View style={[styles.message, success ? styles.success : styles.error]}>
83
+ <Text style={styles.messageText}>{message}</Text>
84
+ </View>
85
+ )}
86
+ </View>
87
+ </ScrollView>
88
+ </KeyboardAvoidingView>
95
89
  );
96
- }
90
+ }
91
+
92
+ const styles = StyleSheet.create({
93
+ container: {
94
+ flex: 1,
95
+ backgroundColor: '#f5f5f5',
96
+ },
97
+ scroll: {
98
+ flexGrow: 1,
99
+ justifyContent: 'center',
100
+ paddingHorizontal: 24,
101
+ },
102
+ box: {
103
+ padding: 28,
104
+ borderRadius: 12,
105
+ backgroundColor: '#fff',
106
+ shadowColor: '#000',
107
+ shadowOpacity: 0.08,
108
+ shadowRadius: 12,
109
+ elevation: 4,
110
+ },
111
+ input: {
112
+ width: '100%',
113
+ padding: 10,
114
+ marginVertical: 10,
115
+ borderRadius: 6,
116
+ borderWidth: 1,
117
+ borderColor: '#ddd',
118
+ fontSize: 16,
119
+ },
120
+ button: {
121
+ width: '100%',
122
+ padding: 12,
123
+ borderRadius: 6,
124
+ backgroundColor: '#0070f3',
125
+ marginTop: 10,
126
+ alignItems: 'center',
127
+ },
128
+ buttonText: {
129
+ color: '#fff',
130
+ fontWeight: '600',
131
+ fontSize: 16,
132
+ },
133
+ message: {
134
+ marginTop: 12,
135
+ padding: 8,
136
+ borderRadius: 6,
137
+ alignItems: 'center',
138
+ },
139
+ success: {
140
+ backgroundColor: '#eafbe7',
141
+ },
142
+ error: {
143
+ backgroundColor: '#fdeaea',
144
+ },
145
+ messageText: {
146
+ fontSize: 15,
147
+ color: '#333',
148
+ textAlign: 'center',
149
+ },
150
+ });
@@ -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
+ });