@rpcbase/client 0.148.0 → 0.150.0
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/auth/SignIn/SignInEmailForm.js +114 -0
- package/auth/SignIn/index.js +23 -123
- package/auth/SignIn/sign-in.scss +0 -14
- package/auth/SignUp/SignUpEmailForm.js +98 -0
- package/auth/SignUp/index.js +28 -84
- package/package.json +1 -1
- package/src/ui/oauth/GitHub.js +26 -0
- package/src/ui/oauth/index.js +10 -0
- package/src/ui/oauth/oauth.scss +16 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
import assert from "assert"
|
|
3
|
+
import debug from "debug"
|
|
4
|
+
import {useState, useEffect} from "react"
|
|
5
|
+
import {useSearchParam} from "react-use"
|
|
6
|
+
import isEmail from "validator/lib/isEmail"
|
|
7
|
+
import page from "page"
|
|
8
|
+
|
|
9
|
+
import post from "../../helpers/post"
|
|
10
|
+
import {reconnect as rts_reconnect} from "../../rts/rts"
|
|
11
|
+
import {set_is_signed_in, setUid, set_tenant_id} from "../index"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
const log = debug("rb:auth:signin")
|
|
15
|
+
|
|
16
|
+
const SignInEmailForm = ({onSuccess, onSuccessRedirect}) => {
|
|
17
|
+
const redirect = useSearchParam("redirect")
|
|
18
|
+
|
|
19
|
+
const [isLoading, setIsLoading] = useState(false)
|
|
20
|
+
|
|
21
|
+
const [email, setEmail] = useState("")
|
|
22
|
+
const [password, setPassword] = useState("")
|
|
23
|
+
const [forgotUrlParam, setForgotUrlParam] = useState(null)
|
|
24
|
+
|
|
25
|
+
const [errors, setErrors] = useState()
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (isEmail(email)) {
|
|
29
|
+
setForgotUrlParam(btoa(email))
|
|
30
|
+
} else {
|
|
31
|
+
setForgotUrlParam("")
|
|
32
|
+
}
|
|
33
|
+
}, [email])
|
|
34
|
+
|
|
35
|
+
const onSubmit = async(e) => {
|
|
36
|
+
e.preventDefault()
|
|
37
|
+
setIsLoading(true)
|
|
38
|
+
const res = await post("/api/v1/auth/sign_in", {email, password})
|
|
39
|
+
setIsLoading(false)
|
|
40
|
+
|
|
41
|
+
// success
|
|
42
|
+
if (res.status === "ok") {
|
|
43
|
+
log("signed in res: ok", res)
|
|
44
|
+
log("redirect to:", redirect || onSuccessRedirect)
|
|
45
|
+
const {user_id} = res
|
|
46
|
+
assert(res.user_id, "missing user_id")
|
|
47
|
+
|
|
48
|
+
setUid(user_id)
|
|
49
|
+
set_tenant_id(user_id.slice(8, 16))
|
|
50
|
+
set_is_signed_in(true)
|
|
51
|
+
|
|
52
|
+
// we must now reconnect on the websocket as we now have a new cookie
|
|
53
|
+
rts_reconnect()
|
|
54
|
+
onSuccess()
|
|
55
|
+
if (redirect) {
|
|
56
|
+
page(redirect)
|
|
57
|
+
} else {
|
|
58
|
+
page(onSuccessRedirect)
|
|
59
|
+
}
|
|
60
|
+
// errors
|
|
61
|
+
} else {
|
|
62
|
+
log("sign in error", res)
|
|
63
|
+
|
|
64
|
+
setErrors(res.errors)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const onChangeEmail = (e) => {
|
|
69
|
+
setEmail(e.target.value)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const onChangePassword = (e) => {
|
|
73
|
+
setPassword(e.target.value)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<form onSubmit={onSubmit}>
|
|
79
|
+
|
|
80
|
+
{errors?.form && (
|
|
81
|
+
<p className="text-danger">{errors.form}</p>
|
|
82
|
+
)}
|
|
83
|
+
|
|
84
|
+
<div className="form-floating text-start">
|
|
85
|
+
<input type="email"
|
|
86
|
+
className="form-control"
|
|
87
|
+
id="input-email"
|
|
88
|
+
placeholder="name@example.com"
|
|
89
|
+
value={email}
|
|
90
|
+
onChange={onChangeEmail} />
|
|
91
|
+
<label htmlFor="input-email">Email Address</label>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div className="form-floating text-start">
|
|
95
|
+
<input type="password"
|
|
96
|
+
className="form-control"
|
|
97
|
+
id="input-password"
|
|
98
|
+
placeholder="Password"
|
|
99
|
+
value={password}
|
|
100
|
+
onChange={onChangePassword} />
|
|
101
|
+
<label htmlFor="input-password">Password</label>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div className="mt-2 text-start w-100">
|
|
105
|
+
<a href={`/forgot-password${forgotUrlParam && "#" + forgotUrlParam}`}>Forgot your password?</a>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<button className="mt-4 mb-3 w-100 btn btn-lg btn-primary" type="submit" onClick={onSubmit}>Sign In</button>
|
|
109
|
+
|
|
110
|
+
</form>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export default SignInEmailForm
|
package/auth/SignIn/index.js
CHANGED
|
@@ -1,87 +1,25 @@
|
|
|
1
1
|
/* @flow */
|
|
2
2
|
import assert from "assert"
|
|
3
|
-
import {useState, useEffect} from "react"
|
|
4
|
-
import {useSearchParam} from "react-use"
|
|
5
|
-
import isEmail from "validator/lib/isEmail"
|
|
6
|
-
import page from "page"
|
|
7
|
-
import debug from "debug"
|
|
8
3
|
|
|
9
|
-
import
|
|
10
|
-
import {reconnect as rts_reconnect} from "../../rts/rts"
|
|
4
|
+
import authConfig from "@rpcbase/dot-rb/auth"
|
|
11
5
|
|
|
12
|
-
import {
|
|
6
|
+
import {AUTH_BUTTONS} from "../../src/ui/oauth"
|
|
13
7
|
import Footer from "../Footer"
|
|
14
8
|
|
|
15
|
-
import "./
|
|
9
|
+
import SignInEmailForm from "./SignInEmailForm"
|
|
16
10
|
|
|
11
|
+
import "./sign-in.scss"
|
|
17
12
|
|
|
18
|
-
const log = debug("rb:auth:signin")
|
|
19
13
|
|
|
20
|
-
const
|
|
14
|
+
const hasOAuth = authConfig.oauth_providers?.length > 0
|
|
15
|
+
const hasEmail = authConfig.has_email_signup
|
|
21
16
|
|
|
22
17
|
const SignIn = ({
|
|
23
18
|
name,
|
|
24
19
|
logo,
|
|
25
|
-
onSuccessRedirect = "/
|
|
20
|
+
onSuccessRedirect = "/",
|
|
26
21
|
onSuccess = () => null
|
|
27
22
|
}) => {
|
|
28
|
-
const [isLoading, setIsLoading] = useState(false)
|
|
29
|
-
const [errors, setErrors] = useState()
|
|
30
|
-
|
|
31
|
-
const [email, setEmail] = useState("")
|
|
32
|
-
const [password, setPassword] = useState("")
|
|
33
|
-
const [forgotUrlParam, setForgotUrlParam] = useState(null)
|
|
34
|
-
|
|
35
|
-
const redirect = useSearchParam("redirect")
|
|
36
|
-
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
if (isEmail(email)) {
|
|
39
|
-
setForgotUrlParam(btoa(email))
|
|
40
|
-
} else {
|
|
41
|
-
setForgotUrlParam("")
|
|
42
|
-
}
|
|
43
|
-
}, [email])
|
|
44
|
-
|
|
45
|
-
const onSubmit = async(e) => {
|
|
46
|
-
e.preventDefault()
|
|
47
|
-
setIsLoading(true)
|
|
48
|
-
const res = await post("/api/v1/auth/sign_in", {email, password})
|
|
49
|
-
setIsLoading(false)
|
|
50
|
-
|
|
51
|
-
// success
|
|
52
|
-
if (res.status === "ok") {
|
|
53
|
-
log("signed in res: ok", res)
|
|
54
|
-
log("redirect to:", redirect || onSuccessRedirect)
|
|
55
|
-
const {user_id} = res
|
|
56
|
-
assert(res.user_id, "missing user_id")
|
|
57
|
-
|
|
58
|
-
setUid(user_id)
|
|
59
|
-
set_tenant_id(user_id.slice(8, 16))
|
|
60
|
-
set_is_signed_in(true)
|
|
61
|
-
|
|
62
|
-
// we must now reconnect on the websocket as we now have a new cookie
|
|
63
|
-
rts_reconnect()
|
|
64
|
-
onSuccess()
|
|
65
|
-
if (redirect) {
|
|
66
|
-
page(redirect)
|
|
67
|
-
} else {
|
|
68
|
-
page(onSuccessRedirect)
|
|
69
|
-
}
|
|
70
|
-
// errors
|
|
71
|
-
} else {
|
|
72
|
-
log("sign in error", res)
|
|
73
|
-
|
|
74
|
-
setErrors(res.errors)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const onChangeEmail = (e) => {
|
|
79
|
-
setEmail(e.target.value)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const onChangePassword = (e) => {
|
|
83
|
-
setPassword(e.target.value)
|
|
84
|
-
}
|
|
85
23
|
|
|
86
24
|
return (
|
|
87
25
|
<div id="sign-in-wrapper">
|
|
@@ -99,66 +37,28 @@ const SignIn = ({
|
|
|
99
37
|
<a href="/signup" className="ms-1">Sign up here</a>
|
|
100
38
|
</p>
|
|
101
39
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
className="form-control"
|
|
111
|
-
id="input-email"
|
|
112
|
-
placeholder="name@example.com"
|
|
113
|
-
value={email}
|
|
114
|
-
onChange={onChangeEmail} />
|
|
115
|
-
<label htmlFor="input-email">Email Address</label>
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
|
-
<div className="form-floating text-start">
|
|
119
|
-
<input type="password"
|
|
120
|
-
className="form-control"
|
|
121
|
-
id="input-password"
|
|
122
|
-
placeholder="Password"
|
|
123
|
-
value={password}
|
|
124
|
-
onChange={onChangePassword} />
|
|
125
|
-
<label htmlFor="input-password">Password</label>
|
|
126
|
-
</div>
|
|
127
|
-
|
|
128
|
-
<div className="mt-2 text-start w-100">
|
|
129
|
-
<a href={`/forgot-password${forgotUrlParam && "#" + forgotUrlParam}`}>Forgot your password?</a>
|
|
130
|
-
</div>
|
|
131
|
-
|
|
132
|
-
<button className="mt-4 mb-3 w-100 btn btn-lg btn-primary" type="submit" onClick={onSubmit}>Sign In</button>
|
|
133
|
-
|
|
134
|
-
</form>
|
|
135
|
-
|
|
136
|
-
{SIGNIN_WITH_GITHUB && (
|
|
40
|
+
{hasEmail && (
|
|
41
|
+
<SignInEmailForm
|
|
42
|
+
onSuccess={onSuccess}
|
|
43
|
+
onSuccessRedirect={onSuccessRedirect}
|
|
44
|
+
/>
|
|
45
|
+
)}
|
|
46
|
+
|
|
47
|
+
{hasEmail && hasOAuth && (
|
|
137
48
|
<>
|
|
138
49
|
<hr />
|
|
139
50
|
<p className="text-muted">OR</p>
|
|
140
|
-
|
|
141
|
-
<a href="/signup"
|
|
142
|
-
className="sign-in-github-btn p-2 btn-lg w-100"
|
|
143
|
-
style={{}}>
|
|
144
|
-
<div style={{}} className="me-2">
|
|
145
|
-
<svg height="28px" width="28px" viewBox="0 0 16 16" style={{fill: "currentColor"}}>
|
|
146
|
-
<path fillRule={"evenodd"} d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38
|
|
147
|
-
0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01
|
|
148
|
-
1.08.58 1.23.82.72 1.21 1.87.87
|
|
149
|
-
2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12
|
|
150
|
-
0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08
|
|
151
|
-
2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0
|
|
152
|
-
.21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
|
|
153
|
-
</svg>
|
|
154
|
-
</div>
|
|
155
|
-
<div className="">
|
|
156
|
-
Sign in with GitHub
|
|
157
|
-
</div>
|
|
158
|
-
</a>
|
|
159
51
|
</>
|
|
160
52
|
)}
|
|
161
53
|
|
|
54
|
+
{hasOAuth && authConfig.oauth_providers.map((provider, index) => {
|
|
55
|
+
const Comp = AUTH_BUTTONS[provider.id]
|
|
56
|
+
assert(Comp, `unable to find oauth button for provider: ${JSON.stringify(provider)}`)
|
|
57
|
+
|
|
58
|
+
return <Comp key={`${provider.id}-${index}`} text="Sign in" />
|
|
59
|
+
})}
|
|
60
|
+
|
|
61
|
+
|
|
162
62
|
</div>
|
|
163
63
|
</div>
|
|
164
64
|
|
package/auth/SignIn/sign-in.scss
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
align-items: center;
|
|
8
8
|
padding-top: 40px;
|
|
9
9
|
padding-bottom: 40px;
|
|
10
|
-
// background-color: var(--bs-secondary);
|
|
11
10
|
background-color: $gray-500;
|
|
12
11
|
|
|
13
12
|
hr {
|
|
@@ -54,17 +53,4 @@
|
|
|
54
53
|
border-top-left-radius: 0;
|
|
55
54
|
border-top-right-radius: 0;
|
|
56
55
|
}
|
|
57
|
-
|
|
58
|
-
.sign-in-github-btn {
|
|
59
|
-
display: inline-flex;
|
|
60
|
-
align-items: center;
|
|
61
|
-
background-color: #24292E;
|
|
62
|
-
font-size: 1.25rem;
|
|
63
|
-
color: $gray-200;
|
|
64
|
-
text-decoration: none;
|
|
65
|
-
|
|
66
|
-
&:hover {
|
|
67
|
-
color: $white;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
56
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
import {useState} from "react"
|
|
3
|
+
|
|
4
|
+
import {reconnect as rts_reconnect} from "../../rts/rts"
|
|
5
|
+
|
|
6
|
+
import {set_is_signed_in, setUid, set_tenant_id} from "../index"
|
|
7
|
+
import post from "../../helpers/post"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const SignUpEmailForm = ({onSuccessRedirect, onSuccess}) => {
|
|
11
|
+
const [email, setEmail] = useState("")
|
|
12
|
+
const [password, setPassword] = useState("")
|
|
13
|
+
const [passwordConfirm, setPasswordConfirm] = useState("")
|
|
14
|
+
const [error, setError] = useState(null)
|
|
15
|
+
|
|
16
|
+
const onSubmit = async() => {
|
|
17
|
+
setError(null)
|
|
18
|
+
if (!password || password !== passwordConfirm) {
|
|
19
|
+
setError("Passwords do not match")
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
const res = await post("/public/v1/auth/sign_up", {email, password})
|
|
23
|
+
|
|
24
|
+
if (res.status === "ok") {
|
|
25
|
+
const {user_id} = res
|
|
26
|
+
setUid(user_id)
|
|
27
|
+
set_tenant_id(user_id.slice(8, 16))
|
|
28
|
+
set_is_signed_in(true)
|
|
29
|
+
|
|
30
|
+
// we must now reconnect on the websocket as we have a new cookie
|
|
31
|
+
rts_reconnect()
|
|
32
|
+
onSuccess()
|
|
33
|
+
page(onSuccessRedirect)
|
|
34
|
+
} else if (res.status === "error") {
|
|
35
|
+
setError(res.message)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const onChangeEmail = (e) => {
|
|
40
|
+
setEmail(e.target.value)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const onChangePassword = (e) => {
|
|
44
|
+
setPassword(e.target.value)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const onChangePasswordConfirm = (e) => {
|
|
48
|
+
setPasswordConfirm(e.target.value)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<>
|
|
54
|
+
{error && (
|
|
55
|
+
<div className="invalid-feedback d-flex text-start">
|
|
56
|
+
{error}
|
|
57
|
+
</div>
|
|
58
|
+
)}
|
|
59
|
+
|
|
60
|
+
<div className="form-floating text-start">
|
|
61
|
+
<input type="email"
|
|
62
|
+
className="form-control"
|
|
63
|
+
id="input-email"
|
|
64
|
+
placeholder="name@example.com"
|
|
65
|
+
value={email}
|
|
66
|
+
onChange={onChangeEmail} />
|
|
67
|
+
<label htmlFor="input-email">Email Address</label>
|
|
68
|
+
</div>
|
|
69
|
+
<div className="form-floating text-start">
|
|
70
|
+
<input type="password"
|
|
71
|
+
className="form-control"
|
|
72
|
+
id="input-password"
|
|
73
|
+
placeholder="Password"
|
|
74
|
+
value={password}
|
|
75
|
+
onChange={onChangePassword} />
|
|
76
|
+
<label htmlFor="input-password">Password</label>
|
|
77
|
+
</div>
|
|
78
|
+
<div className="form-floating text-start">
|
|
79
|
+
<input type="password"
|
|
80
|
+
className="form-control"
|
|
81
|
+
id="input-password-confirm"
|
|
82
|
+
placeholder="Confirm Password"
|
|
83
|
+
value={passwordConfirm}
|
|
84
|
+
onChange={onChangePasswordConfirm} />
|
|
85
|
+
<label htmlFor="input-password-confirm">Confirm Password</label>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<div className="checkbox mt-3 mb-3 text-start">
|
|
89
|
+
<label style={{cursor: "pointer", userSelect: "none"}}>
|
|
90
|
+
<input type="checkbox" value="terms-accepted" /> I agree to the terms and privacy policy.
|
|
91
|
+
</label>
|
|
92
|
+
</div>
|
|
93
|
+
<button className="w-100 btn btn-lg btn-primary" type="submit" onClick={onSubmit}>Sign Up</button>
|
|
94
|
+
</>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export default SignUpEmailForm
|
package/auth/SignUp/index.js
CHANGED
|
@@ -1,61 +1,26 @@
|
|
|
1
1
|
/* @flow */
|
|
2
|
-
import
|
|
3
|
-
import page from "page"
|
|
2
|
+
import assert from "assert"
|
|
4
3
|
|
|
5
|
-
import
|
|
4
|
+
import authConfig from "@rpcbase/dot-rb/auth"
|
|
5
|
+
|
|
6
|
+
import {AUTH_BUTTONS} from "../../src/ui/oauth"
|
|
6
7
|
|
|
7
|
-
import {set_is_signed_in, setUid, set_tenant_id} from "../index"
|
|
8
|
-
import post from "../../helpers/post"
|
|
9
8
|
import Footer from "../Footer"
|
|
10
9
|
|
|
10
|
+
import SignUpEmailForm from "./SignUpEmailForm"
|
|
11
|
+
|
|
11
12
|
import "./sign-up.scss"
|
|
12
13
|
|
|
14
|
+
|
|
15
|
+
const hasOAuth = authConfig.oauth_providers?.length > 0
|
|
16
|
+
const hasEmail = authConfig.has_email_signup
|
|
17
|
+
|
|
13
18
|
const SignUp = ({
|
|
14
19
|
logo,
|
|
15
20
|
name,
|
|
16
|
-
onSuccessRedirect = "/
|
|
21
|
+
onSuccessRedirect = "/",
|
|
17
22
|
onSuccess = () => null,
|
|
18
23
|
}) => {
|
|
19
|
-
const [email, setEmail] = useState("")
|
|
20
|
-
const [password, setPassword] = useState("")
|
|
21
|
-
const [passwordConfirm, setPasswordConfirm] = useState("")
|
|
22
|
-
const [error, setError] = useState(null)
|
|
23
|
-
|
|
24
|
-
const onSubmit = async() => {
|
|
25
|
-
setError(null)
|
|
26
|
-
if (!password || password !== passwordConfirm) {
|
|
27
|
-
setError("Passwords do not match")
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
const res = await post("/public/v1/auth/sign_up", {email, password})
|
|
31
|
-
|
|
32
|
-
if (res.status === "ok") {
|
|
33
|
-
const {user_id} = res
|
|
34
|
-
setUid(user_id)
|
|
35
|
-
set_tenant_id(user_id.slice(8, 16))
|
|
36
|
-
set_is_signed_in(true)
|
|
37
|
-
|
|
38
|
-
// we must now reconnect on the websocket as we have a new cookie
|
|
39
|
-
rts_reconnect()
|
|
40
|
-
onSuccess()
|
|
41
|
-
page(onSuccessRedirect)
|
|
42
|
-
} else if (res.status === "error") {
|
|
43
|
-
setError(res.message)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const onChangeEmail = (e) => {
|
|
48
|
-
setEmail(e.target.value)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const onChangePassword = (e) => {
|
|
52
|
-
setPassword(e.target.value)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const onChangePasswordConfirm = (e) => {
|
|
56
|
-
setPasswordConfirm(e.target.value)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
24
|
|
|
60
25
|
return (
|
|
61
26
|
<div id="sign-up-wrapper">
|
|
@@ -68,51 +33,30 @@ const SignUp = ({
|
|
|
68
33
|
<hr />
|
|
69
34
|
|
|
70
35
|
<h1 className="h4 mt-3 mb-3 fw-normal">Sign Up</h1>
|
|
71
|
-
<p className="text-muted">
|
|
36
|
+
<p className="text-start text-muted">
|
|
72
37
|
Already have an account ? <a href="/signin" className="ms-1">Sign in here</a>
|
|
73
38
|
</p>
|
|
74
39
|
|
|
75
|
-
{
|
|
76
|
-
<
|
|
77
|
-
{
|
|
78
|
-
|
|
40
|
+
{hasEmail && (
|
|
41
|
+
<SignUpEmailForm
|
|
42
|
+
onSuccess={onSuccess}
|
|
43
|
+
onSuccessRedirect={onSuccessRedirect}
|
|
44
|
+
/>
|
|
79
45
|
)}
|
|
80
46
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
onChange={onChangeEmail} />
|
|
88
|
-
<label htmlFor="input-email">Email Address</label>
|
|
89
|
-
</div>
|
|
90
|
-
<div className="form-floating text-start">
|
|
91
|
-
<input type="password"
|
|
92
|
-
className="form-control"
|
|
93
|
-
id="input-password"
|
|
94
|
-
placeholder="Password"
|
|
95
|
-
value={password}
|
|
96
|
-
onChange={onChangePassword} />
|
|
97
|
-
<label htmlFor="input-password">Password</label>
|
|
98
|
-
</div>
|
|
99
|
-
<div className="form-floating text-start">
|
|
100
|
-
<input type="password"
|
|
101
|
-
className="form-control"
|
|
102
|
-
id="input-password-confirm"
|
|
103
|
-
placeholder="Confirm Password"
|
|
104
|
-
value={passwordConfirm}
|
|
105
|
-
onChange={onChangePasswordConfirm} />
|
|
106
|
-
<label htmlFor="input-password-confirm">Confirm Password</label>
|
|
107
|
-
</div>
|
|
47
|
+
{hasEmail && hasOAuth && (
|
|
48
|
+
<>
|
|
49
|
+
<hr />
|
|
50
|
+
<p className="text-muted">OR</p>
|
|
51
|
+
</>
|
|
52
|
+
)}
|
|
108
53
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
</label>
|
|
113
|
-
</div>
|
|
114
|
-
<button className="w-100 btn btn-lg btn-primary" type="submit" onClick={onSubmit}>Sign Up</button>
|
|
54
|
+
{hasOAuth && authConfig.oauth_providers.map((provider, index) => {
|
|
55
|
+
const Comp = AUTH_BUTTONS[provider.id]
|
|
56
|
+
assert(Comp, `unable to find oauth button for provider: ${JSON.stringify(provider)}`)
|
|
115
57
|
|
|
58
|
+
return <Comp key={`${provider.id}-${index}`} text="Sign up"/>
|
|
59
|
+
})}
|
|
116
60
|
</div>
|
|
117
61
|
</div>
|
|
118
62
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const GitHub = ({text}) => {
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<a href="/signup"
|
|
8
|
+
className="sign-in-github-btn p-2 btn-lg w-100"
|
|
9
|
+
style={{}}>
|
|
10
|
+
<div style={{}} className="me-2">
|
|
11
|
+
<svg height="28px" width="28px" viewBox="0 0 16 16" style={{fill: "currentColor"}}>
|
|
12
|
+
<path fillRule={"evenodd"} d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38
|
|
13
|
+
0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01
|
|
14
|
+
1.08.58 1.23.82.72 1.21 1.87.87
|
|
15
|
+
2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12
|
|
16
|
+
0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08
|
|
17
|
+
2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0
|
|
18
|
+
.21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
|
|
19
|
+
</svg>
|
|
20
|
+
</div>
|
|
21
|
+
<div className="">
|
|
22
|
+
{text} with GitHub
|
|
23
|
+
</div>
|
|
24
|
+
</a>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
@import "helpers";
|
|
2
|
+
|
|
3
|
+
.sign-in-github-btn {
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
background-color: #24292E;
|
|
7
|
+
font-size: 1.25rem;
|
|
8
|
+
color: $gray-200;
|
|
9
|
+
text-decoration: none;
|
|
10
|
+
|
|
11
|
+
border-radius: $border-radius;
|
|
12
|
+
|
|
13
|
+
&:hover {
|
|
14
|
+
color: $white;
|
|
15
|
+
}
|
|
16
|
+
}
|