@openneuro/app 4.34.1 → 4.35.0-alpha.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.
Files changed (42) hide show
  1. package/package.json +3 -3
  2. package/src/scripts/authentication/profile.ts +3 -5
  3. package/src/scripts/common/containers/header.tsx +1 -2
  4. package/src/scripts/common/content/affiliate-content.jsx +1 -1
  5. package/src/scripts/common/partials/freshdesk-widget.jsx +5 -1
  6. package/src/scripts/components/header/Header.tsx +4 -10
  7. package/src/scripts/components/header/LandingExpandedHeader.tsx +11 -9
  8. package/src/scripts/components/header/header.scss +4 -2
  9. package/src/scripts/components/logo/Logo.tsx +1 -1
  10. package/src/scripts/components/modal/UserLoginModal.tsx +12 -11
  11. package/src/scripts/components/modal/__tests__/UserLoginModal.spec.tsx +1 -1
  12. package/src/scripts/components/page/Page.tsx +1 -2
  13. package/src/scripts/components/search-page/SearchResultItem.tsx +14 -13
  14. package/src/scripts/components/search-page/SearchResultsList.tsx +0 -19
  15. package/src/scripts/dataset/draft-container.tsx +0 -1
  16. package/src/scripts/dataset/snapshot-container.tsx +13 -11
  17. package/src/scripts/errors/freshdesk-widget.jsx +5 -1
  18. package/src/scripts/index.tsx +15 -2
  19. package/src/scripts/pages/__tests__/orcid-link.spec.tsx +13 -0
  20. package/src/scripts/pages/orcid-link.tsx +60 -0
  21. package/src/scripts/queries/user.ts +71 -0
  22. package/src/scripts/routes.tsx +2 -0
  23. package/src/scripts/scss/variables.scss +13 -9
  24. package/src/scripts/search/search-container.tsx +0 -9
  25. package/src/scripts/types/user-types.ts +2 -0
  26. package/src/scripts/users/__tests__/user-account-view.spec.tsx +36 -22
  27. package/src/scripts/users/__tests__/user-query.spec.tsx +3 -3
  28. package/src/scripts/users/__tests__/user-routes.spec.tsx +28 -11
  29. package/src/scripts/users/__tests__/user-tabs.spec.tsx +12 -9
  30. package/src/scripts/users/scss/user-menu.scss +133 -0
  31. package/src/scripts/users/scss/usernotifications.module.scss +1 -1
  32. package/src/scripts/users/user-account-view.tsx +35 -21
  33. package/src/scripts/users/user-container.tsx +2 -1
  34. package/src/scripts/users/user-menu.tsx +114 -0
  35. package/src/scripts/users/user-notification-accordion.tsx +2 -2
  36. package/src/scripts/users/user-query.tsx +6 -36
  37. package/src/scripts/users/user-routes.tsx +7 -5
  38. package/src/scripts/users/user-tabs.tsx +4 -3
  39. package/src/scripts/validation/__tests__/__snapshots__/validation-issues.spec.tsx.snap +10 -1
  40. package/src/scripts/validation/validation-issues.tsx +7 -3
  41. package/src/scripts/components/user/UserMenu.tsx +0 -72
  42. package/src/scripts/components/user/user-menu.scss +0 -88
