1
0
Fork 0
mirror of https://github.com/overleaf/overleaf.git synced 2025-04-14 17:33:34 +00:00

Merge pull request from overleaf/ii-7155-display-institution

Display the institution and role if applicable

GitOrigin-RevId: e00b07f0118e7f3ab8ec0b0f01b2b3e52fcc1cd2
This commit is contained in:
Tim Down 2022-04-14 10:19:18 +01:00 committed by Copybot
parent dc706b4942
commit e0d5cf4b42
11 changed files with 207 additions and 15 deletions

View file

@ -29,7 +29,7 @@ function Email({ userEmailData }: EmailProps) {
)}
{userEmailData.confirmedAt &&
userEmailData.affiliation?.institution.confirmed &&
userEmailData.affiliation?.licence !== 'free' && (
userEmailData.affiliation.licence !== 'free' && (
<div className="small">
<span className="label label-primary">{t('professional')}</span>
</div>

View file

@ -0,0 +1,50 @@
import { useTranslation } from 'react-i18next'
import { UserEmailData } from '../../../../../../types/user-email'
import { Button } from 'react-bootstrap'
type InstitutionAndRoleProps = {
userEmailData: UserEmailData
}
function InstitutionAndRole({ userEmailData }: InstitutionAndRoleProps) {
const { t } = useTranslation()
const { affiliation } = userEmailData
const handleAddRoleDepartment = () => {
console.log('TODO: add role department')
}
const handleChangeAffiliation = () => {
console.log('TODO: change affiliation')
}
if (!affiliation?.institution) {
return null
}
return (
<>
<div>{affiliation.institution.name}</div>
{!affiliation.department && !affiliation.role && (
<div className="small">
<Button className="btn-inline-link" onClick={handleAddRoleDepartment}>
{t('add_role_and_department')}
</Button>
</div>
)}
{(affiliation.role || affiliation.department) && (
<div className="small">
{[affiliation.role, affiliation.department]
.filter(Boolean)
.join(', ')}
<br />
<Button className="btn-inline-link" onClick={handleChangeAffiliation}>
{t('change')}
</Button>
</div>
)}
</>
)
}
export default InstitutionAndRole

View file

@ -1,6 +1,7 @@
import { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import Icon from '../../../../shared/components/icon'
import { Button } from 'react-bootstrap'
import useAsync from '../../../../shared/hooks/use-async'
import { postJSON } from '../../../../infrastructure/fetch-json'
import { UserEmailData } from '../../../../../../types/user-email'
@ -42,12 +43,12 @@ function ResendConfirmationEmailButton({
return (
<>
<button
className="btn btn-inline-link"
<Button
className="btn-inline-link"
onClick={handleResendConfirmationEmail}
>
{t('resend_confirmation_email')}
</button>
</Button>
<br />
{isError && (
<span className="text-danger">

View file

@ -1,6 +1,7 @@
import { UserEmailData } from '../../../../../../types/user-email'
import { Row, Col } from 'react-bootstrap'
import Email from './email'
import InstitutionAndRole from './institution-and-role'
import EmailCell from './cell'
type EmailsRowProps = {
@ -16,7 +17,11 @@ function EmailsRow({ userEmailData }: EmailsRowProps) {
</EmailCell>
</Col>
<Col sm={5}>
<EmailCell>todo</EmailCell>
{userEmailData.affiliation?.institution && (
<EmailCell>
<InstitutionAndRole userEmailData={userEmailData} />
</EmailCell>
)}
</Col>
<Col sm={2}>
<EmailCell>todo</EmailCell>

View file

@ -21,6 +21,7 @@ const fakeUsersData = [
affiliation: {
institution: {
confirmed: true,
name: 'Overleaf',
},
licence: 'pro_plus',
},
@ -34,6 +35,15 @@ const fakeUsersData = [
default: false,
},
{
affiliation: {
institution: {
confirmed: true,
name: 'Overleaf',
},
licence: 'pro_plus',
department: 'Art & Art History',
role: 'Reader',
},
email: 'baz@overleaf.com',
default: false,
},

View file

@ -0,0 +1,84 @@
import { render, screen } from '@testing-library/react'
import { expect } from 'chai'
import { UserEmailData } from '../../../../../../types/user-email'
import InstitutionAndRole from '../../../../../../frontend/js/features/settings/components/emails/institution-and-role'
const userData1: UserEmailData = {
affiliation: {
cachedConfirmedAt: null,
cachedPastReconfirmDate: false,
cachedReconfirmedAt: null,
department: null,
institution: {
commonsAccount: false,
confirmed: true,
id: 1,
isUniversity: false,
name: 'Overleaf',
ssoEnabled: false,
ssoBeta: false,
},
inReconfirmNotificationPeriod: false,
inferred: false,
licence: 'pro_plus',
pastReconfirmDate: false,
portal: { slug: '', templates_count: 1 },
role: null,
},
confirmedAt: '2022-03-09T10:59:44.139Z',
email: 'foo@overleaf.com',
default: true,
}
const userData2: UserEmailData = {
affiliation: {
cachedConfirmedAt: null,
cachedPastReconfirmDate: false,
cachedReconfirmedAt: null,
department: 'Art History',
institution: {
commonsAccount: false,
confirmed: true,
id: 1,
isUniversity: false,
name: 'Overleaf',
ssoEnabled: false,
ssoBeta: false,
},
inReconfirmNotificationPeriod: false,
inferred: false,
licence: 'pro_plus',
pastReconfirmDate: false,
portal: { slug: '', templates_count: 1 },
role: 'Reader',
},
email: 'baz@overleaf.com',
default: false,
}
describe('user role and institution', function () {
it('renders affiliation name with add role/department button', function () {
const userEmailData = userData1
render(<InstitutionAndRole userEmailData={userEmailData} />)
screen.getByText(userEmailData.affiliation.institution.name, {
exact: false,
})
screen.getByRole('button', { name: /add role and department/i })
expect(screen.queryByRole('button', { name: /change/i })).to.not.exist
})
it('renders affiliation name, role and department with change button', function () {
const userEmailData = userData2
render(<InstitutionAndRole userEmailData={userEmailData} />)
screen.getByText(userEmailData.affiliation.institution.name, {
exact: false,
})
screen.getByText(userEmailData.affiliation.department, { exact: false })
screen.getByText(userEmailData.affiliation.role, { exact: false })
screen.getByRole('button', { name: /change/i })
expect(screen.queryByRole('button', { name: /add role and department/i }))
.to.not.exist
})
})

View file

@ -8,24 +8,40 @@ import {
import EmailsSection from '../../../../../../frontend/js/features/settings/components/emails-section'
import { expect } from 'chai'
import fetchMock from 'fetch-mock'
import { UserEmailData } from '../../../../../../types/user-email'
const confirmedUserData = {
const confirmedUserData: UserEmailData = {
confirmedAt: '2022-03-10T10:59:44.139Z',
email: 'bar@overleaf.com',
default: false,
}
const unconfirmedUserData = {
const unconfirmedUserData: UserEmailData = {
email: 'baz@overleaf.com',
default: false,
}
const professionalUserData = {
const professionalUserData: UserEmailData = {
affiliation: {
cachedConfirmedAt: null,
cachedPastReconfirmDate: false,
cachedReconfirmedAt: null,
department: 'Art History',
institution: {
commonsAccount: false,
confirmed: true,
id: 1,
isUniversity: false,
name: 'Overleaf',
ssoEnabled: false,
ssoBeta: false,
},
inReconfirmNotificationPeriod: false,
inferred: false,
licence: 'pro_plus',
pastReconfirmDate: false,
portal: { slug: '', templates_count: 1 },
role: 'Reader',
},
confirmedAt: '2022-03-09T10:59:44.139Z',
email: 'foo@overleaf.com',
@ -69,12 +85,10 @@ describe('<EmailsSection />', function () {
})
it('renders primary status', function () {
window.metaAttributesCache.set('ol-userEmails', fakeUsersData)
window.metaAttributesCache.set('ol-userEmails', [professionalUserData])
render(<EmailsSection />)
const primary = fakeUsersData.find(userData => userData.default)
screen.getByText(`${primary.email} (primary)`)
screen.getByText(`${professionalUserData.email} (primary)`)
})
it('shows confirmation status for unconfirmed users', function () {

View file

@ -1,6 +1,19 @@
import { Institution } from './institution'
import { Portal } from './portal'
import { Nullable } from './utils'
export type Affiliation = {
cachedConfirmedAt: Nullable<string>
cachedEntitlement: Nullable<boolean>
cachedLastDayToReconfirm: Nullable<string>
cachedPastReconfirmDate: boolean
cachedReconfirmedAt: Nullable<string>
department: Nullable<string>
inReconfirmNotificationPeriod: boolean
inferred: boolean
institution: Institution
licence?: 'free' | 'pro_plus'
licence: 'free' | 'pro_plus'
pastReconfirmDate: boolean
portal: Portal
role: Nullable<string>
}

View file

@ -1 +1,12 @@
export type Institution = Record<string, unknown>
import { Nullable } from './utils'
export type Institution = {
commonsAccount: boolean
confirmed: boolean
id: number
isUniversity: boolean
maxConfirmationMonths: Nullable<number>
name: string
ssoBeta: boolean
ssoEnabled: boolean
}

View file

@ -0,0 +1,4 @@
export type Portal = {
slug: string
templates_count: number
}

View file

@ -2,7 +2,7 @@ import { Affiliation } from './affiliation'
export type UserEmailData = {
affiliation?: Affiliation
confirmedAt: string
confirmedAt?: string
email: string
default: boolean
ssoAvailable?: boolean