@rpcbase/client 0.175.0 → 0.176.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/components/SignIn/SignInEmailForm.js +9 -6
- package/auth/components/SignIn/index.js +7 -6
- package/auth/components/SignOut/index.js +5 -5
- package/auth/index.js +30 -13
- package/i18n/en/rb.sign_in.json +11 -0
- package/i18n/en/rb.sign_out.json +5 -0
- package/i18n/fr/rb.sign_in.json +11 -0
- package/i18n/fr/rb.sign_out.json +5 -0
- package/{i18next.js → i18n/index.js} +19 -6
- package/package.json +3 -3
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import assert from "assert"
|
|
3
3
|
import debug from "debug"
|
|
4
4
|
import {useState, useEffect} from "react"
|
|
5
|
+
import {useTranslation} from "react-i18next"
|
|
5
6
|
import useSearchParam from "react-use/lib/useSearchParam"
|
|
6
7
|
import isEmail from "validator/lib/isEmail"
|
|
7
8
|
|
|
@@ -14,6 +15,8 @@ import {setIsSignedIn, setUid, setTenantId} from "../../index"
|
|
|
14
15
|
const log = debug("rb:auth:signin")
|
|
15
16
|
|
|
16
17
|
export const SignInEmailForm = ({onSuccess, onSuccessRedirect}) => {
|
|
18
|
+
const {t} = useTranslation("rb.sign_in", {useSuspense: false})
|
|
19
|
+
|
|
17
20
|
const redirect = useSearchParam("redirect")
|
|
18
21
|
|
|
19
22
|
const [isLoading, setIsLoading] = useState(false)
|
|
@@ -86,27 +89,27 @@ export const SignInEmailForm = ({onSuccess, onSuccessRedirect}) => {
|
|
|
86
89
|
<input type="email"
|
|
87
90
|
className="form-control"
|
|
88
91
|
id="input-email"
|
|
89
|
-
placeholder="
|
|
92
|
+
placeholder={t("email_placeholder")}
|
|
90
93
|
value={email}
|
|
91
94
|
onChange={onChangeEmail} />
|
|
92
|
-
<label htmlFor="input-email">
|
|
95
|
+
<label htmlFor="input-email">{t("email_address")}</label>
|
|
93
96
|
</div>
|
|
94
97
|
|
|
95
98
|
<div className="form-floating text-start">
|
|
96
99
|
<input type="password"
|
|
97
100
|
className="form-control"
|
|
98
101
|
id="input-password"
|
|
99
|
-
placeholder="
|
|
102
|
+
placeholder={t("password")}
|
|
100
103
|
value={password}
|
|
101
104
|
onChange={onChangePassword} />
|
|
102
|
-
<label htmlFor="input-password">
|
|
105
|
+
<label htmlFor="input-password">{t("password")}</label>
|
|
103
106
|
</div>
|
|
104
107
|
|
|
105
108
|
<div className="mt-2 text-start w-100">
|
|
106
|
-
<a href={`/forgot-password${forgotUrlParam && "#" + forgotUrlParam}`}>
|
|
109
|
+
<a href={`/forgot-password${forgotUrlParam && "#" + forgotUrlParam}`}>{t("forgot_password")}</a>
|
|
107
110
|
</div>
|
|
108
111
|
|
|
109
|
-
<button className="mt-4 mb-3 w-100 btn btn-lg btn-primary" type="submit" onClick={onSubmit}>
|
|
112
|
+
<button className="mt-4 mb-3 w-100 btn btn-lg btn-primary" type="submit" onClick={onSubmit}>{t("submit_btn")}</button>
|
|
110
113
|
|
|
111
114
|
</form>
|
|
112
115
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* @flow */
|
|
2
2
|
import assert from "assert"
|
|
3
|
-
|
|
3
|
+
import {useTranslation} from "react-i18next"
|
|
4
4
|
import authConfig from "@rpcbase/dot-rb/auth"
|
|
5
5
|
|
|
6
6
|
import {AUTH_BUTTONS} from "../../../src/ui/oauth"
|
|
@@ -20,6 +20,7 @@ export const SignIn = ({
|
|
|
20
20
|
onSuccessRedirect = "/",
|
|
21
21
|
onSuccess = () => null
|
|
22
22
|
}) => {
|
|
23
|
+
const {t} = useTranslation("rb.sign_in", {useSuspense: false})
|
|
23
24
|
|
|
24
25
|
return (
|
|
25
26
|
<div id="sign-in-wrapper">
|
|
@@ -31,10 +32,10 @@ export const SignIn = ({
|
|
|
31
32
|
|
|
32
33
|
<hr />
|
|
33
34
|
|
|
34
|
-
<h1 className="h4 mt-3 mb-3 fw-normal">
|
|
35
|
+
<h1 className="h4 mt-3 mb-3 fw-normal">{t("title")}</h1>
|
|
35
36
|
<p className="text-start text-muted">
|
|
36
|
-
|
|
37
|
-
<a href="/signup" className="ms-1">
|
|
37
|
+
{t("dont_have_account")}
|
|
38
|
+
<a href="/signup" className="ms-1">{t("sign_up_here")}</a>
|
|
38
39
|
</p>
|
|
39
40
|
|
|
40
41
|
{hasEmail && (
|
|
@@ -47,7 +48,7 @@ export const SignIn = ({
|
|
|
47
48
|
{hasEmail && hasOAuth && (
|
|
48
49
|
<>
|
|
49
50
|
<hr />
|
|
50
|
-
<p className="text-muted">
|
|
51
|
+
<p className="text-muted">{t("or")}</p>
|
|
51
52
|
</>
|
|
52
53
|
)}
|
|
53
54
|
|
|
@@ -55,7 +56,7 @@ export const SignIn = ({
|
|
|
55
56
|
const Comp = AUTH_BUTTONS[provider.id]
|
|
56
57
|
assert(Comp, `unable to find oauth button for provider: ${JSON.stringify(provider)}`)
|
|
57
58
|
|
|
58
|
-
return <Comp key={`${provider.id}-${index}`} text="
|
|
59
|
+
return <Comp key={`${provider.id}-${index}`} text={t("submit_btn")} className="w-100 justify-content-center" />
|
|
59
60
|
})}
|
|
60
61
|
|
|
61
62
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import assert from "assert"
|
|
3
3
|
import {useState, useEffect} from "react"
|
|
4
4
|
import Alert from "react-bootstrap/Alert"
|
|
5
|
+
import {useTranslation} from "react-i18next"
|
|
5
6
|
|
|
6
7
|
import authConfig from "@rpcbase/dot-rb/auth"
|
|
7
8
|
|
|
@@ -23,6 +24,7 @@ export const SignOut = ({
|
|
|
23
24
|
name,
|
|
24
25
|
onSignOutSuccess = () => null
|
|
25
26
|
}) => {
|
|
27
|
+
const {t} = useTranslation("rb.sign_out", {useSuspense: false})
|
|
26
28
|
|
|
27
29
|
const [isSignedOut, setIsSignedOut] = useState(false)
|
|
28
30
|
|
|
@@ -55,19 +57,17 @@ export const SignOut = ({
|
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
|
|
59
60
|
const onSubmit = () => {
|
|
60
|
-
console.log("sign out from selected accounts", selectedAccounts)
|
|
61
61
|
onSignOut()
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const message = hasMultiAccounts ? "Select accounts to sign out of:" : "
|
|
64
|
+
const message = hasMultiAccounts ? "Select accounts to sign out of:" : t("click_here_signout")
|
|
65
65
|
|
|
66
66
|
return (
|
|
67
67
|
<div id="sign-out-wrapper">
|
|
68
68
|
|
|
69
69
|
{isSignedOut && (
|
|
70
|
-
<Alert variant="light" data-bs-theme="dark" style={{maxWidth: 260, position: "absolute"}} onClose={() => setIsSignedOut(false)} dismissible>
|
|
70
|
+
<Alert variant="light" transition data-bs-theme="dark" style={{maxWidth: 260, position: "absolute"}} onClose={() => setIsSignedOut(false)} dismissible>
|
|
71
71
|
Signed out successfully
|
|
72
72
|
</Alert>
|
|
73
73
|
)}
|
|
@@ -80,7 +80,7 @@ export const SignOut = ({
|
|
|
80
80
|
|
|
81
81
|
<hr />
|
|
82
82
|
|
|
83
|
-
<h1 className="h4 mt-3 mb-3 fw-normal">
|
|
83
|
+
<h1 className="h4 mt-3 mb-3 fw-normal">{t("title")}</h1>
|
|
84
84
|
|
|
85
85
|
<p className="text-start text-muted">
|
|
86
86
|
{message}
|
package/auth/index.js
CHANGED
|
@@ -17,11 +17,17 @@ const log = debug("rb:auth")
|
|
|
17
17
|
|
|
18
18
|
// TODO: this should be refactored to AuthContext + Provider
|
|
19
19
|
|
|
20
|
-
let
|
|
20
|
+
let __isSignedIn = null
|
|
21
21
|
|
|
22
22
|
let __tenantId = typeof storage !== "undefined" && storage.getItem(LAST_TENANT_KEY)
|
|
23
23
|
let __userId = typeof storage !== "undefined" && __tenantId && storage.getItem(uidStorageKey(__tenantId))
|
|
24
24
|
|
|
25
|
+
let __pendingSignedInStatusCallbacks = []
|
|
26
|
+
|
|
27
|
+
const purgePendingSignedInStatusCallbacks = () => {
|
|
28
|
+
__pendingSignedInStatusCallbacks.forEach((fn) => fn(__isSignedIn))
|
|
29
|
+
__pendingSignedInStatusCallbacks = []
|
|
30
|
+
}
|
|
25
31
|
|
|
26
32
|
const getQueryStringAuthId = () => {
|
|
27
33
|
const url = new URL(window.location.href)
|
|
@@ -51,11 +57,11 @@ const runSessionCheck = async() => {
|
|
|
51
57
|
|
|
52
58
|
log("check_session response", res)
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
__isSignedIn = res.is_signed_in
|
|
61
|
+
purgePendingSignedInStatusCallbacks() // IMPORTANT: call and purge all pending callbacks
|
|
56
62
|
|
|
57
63
|
// if not authenticated, clear __userId + __tenantId and disconnect socket
|
|
58
|
-
if (!
|
|
64
|
+
if (!__isSignedIn) {
|
|
59
65
|
__userId = null
|
|
60
66
|
__tenantId = null
|
|
61
67
|
rtsDisconnect()
|
|
@@ -83,14 +89,14 @@ if (typeof window !== "undefined" && !isJest) runSessionCheck()
|
|
|
83
89
|
|
|
84
90
|
|
|
85
91
|
export const getSessionRestrictMiddleware = () => (ctx, next) => {
|
|
86
|
-
log("session_restrict:
|
|
92
|
+
log("session_restrict:__isSignedIn", __isSignedIn)
|
|
87
93
|
|
|
88
|
-
if (typeof
|
|
94
|
+
if (typeof __isSignedIn !== "boolean") {
|
|
89
95
|
log("session_restrict: will run session check")
|
|
90
96
|
|
|
91
97
|
runSessionCheck()
|
|
92
98
|
.then(() => {
|
|
93
|
-
if (
|
|
99
|
+
if (__isSignedIn) {
|
|
94
100
|
next()
|
|
95
101
|
} else {
|
|
96
102
|
redirectSignIn(ctx)
|
|
@@ -100,13 +106,12 @@ export const getSessionRestrictMiddleware = () => (ctx, next) => {
|
|
|
100
106
|
console.log("warning error in check session request", err)
|
|
101
107
|
throw err
|
|
102
108
|
})
|
|
103
|
-
} else if (
|
|
109
|
+
} else if (__isSignedIn) {
|
|
104
110
|
next()
|
|
105
111
|
} else {
|
|
106
|
-
log("AUTH", JSON.stringify(
|
|
107
|
-
log("NOT
|
|
112
|
+
log("AUTH", JSON.stringify(__isSignedIn))
|
|
113
|
+
log("NOT SIGNED IN, REDIRECT HERE")
|
|
108
114
|
redirectSignIn(ctx)
|
|
109
|
-
// next()
|
|
110
115
|
}
|
|
111
116
|
}
|
|
112
117
|
|
|
@@ -127,6 +132,18 @@ export const setTenantId = (val) => {
|
|
|
127
132
|
storage.setItem(LAST_TENANT_KEY, val)
|
|
128
133
|
}
|
|
129
134
|
|
|
130
|
-
export const setIsSignedIn = (val) =>
|
|
135
|
+
export const setIsSignedIn = (val) => {
|
|
136
|
+
__isSignedIn = val
|
|
137
|
+
purgePendingSignedInStatusCallbacks() // IMPORTANT: call and purge all pending callbacks
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export const getIsSignedIn = () => __isSignedIn
|
|
141
|
+
|
|
131
142
|
|
|
132
|
-
export const
|
|
143
|
+
export const waitForSignedInStatus = () => new Promise((resolve) => {
|
|
144
|
+
if (typeof __isSignedIn === "boolean") {
|
|
145
|
+
resolve(__isSignedIn)
|
|
146
|
+
} else {
|
|
147
|
+
__pendingSignedInStatusCallbacks.push(resolve)
|
|
148
|
+
}
|
|
149
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Sign In",
|
|
3
|
+
"dont_have_account": "Don't have an account?",
|
|
4
|
+
"sign_up_here": "Sign up here",
|
|
5
|
+
"or": "OR",
|
|
6
|
+
"email_address": "Email Address",
|
|
7
|
+
"email_placeholder": "name@example.com",
|
|
8
|
+
"password": "Password",
|
|
9
|
+
"forgot_password": "Forgot your password?",
|
|
10
|
+
"submit_btn": "Sign in"
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Connexion",
|
|
3
|
+
"dont_have_account": "Vous n'avez pas de compte?",
|
|
4
|
+
"sign_up_here": "Créez un compte ici",
|
|
5
|
+
"or": "OU",
|
|
6
|
+
"email_address": "Addresse Email",
|
|
7
|
+
"email_placeholder": "nom@example.com",
|
|
8
|
+
"password": "Mot de passe",
|
|
9
|
+
"forgot_password": "Mot de passe oublié?",
|
|
10
|
+
"submit_btn": "Connexion"
|
|
11
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* @flow */
|
|
2
|
-
import
|
|
2
|
+
import i18next from "i18next"
|
|
3
3
|
import {initReactI18next} from "react-i18next"
|
|
4
4
|
import ChainedBackend from "i18next-chained-backend"
|
|
5
5
|
import resourcesToBackend from "i18next-resources-to-backend"
|
|
@@ -22,20 +22,33 @@ if (!locale) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// Do not call this code directly, it is injected from babel-plugin-i18next-client by the bundler
|
|
25
|
-
export
|
|
26
|
-
|
|
27
|
-
i18n
|
|
25
|
+
export const registerI18N = async (backendFn) => {
|
|
26
|
+
i18next
|
|
28
27
|
.use(ChainedBackend)
|
|
29
28
|
.use(initReactI18next)
|
|
30
29
|
.init({
|
|
31
30
|
lng: locale,
|
|
32
|
-
fallbackLng: (code) =>
|
|
31
|
+
fallbackLng: (code) => {
|
|
32
|
+
const val = getLocaleFromCode({ code, supported_locales: SUPPORTED_LOCALES, default_locale: DEFAULT_LOCALE })
|
|
33
|
+
// console.log("GOT VAL", {code, val})
|
|
34
|
+
return val
|
|
35
|
+
},
|
|
33
36
|
defaultNS: "common",
|
|
34
37
|
backend: {
|
|
35
|
-
backends: [
|
|
38
|
+
backends: [
|
|
39
|
+
// rb internal i18n
|
|
40
|
+
resourcesToBackend((lng, ns) => import(/* webpackChunkName: "rb-i18n" */ `./${lng}/${ns}.json`)),
|
|
41
|
+
// users's i18n
|
|
42
|
+
resourcesToBackend(backendFn)
|
|
43
|
+
],
|
|
36
44
|
},
|
|
37
45
|
interpolation: {
|
|
38
46
|
escapeValue: false,
|
|
39
47
|
},
|
|
40
48
|
})
|
|
49
|
+
|
|
50
|
+
// save preference to local storage so it works on reload
|
|
51
|
+
i18next.on('languageChanged', (lng) => {
|
|
52
|
+
localStorage.setItem(LOCALE_KEY, lng)
|
|
53
|
+
})
|
|
41
54
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpcbase/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.176.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"test": "../../node_modules/.bin/wireit"
|
|
6
6
|
},
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"@rpcbase/redbox-react": "0.3.0",
|
|
85
85
|
"figma-squircle": "0.3.1",
|
|
86
86
|
"firebase": "10.12.3",
|
|
87
|
-
"i18next": "23.
|
|
87
|
+
"i18next": "23.12.2",
|
|
88
88
|
"i18next-chained-backend": "4.6.2",
|
|
89
89
|
"i18next-resources-to-backend": "1.2.1",
|
|
90
90
|
"lz-string": "1.5.0",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"pouchdb-adapter-indexeddb": "8.0.1",
|
|
93
93
|
"pouchdb-core": "8.0.1",
|
|
94
94
|
"pouchdb-find": "8.0.1",
|
|
95
|
-
"react-i18next": "
|
|
95
|
+
"react-i18next": "15.0.0",
|
|
96
96
|
"socket.io-client": "4.7.5"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|