Skip to content

Commit 6ab5b53

Browse files
✨ specialists can nominate other specialists (#374)
This allows specialists to nominate and demote other specialists of the same specialty, through the same screen as the admins. In order to write an e2e test for this use case, we needed e2e tests to have more control over the user that is stored on the front end, so we had to refactor how the DISABLE_AUTH flag works.
1 parent 36b4f9b commit 6ab5b53

File tree

12 files changed

+126
-70
lines changed

12 files changed

+126
-70
lines changed

client/src/components/Authenticated/Authenticated.jsx

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,20 @@ import { Redirect } from 'react-router-dom'
55

66
import { useAuth } from 'contexts'
77

8-
const Authenticated = ({ location, reverse, redirect, children, admin }) => {
9-
const { isAuth, isAdmin } = useAuth()
8+
const Authenticated = ({ location, reverse, redirect, children, admin, specialist }) => {
9+
const { isAuth, isAdmin, isSpecialist } = useAuth()
10+
const currentURL = location.pathname + location.search
1011

11-
if (import.meta.env.VITE_DISABLE_AUTH === 'true') {
12+
if (admin && isAdmin) {
1213
return children
1314
}
1415

15-
const currentURL = location.pathname + location.search
16+
if (specialist && isSpecialist) {
17+
return children
18+
}
1619

17-
if (admin) {
18-
if (!isAdmin) {
19-
return redirect ? <Redirect to="/" /> : ''
20-
} else {
21-
return children
22-
}
20+
if (admin || specialist) {
21+
return redirect ? <Redirect to="/" /> : ''
2322
}
2423

2524
if ((isAuth && !reverse) || (!isAuth && reverse)) {

client/src/components/PrivateRoute/PrivateRoute.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { Route } from 'react-router-dom'
44

55
import Authenticated from 'components/Authenticated'
66

7-
const PrivateRoute = ({ component: Component, render, admin, ...otherProps }) => (
7+
const PrivateRoute = ({ component: Component, render, admin, specialist, ...otherProps }) => (
88
<Route
99
{...otherProps}
1010
render={props => (
11-
<Authenticated {...props} admin={admin} redirect="/auth/login">
11+
<Authenticated {...props} admin={admin} specialist={specialist} redirect="/auth/login">
1212
{Component ? <Component {...props} {...otherProps} /> : render(props)}
1313
</Authenticated>
1414
)}

client/src/components/UsersList/components/Specialist.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import { useMutation } from '@apollo/client'
22
import { alert, getIntl } from 'services'
33
import { UPDATE_SPECIALTIES } from '../queries'
44
import SpecialtiesList from './SpecialtiesList'
5+
import { useAuth, useUser } from 'contexts'
56

67
const Specialist = ({ specialist, services, onUpdateSpecialty }) => {
78
const intl = getIntl(Specialist)
89

910
const specialties = specialist.specialties
11+
const user = useUser()
12+
const { isAdmin } = useAuth()
1013

1114
const onSpecialtyChange = params => {
1215
const { action, data } = params
@@ -63,7 +66,7 @@ const Specialist = ({ specialist, services, onUpdateSpecialty }) => {
6366
{services && (
6467
<SpecialtiesList
6568
specialties={specialties}
66-
services={services}
69+
userSpecialties={isAdmin ? services : user.specialties}
6770
onChange={onSpecialtyChange}
6871
/>
6972
)}

client/src/components/UsersList/components/SpecialtiesList.jsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Button } from 'components'
33
import { useClickOutside } from 'helpers'
44
import { useState } from 'react'
55

6-
const SpecialtiesList = ({ specialties, services, onChange }) => {
6+
const SpecialtiesList = ({ specialties, userSpecialties, onChange }) => {
77
const [opened, setOpened] = useState(false)
88
const ref = useClickOutside(() => setOpened(false))
99

@@ -16,26 +16,26 @@ const SpecialtiesList = ({ specialties, services, onChange }) => {
1616
onClick={() => setOpened(opened => !opened)}
1717
/>
1818
<ul ref={ref} className="specialtiesList" style={{ display: opened ? 'flex' : 'none' }}>
19-
{services.map(service => {
20-
const isSelected = specialties?.filter(({ id }) => id === service.id).length > 0
19+
{userSpecialties.map(specialty => {
20+
const isSelected = specialties?.filter(({ id }) => id === specialty.id).length > 0
2121
return (
2222
<li
23-
key={service.id}
23+
key={specialty.id}
2424
className={cn('specialtyEl', {
2525
selected: isSelected
2626
})}
2727
onClick={() =>
2828
onChange(
2929
isSelected
3030
? {
31-
data: specialties.filter(specialty => specialty.id !== service.id),
31+
data: specialties.filter(specialty => specialty.id !== specialty.id),
3232
action: 'delete'
3333
}
34-
: { data: [...specialties, service], action: 'add' }
34+
: { data: [...specialties, specialty], action: 'add' }
3535
)
3636
}
3737
>
38-
<button className="specialtyButton">{service.name}</button>
38+
<button className="specialtyButton">{specialty.name}</button>
3939
</li>
4040
)
4141
})}

client/src/contexts/Auth/hooks.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const useAuth = () => {
88
const isAuth = !!(auth.session && auth.session.expiresAt > new Date().getTime() && auth.user)
99
const wasAuth = !!(auth.session && auth.session.expiresAt < new Date().getTime() && auth.user)
1010
const isAdmin = isAuth && auth.user && auth.user.admin
11+
const isSpecialist = isAuth && auth.user && (auth.user.specialties?.length > 0 ?? false)
1112

12-
return { ready: auth.ready, isAuth, wasAuth, isAdmin, ...actions }
13+
return { ready: auth.ready, isAuth, wasAuth, isAdmin, isSpecialist, ...actions }
1314
}

client/src/contexts/User/queries.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export const GET_ME = gql`
99
email
1010
picture
1111
specialties {
12+
id
1213
name
1314
}
1415
}

client/src/scenes/App/AppBody.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const AppBody = () => {
3030
<Route path="/auth" component={Auth} />
3131
<PrivateRoute path="/q" component={Question} />
3232
<PrivateRoute path="/user-profile" component={UserProfile} />
33-
<PrivateRoute path="/settings" component={Settings} admin />
33+
<PrivateRoute path="/settings" component={Settings} admin specialist />
3434
<PrivateRoute component={NotFound} />
3535
</Switch>
3636
</ErrorBoundary>

client/src/scenes/App/components/Navbar/components/UserMenu/UserMenu.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const UserMenu = ({ history }) => {
2323
<DropdownItem icon="account_box" path="/user-profile">
2424
{intl('profile')}
2525
</DropdownItem>
26-
<Authenticated admin>
26+
<Authenticated admin specialist>
2727
<DropdownItem icon="settings" path="/settings">
2828
{intl('settings')}
2929
</DropdownItem>

client/src/scenes/Auth/Login.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const Login = ({ location }) => {
1515

1616
const { login, renewAuth, isAuth, wasAuth } = useAuth()
1717

18-
if (isAuth || import.meta.env.VITE_DISABLE_AUTH === 'true') {
18+
if (isAuth) {
1919
return <Redirect to="/" />
2020
}
2121

client/src/scenes/Settings/Settings.jsx

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useMutation } from '@apollo/client'
33

44
import { alert, getIntl } from 'services'
55

6-
import { useConfiguration } from 'contexts'
6+
import { useAuth, useConfiguration } from 'contexts'
77

88
import { Tabs, Button } from 'components'
99
import Card, { CardTitle, CardText, CardActions } from 'components/Card'
@@ -16,25 +16,18 @@ import { General, Tags, Synonyms, Integrations, Specialists } from './scenes'
1616

1717
import './Settings.scss'
1818

19-
let initState
20-
21-
if (import.meta.env.VITE_DISABLE_AUTH === 'true') {
22-
initState = conf => ({
23-
...conf,
24-
bugReporting: conf.bugReporting || 'GITHUB'
25-
})
26-
} else {
27-
initState = conf => ({
28-
...conf,
29-
synonyms: synonymsToList(conf.algoliaSynonyms),
30-
authorizedDomains: conf.authorizedDomains.join(', '),
31-
bugReporting: conf.bugReporting || 'GITHUB'
32-
})
33-
}
19+
const initState = conf => ({
20+
...conf,
21+
synonyms: synonymsToList(conf.algoliaSynonyms),
22+
authorizedDomains: conf.authorizedDomains.join(', '),
23+
bugReporting: conf.bugReporting || 'GITHUB'
24+
})
3425

3526
const Settings = ({ configuration: conf }) => {
3627
const intl = getIntl(Settings)
3728

29+
const { isAdmin, isSpecialist } = useAuth()
30+
3831
const configuration = useConfiguration()
3932

4033
const [loading, setLoading] = useState(false)
@@ -90,13 +83,17 @@ const Settings = ({ configuration: conf }) => {
9083
</CardTitle>
9184
<CardText>
9285
<Tabs>
93-
<General state={state} dispatch={dispatch} loading={loading} />
94-
<Tags state={state} onTagsChange={onTagsChange} />
95-
{import.meta.env.VITE_DISABLE_AUTH !== 'true' && (
96-
<Synonyms state={state} dispatch={dispatch} loading={loading} />
86+
{isAdmin && (
87+
<>
88+
<General state={state} dispatch={dispatch} loading={loading} />
89+
<Tags state={state} onTagsChange={onTagsChange} />
90+
<Synonyms state={state} dispatch={dispatch} loading={loading} />
91+
</>
92+
)}
93+
{(isAdmin || isSpecialist) && (
94+
<Specialists state={state} dispatch={dispatch} loading={loading} />
9795
)}
98-
<Specialists state={state} dispatch={dispatch} loading={loading} />
99-
<Integrations state={state} dispatch={dispatch} loading={loading} />
96+
{isAdmin && <Integrations state={state} dispatch={dispatch} loading={loading} />}
10097
</Tabs>
10198
</CardText>
10299
<CardActions>

0 commit comments

Comments
 (0)