@rpcbase/client 0.56.0 → 0.57.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.
@@ -0,0 +1,67 @@
1
+ /* @flow */
2
+ import assert from "assert"
3
+ import {useTranslation} from "react-i18next"
4
+ import page from "page"
5
+
6
+ import Avatar from "ui/avatars/Avatar"
7
+ import getInitials from "ui/avatars/Avatar/getInitials"
8
+
9
+ import "./account-list-item.scss"
10
+
11
+ const getAvatarText = (user) => {
12
+ if (user.initials) return user.initials
13
+
14
+ const fullName = `${user.first_name || ""} ${user.last_name || ""}`
15
+ let initials = getInitials(fullName)
16
+
17
+ if (!initials) initials = "?"
18
+
19
+ return initials
20
+ }
21
+
22
+
23
+ const getTenantName = (tenant) => {
24
+ if (tenant.short_name) return tenant.short_name
25
+ else if (tenant.name) return tenant.name
26
+ else return tenant.slug
27
+ }
28
+
29
+ const getUserName = (user) => {
30
+ let name = ""
31
+
32
+ if (user.first_name) {
33
+ name += user.first_name
34
+ }
35
+
36
+ if (user.last_name) {
37
+ name += ` ${user.last_name}`
38
+ }
39
+
40
+ if (!name && user.initials) {
41
+ name += user.initials
42
+ }
43
+
44
+ if (!name) {
45
+ name = user.email
46
+ }
47
+
48
+ return name
49
+ }
50
+
51
+ const AccountListItem = ({account, onClick, avatarProps}) => {
52
+
53
+ return (
54
+ <div
55
+ key={`acc-${account.user._id}`}
56
+ className="account-list-item d-flex flex-row"
57
+ onClick={() => onClick(account)}
58
+ >
59
+ <div>
60
+ <Avatar className="me-2" size="small" text={getAvatarText(account.user)} color={account.user.avatar_color} {...avatarProps} />
61
+ </div>
62
+ <div style={{wordBreak: "break-all"}}>{getTenantName(account.tenant)} / {getUserName(account.user)}</div>
63
+ </div>
64
+ )
65
+ }
66
+
67
+ export default AccountListItem
@@ -0,0 +1,5 @@
1
+ @import "helpers";
2
+
3
+ .account-list-item {
4
+ cursor: pointer;
5
+ }
@@ -0,0 +1,19 @@
1
+ /* @flow */
2
+ import AccountListItem from "./AccountListItem"
3
+
4
+
5
+ const AccountsList = ({accounts}) => {
6
+
7
+ return (
8
+ <>
9
+ {accounts.map((acc) => (
10
+ <AccountListItem
11
+ key={`acc-${acc.user._id}`}
12
+ account={acc}
13
+ />
14
+ ))}
15
+ </>
16
+ )
17
+ }
18
+
19
+ export default AccountsList
@@ -1,4 +1,5 @@
1
1
  /* @flow */
2
+ import assert from "assert"
2
3
  import {useState, useEffect} from "react"
3
4
  import {ActivityIndicator} from "react-native"
4
5
  import page from "page"
@@ -6,49 +7,95 @@ import page from "page"
6
7
  import post from "../../helpers/post"
7
8
 
8
9
  import {set_is_signed_in, set_uid} from "../index"
10
+ import AccountListItem from "../AccountsList/AccountListItem"
11
+ import Footer from "../Footer"
12
+
13
+ import "./sign-out.scss"
9
14
 
10
15
  // TODO: rts_disconnect
11
16
  // TODO: clear cache + db
12
17
 
