@xouteiro/auth_npm 1.0.6 → 1.0.8
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/README.md +2 -0
- package/dist/index.js +433 -64
- package/dist/index.mjs +430 -63
- package/package.json +1 -1
- package/src/components/LoginOnly.jsx +96 -0
- package/src/components/LoginRegisterFlow.jsx +171 -0
- package/src/components/LogoutButton.jsx +63 -0
- package/src/components/RegisterOnly.jsx +114 -0
- package/src/index.js +6 -3
- package/src/AuthWrapper.jsx +0 -39
- package/src/LogoutButton.jsx +0 -12
@@ -0,0 +1,171 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { signInWithEmail } from '../login';
|
3
|
+
import { registerWithEmail } from '../register';
|
4
|
+
|
5
|
+
const boxStyle = {
|
6
|
+
maxWidth: 380,
|
7
|
+
margin: '40px auto',
|
8
|
+
padding: 32,
|
9
|
+
borderRadius: 14,
|
10
|
+
boxShadow: '0 2px 16px rgba(0,0,0,0.09)',
|
11
|
+
background: '#fff',
|
12
|
+
fontFamily: 'sans-serif',
|
13
|
+
};
|
14
|
+
|
15
|
+
const tabStyle = (active) => ({
|
16
|
+
flex: 1,
|
17
|
+
padding: 12,
|
18
|
+
border: 'none',
|
19
|
+
borderBottom: active ? '3px solid #0070f3' : '3px solid #eee',
|
20
|
+
background: 'none',
|
21
|
+
fontWeight: active ? 700 : 400,
|
22
|
+
color: active ? '#0070f3' : '#444',
|
23
|
+
cursor: 'pointer',
|
24
|
+
outline: 'none',
|
25
|
+
});
|
26
|
+
|
27
|
+
const inputStyle = {
|
28
|
+
width: '100%',
|
29
|
+
padding: 10,
|
30
|
+
margin: '10px 0',
|
31
|
+
borderRadius: 6,
|
32
|
+
border: '1px solid #ddd',
|
33
|
+
fontSize: 16,
|
34
|
+
};
|
35
|
+
|
36
|
+
const buttonStyle = {
|
37
|
+
width: '100%',
|
38
|
+
padding: 12,
|
39
|
+
borderRadius: 6,
|
40
|
+
border: 'none',
|
41
|
+
background: '#0070f3',
|
42
|
+
color: '#fff',
|
43
|
+
fontWeight: 600,
|
44
|
+
fontSize: 16,
|
45
|
+
marginTop: 10,
|
46
|
+
cursor: 'pointer',
|
47
|
+
};
|
48
|
+
|
49
|
+
const messageStyle = (success) => ({
|
50
|
+
margin: '12px 0',
|
51
|
+
color: success ? '#0a0' : '#d32f2f',
|
52
|
+
background: success ? '#eafbe7' : '#fdeaea',
|
53
|
+
padding: 8,
|
54
|
+
borderRadius: 6,
|
55
|
+
textAlign: 'center',
|
56
|
+
fontSize: 15,
|
57
|
+
});
|
58
|
+
|
59
|
+
export default function LoginRegisterFlow() {
|
60
|
+
const [mode, setMode] = useState('login');
|
61
|
+
const [identifier, setIdentifier] = useState('');
|
62
|
+
const [password, setPassword] = useState('');
|
63
|
+
const [username, setUsername] = useState('');
|
64
|
+
const [phone, setPhone] = useState('');
|
65
|
+
const [message, setMessage] = useState(null);
|
66
|
+
const [success, setSuccess] = useState(false);
|
67
|
+
|
68
|
+
const resetFields = () => {
|
69
|
+
setIdentifier('');
|
70
|
+
setPassword('');
|
71
|
+
setUsername('');
|
72
|
+
setPhone('');
|
73
|
+
setMessage(null);
|
74
|
+
setSuccess(false);
|
75
|
+
};
|
76
|
+
|
77
|
+
const handleLogin = async (e) => {
|
78
|
+
e.preventDefault();
|
79
|
+
setMessage(null);
|
80
|
+
setSuccess(false);
|
81
|
+
const { error } = await signInWithEmail(identifier, password);
|
82
|
+
if (error) {
|
83
|
+
setMessage(error.message || 'Login failed');
|
84
|
+
setSuccess(false);
|
85
|
+
} else {
|
86
|
+
setMessage('Login successful!');
|
87
|
+
setSuccess(true);
|
88
|
+
setTimeout(resetFields, 1200);
|
89
|
+
}
|
90
|
+
};
|
91
|
+
|
92
|
+
const handleRegister = async (e) => {
|
93
|
+
e.preventDefault();
|
94
|
+
setMessage(null);
|
95
|
+
setSuccess(false);
|
96
|
+
const { error } = await registerWithEmail(identifier, password, username, phone);
|
97
|
+
if (error) {
|
98
|
+
setMessage(error.message || 'Registration failed');
|
99
|
+
setSuccess(false);
|
100
|
+
} else {
|
101
|
+
setMessage('Registration successful! Please check your email to confirm.');
|
102
|
+
setSuccess(true);
|
103
|
+
setTimeout(resetFields, 2000);
|
104
|
+
}
|
105
|
+
};
|
106
|
+
|
107
|
+
return (
|
108
|
+
<div style={boxStyle}>
|
109
|
+
<div style={{ display: 'flex', marginBottom: 24 }}>
|
110
|
+
<button style={tabStyle(mode === 'login')} onClick={() => { setMode('login'); setMessage(null); }}>Login</button>
|
111
|
+
<button style={tabStyle(mode === 'register')} onClick={() => { setMode('register'); setMessage(null); }}>Register</button>
|
112
|
+
</div>
|
113
|
+
{mode === 'login' ? (
|
114
|
+
<form onSubmit={handleLogin}>
|
115
|
+
<input
|
116
|
+
style={inputStyle}
|
117
|
+
type="text"
|
118
|
+
placeholder="Email, phone, or username"
|
119
|
+
value={identifier}
|
120
|
+
onChange={e => setIdentifier(e.target.value)}
|
121
|
+
required
|
122
|
+
/>
|
123
|
+
<input
|
124
|
+
style={inputStyle}
|
125
|
+
type="password"
|
126
|
+
placeholder="Password"
|
127
|
+
value={password}
|
128
|
+
onChange={e => setPassword(e.target.value)}
|
129
|
+
required
|
130
|
+
/>
|
131
|
+
<button style={buttonStyle} type="submit">Login</button>
|
132
|
+
</form>
|
133
|
+
) : (
|
134
|
+
<form onSubmit={handleRegister}>
|
135
|
+
<input
|
136
|
+
style={inputStyle}
|
137
|
+
type="text"
|
138
|
+
placeholder="Email"
|
139
|
+
value={identifier}
|
140
|
+
onChange={e => setIdentifier(e.target.value)}
|
141
|
+
required
|
142
|
+
/>
|
143
|
+
<input
|
144
|
+
style={inputStyle}
|
145
|
+
type="password"
|
146
|
+
placeholder="Password"
|
147
|
+
value={password}
|
148
|
+
onChange={e => setPassword(e.target.value)}
|
149
|
+
required
|
150
|
+
/>
|
151
|
+
<input
|
152
|
+
style={inputStyle}
|
153
|
+
type="text"
|
154
|
+
placeholder="Username (optional)"
|
155
|
+
value={username}
|
156
|
+
onChange={e => setUsername(e.target.value)}
|
157
|
+
/>
|
158
|
+
<input
|
159
|
+
style={inputStyle}
|
160
|
+
type="text"
|
161
|
+
placeholder="Phone (optional)"
|
162
|
+
value={phone}
|
163
|
+
onChange={e => setPhone(e.target.value)}
|
164
|
+
/>
|
165
|
+
<button style={buttonStyle} type="submit">Register</button>
|
166
|
+
</form>
|
167
|
+
)}
|
168
|
+
{message && <div style={messageStyle(success)}>{message}</div>}
|
169
|
+
</div>
|
170
|
+
);
|
171
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { logout } from '../logout';
|
3
|
+
|
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
|
+
export default function LogoutButton() {
|
37
|
+
const [message, setMessage] = useState(null);
|
38
|
+
const [success, setSuccess] = useState(false);
|
39
|
+
|
40
|
+
const handleLogout = async () => {
|
41
|
+
setMessage(null);
|
42
|
+
setSuccess(false);
|
43
|
+
const { error } = await logout();
|
44
|
+
if (error) {
|
45
|
+
setMessage(error.message || 'Logout failed');
|
46
|
+
setSuccess(false);
|
47
|
+
} else {
|
48
|
+
setMessage('Logout successful!');
|
49
|
+
setSuccess(true);
|
50
|
+
setTimeout(() => {
|
51
|
+
setMessage(null);
|
52
|
+
setSuccess(false);
|
53
|
+
}, 1500);
|
54
|
+
}
|
55
|
+
};
|
56
|
+
|
57
|
+
return (
|
58
|
+
<div style={boxStyle}>
|
59
|
+
<button style={buttonStyle} onClick={handleLogout}>Logout</button>
|
60
|
+
{message && <div style={messageStyle(success)}>{message}</div>}
|
61
|
+
</div>
|
62
|
+
);
|
63
|
+
}
|
@@ -0,0 +1,114 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { registerWithEmail } from '../register';
|
3
|
+
|
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 RegisterOnly() {
|
47
|
+
const [email, setEmail] = useState('');
|
48
|
+
const [password, setPassword] = useState('');
|
49
|
+
const [username, setUsername] = useState('');
|
50
|
+
const [phone, setPhone] = useState('');
|
51
|
+
const [message, setMessage] = useState(null);
|
52
|
+
const [success, setSuccess] = useState(false);
|
53
|
+
|
54
|
+
const handleRegister = async (e) => {
|
55
|
+
e.preventDefault();
|
56
|
+
setMessage(null);
|
57
|
+
setSuccess(false);
|
58
|
+
const { error } = await registerWithEmail(email, password, username, phone);
|
59
|
+
if (error) {
|
60
|
+
setMessage(error.message || 'Registration failed');
|
61
|
+
setSuccess(false);
|
62
|
+
} else {
|
63
|
+
setMessage('Registration successful! Please check your email to confirm.');
|
64
|
+
setSuccess(true);
|
65
|
+
setTimeout(() => {
|
66
|
+
setEmail('');
|
67
|
+
setPassword('');
|
68
|
+
setUsername('');
|
69
|
+
setPhone('');
|
70
|
+
setMessage(null);
|
71
|
+
setSuccess(false);
|
72
|
+
}, 2000);
|
73
|
+
}
|
74
|
+
};
|
75
|
+
|
76
|
+
return (
|
77
|
+
<div style={boxStyle}>
|
78
|
+
<form onSubmit={handleRegister}>
|
79
|
+
<input
|
80
|
+
style={inputStyle}
|
81
|
+
type="text"
|
82
|
+
placeholder="Email"
|
83
|
+
value={email}
|
84
|
+
onChange={e => setEmail(e.target.value)}
|
85
|
+
required
|
86
|
+
/>
|
87
|
+
<input
|
88
|
+
style={inputStyle}
|
89
|
+
type="password"
|
90
|
+
placeholder="Password"
|
91
|
+
value={password}
|
92
|
+
onChange={e => setPassword(e.target.value)}
|
93
|
+
required
|
94
|
+
/>
|
95
|
+
<input
|
96
|
+
style={inputStyle}
|
97
|
+
type="text"
|
98
|
+
placeholder="Username (optional)"
|
99
|
+
value={username}
|
100
|
+
onChange={e => setUsername(e.target.value)}
|
101
|
+
/>
|
102
|
+
<input
|
103
|
+
style={inputStyle}
|
104
|
+
type="text"
|
105
|
+
placeholder="Phone (optional)"
|
106
|
+
value={phone}
|
107
|
+
onChange={e => setPhone(e.target.value)}
|
108
|
+
/>
|
109
|
+
<button style={buttonStyle} type="submit">Register</button>
|
110
|
+
</form>
|
111
|
+
{message && <div style={messageStyle(success)}>{message}</div>}
|
112
|
+
</div>
|
113
|
+
);
|
114
|
+
}
|
package/src/index.js
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
export { default as AuthWrapper } from './AuthWrapper';
|
2
|
-
export { default as LogoutButton } from './LogoutButton';
|
3
1
|
export { useAuth } from './useAuth';
|
4
2
|
export { isAdmin } from './utils';
|
5
3
|
export { supabase } from './supabaseClient';
|
6
4
|
export { signInWithEmail } from './login'; // Add this line
|
7
5
|
export { initializeSupabase } from './supabaseClient';
|
8
6
|
export { registerWithEmail } from './register';
|
9
|
-
export { logout } from './logout';
|
7
|
+
export { logout } from './logout';
|
8
|
+
|
9
|
+
export { default as LoginRegisterFlow } from './components/LoginRegisterFlow';
|
10
|
+
export { default as LoginOnly } from './components/LoginOnly';
|
11
|
+
export { default as RegisterOnly } from './components/RegisterOnly';
|
12
|
+
export { default as LogoutButton } from './components/LogoutButton';
|
package/src/AuthWrapper.jsx
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
import { useState, useEffect } from 'react'
|
2
|
-
import { Auth } from '@supabase/auth-ui-react'
|
3
|
-
import { ThemeSupa } from '@supabase/auth-ui-shared'
|
4
|
-
import { supabase } from './supabaseClient'
|
5
|
-
|
6
|
-
export default function AuthWrapper({ onAuth, providers = ['google', 'github'], theme = 'dark' }) {
|
7
|
-
if (!supabase) {
|
8
|
-
throw new Error('Supabase client is not initialized. Call initializeSupabase() before using AuthWrapper.')
|
9
|
-
}
|
10
|
-
|
11
|
-
const [session, setSession] = useState(null)
|
12
|
-
|
13
|
-
useEffect(() => {
|
14
|
-
supabase.auth.getSession().then(({ data: { session } }) => {
|
15
|
-
setSession(session)
|
16
|
-
if (session) onAuth?.(session)
|
17
|
-
})
|
18
|
-
|
19
|
-
const { data: subscription } = supabase.auth.onAuthStateChange((_event, session) => {
|
20
|
-
setSession(session)
|
21
|
-
if (session) onAuth?.(session)
|
22
|
-
})
|
23
|
-
|
24
|
-
return () => subscription?.unsubscribe()
|
25
|
-
}, [onAuth])
|
26
|
-
|
27
|
-
if (!session) {
|
28
|
-
return (
|
29
|
-
<Auth
|
30
|
-
supabaseClient={supabase}
|
31
|
-
appearance={{ theme: ThemeSupa }}
|
32
|
-
providers={providers}
|
33
|
-
theme={theme}
|
34
|
-
/>
|
35
|
-
)
|
36
|
-
}
|
37
|
-
|
38
|
-
return <div>✅ Logged in as: {session.user.email}</div>
|
39
|
-
}
|
package/src/LogoutButton.jsx
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
import { useAuth } from './useAuth'
|
2
|
-
|
3
|
-
export default function LogoutButton({ supabaseClient, onLogout }) {
|
4
|
-
const { signOut } = useAuth(supabaseClient)
|
5
|
-
|
6
|
-
const handleLogout = async () => {
|
7
|
-
await signOut()
|
8
|
-
onLogout?.()
|
9
|
-
}
|
10
|
-
|
11
|
-
return <button onClick={handleLogout}>🚪 Log out</button>
|
12
|
-
}
|