@@ -0,0 +1,114 @@
1
+ import React from "react"
2
+ import { Link } from "react-router-dom"
3
+ import { Dropdown } from "../components/dropdown/Dropdown"
4
+ import { useUser } from "../queries/user"
5
+ import "./scss/user-menu.scss"
6
+
7
+ export interface UserMenuProps {
8
+ signOutAndRedirect: () => void
9
+ }
10
+
11
+ export const UserMenu = (
12
+ { signOutAndRedirect }: UserMenuProps,
13
+ ) => {
14
+ //const inboxCount = 99
15
+
16
+ const { user } = useUser()
17
+
18
+ return (
19
+ <span className="user-menu-wrap">
20
+ {
21
+ /* {user?.orcid && (
22
+ <span className="notifications-link">
23
+ <Link to={`/user/${user?.orcid}/notifications/unread`}>
24
+ <i className="fa fa-inbox">
25
+ {inboxCount > 0 && (
26
+ <span className="count">
27
+ {inboxCount > 99
28
+ ? (
29
+ <span>
30
+ 99<span>+</span>
31
+ </span>
32
+ )
33
+ : inboxCount}
34
+ </span>
35
+ )}
36
+ </i>
37
+ <span className="sr-only">Account Info</span>
38
+ </Link>
39
+ </span>
40
+ )} */
41
+ }
42
+ <Dropdown
43
+ className={"user-menu-dropdown"}
44
+ label={user?.avatar
45
+ ? (
46
+ <img
47
+ className="user-menu-label avatar"
48
+ src={user?.avatar}
49
+ alt="User Avatar"
50
+ />
51
+ )
52
+ : <div className="user-menu-label">My Account</div>}
53
+ children={
54
+ <div className="user-menu-dropdown-list">
55
+ <ul>
56
+ <li className="dropdown-header">
57
+ <p>
58
+ <span>Hello</span> <br />
59
+ {user?.name} <br />
60
+ {user?.email}
61
+ </p>
62
+ <p>
63
+ <span>signed in via {user?.provider}</span>
64
+ </p>
65
+ </li>
66
+ <li>
67
+ {
68
+ /* {user?.orcid
69
+ ? <Link to={`/user/${user?.orcid}`}>My Datasets</Link>
70
+ : <Link to="/search?mydatasets">My Datasets</Link>} */
71
+ }
72
+ <Link to="/search?mydatasets">My Datasets</Link>
73
+ </li>
74
+
75
+ {
76
+ /* {user?.orcid && (
77
+ <li>
78
+ <Link to={`/user/${user?.orcid}/account`}>
79
+ Account Info
80
+ </Link>
81
+ </li>
82
+ )} */
83
+ }
84
+
85
+ <li className="user-menu-link">
86
+ <Link to="/keygen">Obtain an API Key</Link>
87
+ </li>
88
+ {user?.provider !== "orcid" && (
89
+ <li className="user-menu-link">
90
+ <a href="/crn/auth/orcid?link=true">
91
+ Link ORCID to my account
92
+ </a>
93
+ </li>
94
+ )}
95
+ {user?.admin && (
96
+ <li className="user-menu-link">
97
+ <Link to="/admin">Admin</Link>
98
+ </li>
99
+ )}
100
+ <li className="user-menu-link">
101
+ <a
102
+ onClick={() => signOutAndRedirect()}
103
+ className="btn-submit-other"
104
+ >
105
+ Sign Out
106
+ </a>
107
+ </li>
108
+ </ul>
109
+ </div>
110
+ }
111
+ />
112
+ </span>
113
+ )
114
+ }
@@ -84,7 +84,7 @@ export const NotificationAccordion = ({ notification, onUpdate }) => {
84
84
  >
85
85
  <img
86
86
  className={`${styles.accordionicon} ${styles.saveicon}`}
87
- src={iconSaved}
87
+ src={iconUnread}
88
88
  alt=""
89
89
  />
90
90
  <span className="sr-only">Save</span>
@@ -114,7 +114,7 @@ export const NotificationAccordion = ({ notification, onUpdate }) => {
114
114
  >
115
115
  <img
116
116
  className={`${styles.accordionicon} ${styles.unreadicon}`}
117
- src={iconUnread}
117
+ src={iconSaved}
118
118
  alt=""
119
119
  />
120
120
  <span className="sr-only">Mark as Unread</span>
@@ -3,45 +3,15 @@ import { useParams } from "react-router-dom"
3
3
  import { UserRoutes } from "./user-routes"
4
4
  import FourOFourPage from "../errors/404page"
5
5
  import { isValidOrcid } from "../utils/validationUtils"
6
- import { gql, useQuery } from "@apollo/client"
7
6
  import { isAdmin } from "../authentication/admin-user"
8
7
  import { useCookies } from "react-cookie"
9
8
  import { getProfile } from "../authentication/profile"
10
-
11
- // GraphQL query to fetch user by ORCID
12
- export const GET_USER_BY_ORCID = gql`
13
- query User($userId: ID!) {
14
- user(id: $userId) {
15
- id
16
- name
17
- orcid
18
- email
19
- avatar
20
- location
21
- institution
22
- links
23
- }
24
- }
25
- `
26
-
27
- export const UPDATE_USER = gql`
28
- mutation updateUser($id: ID!, $location: String, $links: [String], $institution: String) {
29
- updateUser(id: $id, location: $location, links: $links, institution: $institution) {
30
- id
31
- location
32
- links
33
- institution
34
- }
35
- }
36
- `
9
+ import { useUser } from "../queries/user"
37
10
 
38
11
  export const UserQuery: React.FC = () => {
39
12
  const { orcid } = useParams()
40
13
  const isOrcidValid = orcid && isValidOrcid(orcid)
41
- const { data, loading, error } = useQuery(GET_USER_BY_ORCID, {
42
- variables: { userId: orcid },
43
- skip: !isOrcidValid,
44
- })
14
+ const { user, loading, error } = useUser()
45
15
 
46
16
  const [cookies] = useCookies()
47
17
  const profile = getProfile(cookies)
@@ -53,16 +23,16 @@ export const UserQuery: React.FC = () => {
53
23
 
54
24
  if (loading) return <div>Loading...</div>
55
25
 
56
- if (error || !data?.user || data.user.orcid !== orcid) {
26
+ if (error || !user || user?.orcid !== orcid) {
57
27
  return <FourOFourPage />
58
28
  }
59
29
 
60
30
  if (!profile || !profile.sub) {
61
31
  return <FourOFourPage />
62
32
  }
63
-
64
33
  // is admin or profile matches id from the user data being returned
65
- const hasEdit = isAdminUser || (data.user.id === profile?.sub) ? true : false
34
+ const isUser = (user?.id === profile?.sub) ? true : false
35
+ const hasEdit = isAdminUser || (user?.id === profile?.sub) ? true : false
66
36
  // Render user data with UserRoutes
67
- return <UserRoutes user={data.user} hasEdit={hasEdit} />
37
+ return <UserRoutes user={user} hasEdit={hasEdit} isUser={isUser} />
68
38
  }
@@ -14,13 +14,17 @@ import {
14
14
 
15
15
  import type { UserRoutesProps } from "../types/user-types"
16
16
 
17
- export const UserRoutes: React.FC<UserRoutesProps> = ({ user, hasEdit }) => {
17
+ export const UserRoutes: React.FC<UserRoutesProps> = (
18
+ { user, hasEdit, isUser },
19
+ ) => {
18
20
  return (
19
21
  <Routes>
20
22
  <Route path="/*" element={<FourOFourPage />} />
21
23
  <Route
22
24
  path="*"
23
- element={<UserAccountContainer user={user} hasEdit={hasEdit} />}
25
+ element={
26
+ <UserAccountContainer user={user} hasEdit={hasEdit} isUser={isUser} />
27
+ }
24
28
  >
25
29
  <Route
26
30
  path=""
@@ -28,9 +32,7 @@ export const UserRoutes: React.FC<UserRoutesProps> = ({ user, hasEdit }) => {
28
32
  />
29
33
  <Route
30
34
  path="account"
31
- element={hasEdit
32
- ? <UserAccountView user={user} />
33
- : <FourOThreePage />}
35
+ element={hasEdit ? <UserAccountView /> : <FourOThreePage />}
34
36
  />
35
37
  <Route
36
38
  path="notifications/*"
@@ -4,10 +4,11 @@ import styles from "./scss/usertabs.module.scss"
4
4
 
5
5
  export interface UserAccountTabsProps {
6
6
  hasEdit: boolean
7
+ isUser?: boolean
7
8
  }
8
9
 
9
10
  export const UserAccountTabs: React.FC<UserAccountTabsProps> = (
10
- { hasEdit },
11
+ { hasEdit, isUser },
11
12
  ) => {
12
13
  const ulRef = useRef<HTMLUListElement>(null)
13
14
  const [activePosition, setActivePosition] = useState<number>(0)
@@ -46,7 +47,7 @@ export const UserAccountTabs: React.FC<UserAccountTabsProps> = (
46
47
  className={({ isActive }) => (isActive ? styles.active : "")}
47
48
  onClick={handleClick}
48
49
  >
49
- User Datasets
50
+ {isUser ? "My" : "User"} Datasets
50
51
  </NavLink>
51
52
  </li>
52
53
  <li>
@@ -56,7 +57,7 @@ export const UserAccountTabs: React.FC<UserAccountTabsProps> = (
56
57
  className={({ isActive }) => (isActive ? styles.active : "")}
57
58
  onClick={handleClick}
58
59
  >
59
- User Notifications
60
+ Notifications
60
61
  </NavLink>
61
62
  </li>
62
63
  <li>
@@ -9,8 +9,17 @@ exports[`Issue component > renders one issue 1`] = `
9
9
  class="e-meta"
10
10
  >
11
11
  <label>
12
- /dataset_description.json
12
+ Location:
13
13
  </label>
14
+ /dataset_description.json
15
+ </div>
16
+ <div
17
+ class="e-meta"
18
+ >
19
+ <label>
20
+ Subcode:
21
+ </label>
22
+ DatasetType
14
23
  </div>
15
24
  <div
16
25
  class="e-meta"
@@ -18,15 +18,19 @@ export function Issue({ datasetIssues, issue, groupBy }: IssueProps) {
18
18
  {groupBy === "location"
19
19
  ? (
20
20
  <div className="e-meta">
21
- <label>{issue.code}</label>
22
- <span>{issue.subCode ? ` - ${issue.subCode}` : ""}</span>
21
+ <label>Code:</label> {issue.code}
23
22
  </div>
24
23
  )
25
24
  : (
26
25
  <div className="e-meta">
27
- <label>{issue.location}</label>
26
+ <label>Location:</label> {issue.location}
28
27
  </div>
29
28
  )}
29
+ {issue.subCode && (
30
+ <div className="e-meta">
31
+ <label>Subcode:</label> {issue.subCode}
32
+ </div>
33
+ )}
30
34
  <div className="e-meta">
31
35
  <label>Rule:</label> {issue.rule}
32
36
  </div>
@@ -1,72 +0,0 @@
1
- import React from "react"
2
- import { Link } from "react-router-dom"
3
- import { Dropdown } from "../dropdown/Dropdown"
4
- import "./user-menu.scss"
5
-
6
- export interface UserMenuProps {
7
- profile: {
8
- name: string
9
- admin: boolean
10
- email: string
11
- provider: string
12
- }
13
- signOutAndRedirect: () => void
14
- }
15
-
16
- export const UserMenu = ({ profile, signOutAndRedirect }: UserMenuProps) => {
17
- return (
18
- <Dropdown
19
- className={"user-menu-dropdown"}
20
- label={<div className="user-menu-label">My Account</div>}
21
- children={
22
- <div className="user-menu-dropdown-list">
23
- <ul>
24
- <li className="dropdown-header">
25
- <p>
26
- <span>Hello</span> <br />
27
- {profile.name}
28
- </p>
29
- <p>
30
- <span>signed in as</span>
31
- <br />
32
- {profile.email}
33
- {" "}
34
- </p>
35
- <p>
36
- <span>via</span>
37
- <br /> {profile.provider}
38
- </p>
39
- </li>
40
- <li>
41
- <Link to="/search?mydatasets">My Datasets</Link>
42
- </li>
43
- <li className="user-menu-link">
44
- <Link to="/keygen">Obtain an API Key</Link>
45
- </li>
46
- {profile.provider !== "orcid" && (
47
- <li className="user-menu-link">
48
- <a href="/crn/auth/orcid?link=true">
49
- {" "}
50
- Link ORCID to my account{" "}
51
- </a>
52
- </li>
53
- )}
54
- {profile.admin && (
55
- <li className="user-menu-link">
56
- <Link to="/admin">Admin</Link>
57
- </li>
58
- )}
59
- <li className="user-menu-link">
60
- <a
61
- onClick={() => signOutAndRedirect()}
62
- className="btn-submit-other"
63
- >
64
- Sign Out
65
- </a>
66
- </li>
67
- </ul>
68
- </div>
69
- }
70
- />
71
- )
72
- }
@@ -1,88 +0,0 @@
1
- @import '../scss/variables';
2
-
3
- .user-menu-dropdown {
4
- position: relative;
5
- .menu {
6
- box-shadow: 0px 0px 5px -4px black;
7
- background-color: #fff;
8
- border-radius: $border-radius-default;
9
- width: 100%;
10
- min-width: 250px;
11
- right: 0px;
12
- top: 60px;
13
- }
14
-
15
- .user-menu-dropdown-list {
16
- ul {
17
- list-style: none;
18
- margin: 0;
19
- padding: 20px;
20
- li {
21
- text-align: center;
22
- border-bottom: 1px solid $newspaper;
23
- &.dropdown-header {
24
- padding: 10px 0;
25
- font-size: 14px;
26
- p:first-child {
27
- margin-top: 0;
28
- }
29
- span {
30
- color: #3d3d3d;
31
- font-weight: bold;
32
- font-size: 12px;
33
- }
34
- }
35
- a {
36
- display: block;
37
- text-decoration: none;
38
- padding: 10px 0;
39
- &:hover {
40
- background-color: #eee;
41
- }
42
- }
43
- &:last-child {
44
- border: 0;
45
- margin: 0;
46
- padding: 0;
47
- }
48
- }
49
- }
50
- }
51
-
52
- .active {
53
- img {
54
- opacity: 0.5;
55
- }
56
- i {
57
- color: $on-light-aqua;
58
- }
59
- }
60
- }
61
-
62
- .header-account-btn {
63
- display: flex;
64
- align-items: center;
65
- background: #eee;
66
- border-radius: $border-radius-default;
67
-
68
- button.on-no-background.icon-text {
69
- color: $on-dark-aqua;
70
- margin: 5px 20px 0;
71
- font-size: 16px;
72
- }
73
- }
74
- .header-account-btn .toggle {
75
- color: #204e5a;
76
- font-weight: bold;
77
- font-size: 14px;
78
- padding: 20px 24px;
79
- @media (max-width: 800px) {
80
- padding: 10px;
81
- }
82
- }
83
- @media (max-width: 800px) {
84
- .header-account-btn .dropdown-wrapper .menu {
85
- right: -25vw;
86
- left: -25vw;
87
- }
88
- }