13
18
  const SignOut = ({
19
+ name,
14
20
  onSuccess = () => null
15
21
  }) => {
16
22
 
17
23
  const [isSignedOut, setIsSignedOut] = useState(false)
18
24
 
25
+ const [accounts, setAccounts] = useState([])
26
+
19
27
  useEffect(() => {
20
- setTimeout(async() => {
21
- const res = await post("/api/v1/auth/sign_out")
22
- if (res.status === "ok") {
23
- set_uid(null)
24
- set_is_signed_in(false)
25
- localStorage.clear()
26
-
27
- // TODO: clear DB
28
-
29
- setIsSignedOut(true)
30
- onSuccess()
31
- } else {
32
- throw new Error("unable to sign out")
33
- }
34
- }, 60)
28
+ const load = async() => {
29
+ const res = await post("/api/v1/auth/get_accounts")
30
+ assert(res.status === "ok")
31
+ setAccounts(res.accounts)
32
+ console.log("ACCOUNTS", res.accounts)
33
+ }
35
34
 
35
+ load()
36
36
  }, [])
37
37
 
38
+
39
+ const signOut = async() => {
40
+ const res = await post("/api/v1/auth/sign_out")
41
+ if (res.status === "ok") {
42
+ set_uid(null)
43
+ set_is_signed_in(false)
44
+ localStorage.clear()
45
+
46
+ // TODO: clear DB
47
+
48
+ setIsSignedOut(true)
49
+ onSuccess()
50
+ } else {
51
+ throw new Error("unable to sign out")
52
+ }
53
+ }
54
+
55
+
56
+ const onClickAccount = () => {
57
+ console.log("clicked account")
58
+ }
59
+
60
+
61
+ const onSubmit = () => {
62
+ signOut()
63
+ }
64
+
38
65
  return (
39
66
  <div id="sign-out-wrapper">
40
- {!isSignedOut && (
41
- <div className="mt-3 d-flex justify-content-center align-items-center">
42
- <div className="me-2"><ActivityIndicator /></div>
43
- <div className="">Signing out, you will be redirected shortly</div>
44
- </div>
45
- )}
46
- {isSignedOut && (
47
- <div className="mt-3 d-flex flex-column flex-1 justify-content-center align-items-center">
48
- <div className="">Signed out</div>
49
- <a href="/">Home</a>
67
+ {isSignedOut && <div>signed out successfully</div>}
68
+ {accounts?.length > 0 && (<><div className="form-signout text-center px-4 py-4 shadow-lg">
69
+ <div>
70
+ <h1 className="h4 mt-3 mb-3 fw-normal">Sign Out</h1>
71
+ <p className="text-start text-muted">
72
+ Select accounts to sign out of:
73
+ </p>
74
+
75
+ <ul className="list-group text-start">
76
+ {accounts.map((acc, index) => {
77
+ const id = `acc-${acc.user_id}-${index}`
78
+ return (
79
+ <li key={id} className="list-group-item">
80
+ <input className="form-check-input me-3" type="checkbox" value="" id={id} />
81
+ <label className="form-check-label stretched-link" for={id}>
82
+ <AccountListItem
83
+ account={acc}
84
+ onClick={onClickAccount}
85
+ />
86
+ </label>
87
+ </li>
88
+ )
89
+ })}
90
+ </ul>
91
+
92
+ <button className="mt-4 mb-3 w-100 btn btn-lg btn-primary" type="submit" onClick={onSubmit}>Sign Out</button>
93
+
50
94
  </div>
51
- )}
95
+ </div>
96
+
97
+ <Footer name={name} />
98
+ </>)}
52
99
  </div>
53
100
  )
54
101
  }
@@ -0,0 +1,34 @@
1
+ @import "helpers";
2
+
3
+ #sign-out-wrapper {
4
+ height: 100%;
5
+ display: flex;
6
+ flex-direction: column;
7
+ align-items: center;
8
+ padding-top: 40px;
9
+ padding-bottom: 40px;
10
+ // background-color: var(--bs-secondary);
11
+ background-color: $gray-500;
12
+
13
+ footer {
14
+ color: $light !important;
15
+ border-top: none !important;
16
+ padding-top: 0 !important;
17
+ margin-bottom: 0 !important;
18
+ }
19
+
20
+
21
+ .form-signout {
22
+ width: 100%;
23
+ max-width: 380px;
24
+ margin: auto;
25
+ background-color: $light;
26
+ border-radius: 22px;
27
+ // border: 1px solid $gray-600;
28
+ }
29
+
30
+ .form-signout .checkbox {
31
+ font-weight: 400;
32
+ }
33
+
34
+ }
package/auth/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  /* @flow */
2
2
  import page from "page"
3
3
  import debug from "debug"
4
+ import isHexadecimal from "validator/lib/isHexadecimal"
4
5
 
5
6
  import {disconnect as rts_disconnect} from "../rts"
6
7
  import post from "../helpers/post"
@@ -18,8 +19,25 @@ let __tenant_id = typeof localStorage !== "undefined" && localStorage.getItem(LA
18
19
  let __user_id = typeof localStorage !== "undefined" && __tenant_id && localStorage.getItem(uid_storage_key(__tenant_id))
19
20
 
20
21
 
22
+ const get_querystring_auth_id = () => {
23
+ const url = new URL(window.location.href)
24
+ const val = url.searchParams.get("auth_id")
25
+ if (!val) return null
26
+
27
+ if (isHexadecimal(val) && val.length === 24) return val
28
+
29
+ return null
30
+ }
31
+
32
+
21
33
  const run_session_check = async() => {
22
- const res = await post("/api/v1/auth/check_session")
34
+ const auth_user_id = get_querystring_auth_id()
35
+
36
+ if (auth_user_id) {
37
+ log("check_session with auth user_id", auth_user_id)
38
+ }
39
+
40
+ const res = await post("/api/v1/auth/check_session", {auth_user_id})
23
41
 
24
42
  log("check_session response", res)
25
43
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/client",
3
- "version": "0.56.0",
3
+ "version": "0.57.0",
4
4
  "scripts": {
5
5
  "test": "echo \"Error: no test specified\" && exit 0"
6
6
  },