Skip to content

Commit

Permalink
Merge pull request #313 from openstax/user-info-fetch
Browse files Browse the repository at this point in the history
User info fetch
  • Loading branch information
chrisbendel authored Nov 8, 2023
2 parents 5095ae8 + d57db3e commit db47ab1
Show file tree
Hide file tree
Showing 16 changed files with 81 additions and 67 deletions.
1 change: 1 addition & 0 deletions frontend/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
parser: '@typescript-eslint/parser',
'extends': [
'eslint:recommended',
'plugin:react-hooks/recommended',
// "plugin:react/recommended", // TODO: enable once
],
'ignorePatterns': ['**/api/**/*.js'],
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@faker-js/faker": "^6.1.2",
"@playwright/test": "^1.36.2",
"@vitejs/plugin-react-refresh": "^1.3.6",
"eslint-plugin-react-hooks": "^4.6.0",
"expect-playwright": "^0.8.0",
"npm-run-all": "^4.1.5",
"typescript": "^4.7.4",
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/incorrect-user.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { React } from '@common'
import { OXColoredStripe } from '@components'
import { loginURL } from '@lib'
import { useLoginURL } from '@lib'

export interface IncorrectUserProps {
desiredRole?: string
}
export const IncorrectUser:React.FC<IncorrectUserProps> = ({ desiredRole }) => {
const loginURL = useLoginURL()

return (
<div className="incorrect-user" data-testid="incorrect-user-panel">
<OXColoredStripe />
<div className="container mt-4">
<h1>Looks like you‘re not logged in{desiredRole ? ` as a ${desiredRole}` : ''}.</h1>
<p>Please <a data-testid="login-link" href={loginURL()}>log in</a> before using this site</p>
<p>Please <a data-testid="login-link" href={loginURL}>log in</a> before using this site</p>
</div>
</div>
)
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/multi-session-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export const MultiSessionBar: FC<{ study: ParticipantStudy }> = ({ study }) => {

const [first, last] = study.stages
const perc = (filter(study.stages, 'isCompleted').length / study.stages.length) * 100

// TODO Come back to this
// eslint-disable-next-line react-hooks/rules-of-hooks
const duration = useMemo(() => {
const d = last.availableAfterDays || 0
if (d === 0) return 'immediately'
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/navbar/account-links.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { logoutURL, useCurrentUser, useEnvironment, useFetchEnvironment } from '@lib';
import { useLogoutURL, useCurrentUser, useEnvironment, useFetchEnvironment } from '@lib';
import { Menu } from '@mantine/core';
import { logout } from '@models';
import { React } from '@common';
Expand All @@ -9,6 +9,7 @@ export default function AccountLinks() {
const env = useEnvironment()
const { refetch } = useFetchEnvironment()
const isAdminOrResearcher = user.isAdministrator || user.isResearcher
const logoutURL = useLogoutURL()

return (
<>
Expand All @@ -19,7 +20,7 @@ export default function AccountLinks() {
</Menu.Item>
</StyledLink>
{!env.isImpersonating &&
<StyledLink to={logoutURL()} onClick={() => {
<StyledLink to={logoutURL} onClick={() => {
logout().then(() => refetch())
}}>
<Menu.Item>
Expand Down
41 changes: 22 additions & 19 deletions frontend/src/lib/environment-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { React } from '@common'
import { UserInfo } from '@models'
import { ErrorPage, IncorrectUser, LoadingAnimation } from '@components'

import { ENV } from './env'
import { useApi } from './api-config'
import { useQuery } from 'react-query';
import { Environment } from '@api'
import { UserInfo } from '@models';

export const EnvironmentContext = React.createContext<Environment | null>(null)

Expand Down Expand Up @@ -57,8 +56,11 @@ export const useCurrentResearcher = () => {
}

export const useUserInfo = () => {
return useQuery('fetchUserInfo', () => {
return fetchUserInfo()
const accountsApiURL = useAccountsApiURL()

return useQuery('fetchUserInfo', async (): Promise<UserInfo> => {
const resp = await fetch(`${accountsApiURL}`, { credentials: 'include' })
return await resp.json()
})
}

Expand All @@ -70,38 +72,39 @@ export const useUserPreferences = () => {
})
}

export const locationOrigin = () => {
export const useLocationOrigin = () => {
const env = useEnvironment()
if (env.accountsEnvName === 'production') {
return `https://openstax.org`;
}
return `https://${env.accountsEnvName}.openstax.org`;
}

export const loginURL = () => {
const url = accountsUrl()
export const useLoginURL = () => {
const url = useAccountsURL()
if (ENV.IS_DEV_MODE) return url

return `${url}/login/?r=${encodeURIComponent(window.location.href)}`
}

export const logoutURL = () => {
export const useLogoutURL = () => {
const locationOrigin = useLocationOrigin()
const accountsURL = useAccountsURL()
if (ENV.IS_DEV_MODE) return '/dev/user';
const homepage = encodeURIComponent(`${locationOrigin()}/kinetic`);
return `${accountsUrl()}/signout?r=${homepage}`;
const homepage = encodeURIComponent(`${locationOrigin}/kinetic`);
return `${accountsURL}/signout?r=${homepage}`;
}

export const accountsUrl = (): string => {
export const useAccountsURL = (): string => {
const locationOrigin = useLocationOrigin()

if (ENV.IS_DEV_MODE) return '/dev/user'
return `${locationOrigin()}/accounts`;
return `${locationOrigin}/accounts`;
}

export const accountsApiUrl = (): string => {
if (ENV.IS_DEV_MODE) return `${ENV.API_ADDRESS}/development/user/api/user`
return `${accountsUrl()}/api/user`
}
export const useAccountsApiURL = (): string => {
const accountsURL = useAccountsURL()

export const fetchUserInfo = async (): Promise<UserInfo> => {
const resp = await fetch(`${accountsApiUrl()}`, { credentials: 'include' })
return resp.json()
if (ENV.IS_DEV_MODE) return `${ENV.API_ADDRESS}/development/user/api/user`
return `${accountsURL}/api/user`
}
9 changes: 5 additions & 4 deletions frontend/src/screens/account-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { React } from '@common'
import styled from '@emotion/styled'
import { colors } from '@theme'

import { accountsUrl, useApi, useIsMobileDevice, useUserInfo, useUserPreferences } from '@lib'
import { useAccountsURL, useApi, useIsMobileDevice, useUserInfo, useUserPreferences } from '@lib'
import {
Box,
Footer,
Expand Down Expand Up @@ -74,10 +74,11 @@ const Sidebar = () => {

export default function AccountDetails() {
const api = useApi()
const { data: userInfo } = useUserInfo()
const isMobile = useIsMobileDevice()

const { data: userInfo } = useUserInfo()
const { data: prefs } = useUserPreferences()
const accountsURL = useAccountsURL()

if (!userInfo || !prefs) return <LoadingAnimation message="Loading account…" />;

const email = userInfo.contact_infos.find(e => e.type == 'EmailAddress')
Expand All @@ -94,7 +95,7 @@ export default function AccountDetails() {
<h2 className="mb-3">My Account</h2>
<Box justify='between' align="center">
<h5 className="mb-0 p-0">General</h5>
<a href={`${accountsUrl()}`}>
<a href={`${accountsURL}`}>
<span>Update Account</span>
<Icon icon="chevronRight" />
</a>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/screens/analysis/runs-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ const StatusIcon = styled(Icon)({
})

const useRunsTable = (analysis: Analysis) => {
const api = useApi()

const [sorting, setSorting] = React.useState<SortingState>([{
id: 'startedAt',
desc: true,
Expand Down Expand Up @@ -181,7 +183,6 @@ const useRunsTable = (analysis: Analysis) => {
size: 375,
enableSorting: false,
cell: ({ row: { original: run } }: { row: { original: AnalysisRun } }) => {
const api = useApi()
const canDownload = hasRunSucceeded(run)
const cancelRun = () => {
api.updateAnalysisRun({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,18 @@ const StyledForm = styled(Form<Researcher>)(({ readOnly }) => ({
export const ResearcherAccountForm: React.FC<{className?: string}> = ({ className }) => {
const api = useApi()
const [researcher, setResearcher] = useState(useCurrentResearcher())
const [institution, setInstitution] = useState(researcher?.institution)
const { refetch: refetchEnv } = useFetchEnvironment()
const { data: userInfo, refetch: refetchUser } = useUserInfo()

if (!researcher) {
return null
}

// Default to OpenStax accounts first/last name if blank
researcher.firstName = researcher.firstName || userInfo?.first_name
researcher.lastName = researcher.lastName || userInfo?.last_name

const [institution, setInstitution] = useState(researcher.institution)

const saveResearcher = async (researcher: Researcher) => {
try {
if (!researcher.id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box, Col, Footer, Form, HelpLink, Icon, Modal, ResourceLinks, Tooltip, TopNavBar } from '@components';
import { React, styled, useState } from '@common';
import { accountsUrl, useApi, useCurrentResearcher } from '@lib';
import { useAccountsURL, useApi, useCurrentResearcher } from '@lib';
import { colors } from '@theme';
import { Researcher } from '@api';
import CustomerSupportImage from '../../../components/customer-support-image';
Expand All @@ -11,6 +11,7 @@ import { ResearcherAccountForm } from './researcher-account-form';

export default function ResearcherAccountPage() {
const researcher = useCurrentResearcher()
const accountsUrl = useAccountsURL()

if (!researcher) {
return null
Expand All @@ -23,7 +24,7 @@ export default function ResearcherAccountPage() {
<Col sm={9} css={{ paddingRight: '2rem' }} direction='column'>
<Box justify='between' height='40px'>
<h3>My Account</h3>
<a href={`${accountsUrl()}`} target='_blank'>
<a href={`${accountsUrl}`} target='_blank'>
<span>Update Email & Password</span>
<Icon icon="chevronRight" />
</a>
Expand Down Expand Up @@ -122,6 +123,9 @@ export const IRB = () => {
const Avatar: React.FC = () => {
const api = useApi()
const [researcher, setResearcher] = useState(useCurrentResearcher())
const [avatar, setAvatar] = useState<Blob>()
const [isShowingModal, setShowingModal] = useState(false)

if (!researcher) {
return null
}
Expand All @@ -133,8 +137,7 @@ const Avatar: React.FC = () => {
height: 125,
width: 125,
})
const [avatar, setAvatar] = useState<Blob>()
const [isShowingModal, setShowingModal] = useState(false)

const onHide = () => setShowingModal(false)

const saveResearcher = async (researcher: Researcher) => {
Expand All @@ -149,7 +152,6 @@ const Avatar: React.FC = () => {
onHide()
}


return (
<Box className='col-2' justify='start' direction='column'>
<Box onClick={() => setShowingModal(true)} direction='column' align='center' gap='large' css={{ cursor: 'pointer' }} >
Expand Down
9 changes: 3 additions & 6 deletions frontend/src/screens/researcher/studies/create/edit-study.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, React, useEffect, useMemo, useNavigate, useParams, useState, Yup } from '@common'
import { Box, React, useMemo, useNavigate, useParams, useState, Yup } from '@common'
import { useApi, useQueryParam } from '@lib';
import { isDraft, useFetchStudy } from '@models';
import {
Expand All @@ -24,6 +24,7 @@ import { colors } from '@theme';
import { ReviewStudy, SubmitStudyModal } from './forms/review-study';
import { noop } from 'lodash-es';
import { useLocalstorageState } from 'rooks';
import { Navigate } from 'react-router-dom';

const buildValidationSchema = (allOtherStudies: Study[]) => {
return Yup.object().shape({
Expand All @@ -46,7 +47,6 @@ const getFormDefaults = (study: Study, step: StudyStep) => {
}

export default function EditStudy() {
const nav = useNavigate()
const id = useParams<{ id: string }>().id
const { loading, study, setStudy, allStudies } = useFetchStudy(id || 'new')

Expand All @@ -55,10 +55,7 @@ export default function EditStudy() {
}

if (!study) {
useEffect(() => {
nav('/studies')
}, [])
return <></>
return <Navigate to={'/studies'} />
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ const AdditionalSession: FC<{
onDelete: (index: number) => void,
session: Stage | NewStage
}> = ({ index, onDelete, session }) => {
const { register, getValues } = useFormContext()

// don't show the first session
if (index === 0) return null
const { register, getValues } = useFormContext()
const prevStagePoints = getValues(`stages.${index - 1}.points`)

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,11 +277,12 @@ const ShareStudy: FC<{study: Study}> = () => {
}

const ClosingCriteria: FC<{study: Study}> = ({ study }) => {
const { watch, setValue, getValues, trigger } = useFormContext()

const firstStage = getFirstStage(study)
if (!firstStage) {
return null
}
const { watch, setValue, getValues, trigger } = useFormContext()

return (
<Box gap='xlarge'>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, React, useEffect, useNavigate, useParams } from '@common';
import { Box, React, useNavigate, useParams } from '@common';
import { Study } from '@api';
import { Col, CollapsibleSection, ExitButton, LoadingAnimation, Page, ResearcherButton } from '@components';
import { getStudyLead, getStudyPi, isReadyForLaunch, isWaiting, useFetchStudy } from '@models';
Expand All @@ -8,33 +8,24 @@ import { FinalizeStudy } from './finalize-study';
import Waiting from '@images/study-creation/waiting.svg'
import { EditSubmittedStudy } from './edit-submitted-study';
import { useQueryParam } from '@lib';
import { Link } from 'react-router-dom';
import { Link, Navigate } from 'react-router-dom';

export default function StudyOverview() {
const nav = useNavigate()
const id = useParams<{ id: string }>().id
const { loading, study } = useFetchStudy(id!)

if (!id) {
useEffect(() => {
nav('/studies')
}, [])
return <></>
return <Navigate to='/studies' />
}

const { loading, study } = useFetchStudy(id)

if (loading) {
return <LoadingAnimation />
}

if (!study) {
useEffect(() => {
nav('/studies')
}, [])
return <></>
return <Navigate to='/studies' />
}


return (
<Page hideFooter backgroundColor={colors.white}>
<StudyOverviewContent study={study} />
Expand Down
Loading

0 comments on commit db47ab1

Please sign in to comment.