Merge pull request #8119 from overleaf/msm-refactor-settings

[Settings] Type refactoring

GitOrigin-RevId: c2b5e76bda463508aa3a1d7ee22fd7839ec26075
This commit is contained in:
Miguel Serrano 2022-05-26 10:32:43 +02:00 committed by Copybot
parent 506010cb14
commit 082a333773
5 changed files with 43 additions and 47 deletions

View file

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import { Col } from 'react-bootstrap'
import Cell from './cell'
import Layout from './add-email/layout'
import Input, { InstitutionInfo } from './add-email/input'
import Input, { DomainInfo } from './add-email/input'
import AddAnotherEmailBtn from './add-email/add-another-email-btn'
import InstitutionFields from './add-email/institution-fields'
import SsoLinkingInfo from './add-email/sso-linking-info'
@ -21,8 +21,8 @@ function AddEmail() {
() => window.location.hash === '#add-email'
)
const [newEmail, setNewEmail] = useState('')
const [newEmailMatchedInstitution, setNewEmailMatchedInstitution] =
useState<InstitutionInfo | null>(null)
const [newEmailMatchedDomain, setNewEmailMatchedDomain] =
useState<DomainInfo | null>(null)
const [countryCode, setCountryCode] = useState<CountryCode | null>(null)
const [universities, setUniversities] = useState<
Partial<Record<CountryCode, University[]>>
@ -45,9 +45,9 @@ function AddEmail() {
setIsFormVisible(true)
}
const handleEmailChange = (value: string, institution?: InstitutionInfo) => {
const handleEmailChange = (value: string, domain?: DomainInfo) => {
setNewEmail(value)
setNewEmailMatchedInstitution(institution || null)
setNewEmailMatchedDomain(domain || null)
}
const getSelectedKnownUniversityId = (): number | undefined => {
@ -57,7 +57,7 @@ function AddEmail() {
)?.id
}
return newEmailMatchedInstitution?.university.id
return newEmailMatchedDomain?.university.id
}
const handleAddNewEmail = () => {
@ -120,12 +120,12 @@ function AddEmail() {
/>
</Cell>
</Col>
{ssoAvailableForDomain(newEmailMatchedInstitution) ? (
{ssoAvailableForDomain(newEmailMatchedDomain) ? (
<Col md={8}>
<Cell>
<SsoLinkingInfo
email={newEmail}
institutionInfo={newEmailMatchedInstitution}
domainInfo={newEmailMatchedDomain}
/>
</Cell>
</Col>
@ -144,7 +144,7 @@ function AddEmail() {
setRole={setRole}
department={department}
setDepartment={setDepartment}
newEmailMatchedInstitution={newEmailMatchedInstitution}
newEmailMatchedDomain={newEmailMatchedDomain}
/>
</Cell>
</Col>

View file

@ -21,7 +21,7 @@ function matchLocalAndDomain(emailHint: string) {
}
}
export type InstitutionInfo = {
export type DomainInfo = {
hostname: string
confirmed?: boolean
university: {
@ -32,14 +32,14 @@ export type InstitutionInfo = {
}
}
let domainCache = new Map<string, InstitutionInfo>()
let domainCache = new Map<string, DomainInfo>()
export function clearDomainCache() {
domainCache = new Map<string, InstitutionInfo>()
domainCache = new Map<string, DomainInfo>()
}
type InputProps = {
onChange: (value: string, institution?: InstitutionInfo) => void
onChange: (value: string, domain?: DomainInfo) => void
handleAddNewEmail: () => void
}
@ -49,8 +49,7 @@ function Input({ onChange, handleAddNewEmail }: InputProps) {
const inputRef = useRef<HTMLInputElement | null>(null)
const [suggestion, setSuggestion] = useState<string | null>(null)
const [inputValue, setInputValue] = useState<string | null>(null)
const [matchedInstitution, setMatchedInstitution] =
useState<InstitutionInfo | null>(null)
const [matchedDomain, setMatchedDomain] = useState<DomainInfo | null>(null)
useEffect(() => {
inputRef.current?.focus()
@ -60,22 +59,19 @@ function Input({ onChange, handleAddNewEmail }: InputProps) {
if (inputValue == null) {
return
}
if (
matchedInstitution &&
inputValue.endsWith(matchedInstitution.hostname)
) {
onChange(inputValue, matchedInstitution)
if (matchedDomain && inputValue.endsWith(matchedDomain.hostname)) {
onChange(inputValue, matchedDomain)
} else {
onChange(inputValue)
}
}, [onChange, inputValue, suggestion, matchedInstitution])
}, [onChange, inputValue, suggestion, matchedDomain])
const handleEmailChange = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
const hint = event.target.value
setInputValue(hint)
const match = matchLocalAndDomain(hint)
if (!matchedInstitution?.hostname.startsWith(match.domain)) {
if (!matchedDomain?.hostname.startsWith(match.domain)) {
setSuggestion(null)
}
if (!match.domain) {
@ -84,11 +80,13 @@ function Input({ onChange, handleAddNewEmail }: InputProps) {
if (domainCache.has(match.domain)) {
const cachedDomain = domainCache.get(match.domain)
setSuggestion(`${match.local}@${cachedDomain.hostname}`)
setMatchedInstitution(cachedDomain)
setMatchedDomain(cachedDomain)
return
}
const query = `?hostname=${match.domain}&limit=1`
getJSON(`/institutions/domains${query}`, { signal })
getJSON<Nullable<DomainInfo[]>>(`/institutions/domains${query}`, {
signal,
})
.then(data => {
if (!(data && data[0])) {
return
@ -100,19 +98,19 @@ function Input({ onChange, handleAddNewEmail }: InputProps) {
if (hostname) {
domainCache.set(match.domain, data[0])
setSuggestion(`${match.local}@${hostname}`)
setMatchedInstitution(data[0])
setMatchedDomain(data[0])
} else {
setSuggestion(null)
setMatchedInstitution(null)
setMatchedDomain(null)
}
})
.catch(error => {
setSuggestion(null)
setMatchedInstitution(null)
setMatchedDomain(null)
console.error(error)
})
},
[signal, matchedInstitution]
[signal, matchedDomain]
)
const handleKeyDownEvent = useCallback(

View file

@ -7,7 +7,7 @@ import defaultRoles from '../../../data/roles'
import defaultDepartments from '../../../data/departments'
import { CountryCode } from '../../../data/countries-list'
import { University } from '../../../../../../../types/university'
import { InstitutionInfo } from './input'
import { DomainInfo } from './input'
import { getJSON } from '../../../../../infrastructure/fetch-json'
import useAsync from '../../../../../shared/hooks/use-async'
import UniversityName from './university-name'
@ -25,7 +25,7 @@ type InstitutionFieldsProps = {
setRole: React.Dispatch<React.SetStateAction<string>>
department: string
setDepartment: React.Dispatch<React.SetStateAction<string>>
newEmailMatchedInstitution: InstitutionInfo | null
newEmailMatchedDomain: DomainInfo | null
}
function InstitutionFields({
@ -39,7 +39,7 @@ function InstitutionFields({
setRole,
department,
setDepartment,
newEmailMatchedInstitution,
newEmailMatchedDomain,
}: InstitutionFieldsProps) {
const { t } = useTranslation()
const countryRef = useRef<HTMLInputElement | null>(null)
@ -66,12 +66,12 @@ function InstitutionFields({
// If the institution selected by autocompletion has changed
// hide the fields visibility and reset values
useEffect(() => {
if (!newEmailMatchedInstitution) {
if (!newEmailMatchedDomain) {
setIsInstitutionFieldsVisible(false)
setRole('')
setDepartment('')
}
}, [newEmailMatchedInstitution, setRole, setDepartment])
}, [newEmailMatchedDomain, setRole, setDepartment])
useEffect(() => {
const selectedKnownUniversity = countryCode
@ -121,9 +121,9 @@ function InstitutionFields({
}
const isLetUsKnowVisible =
!newEmailMatchedInstitution && !isInstitutionFieldsVisible
!newEmailMatchedDomain && !isInstitutionFieldsVisible
const isAutocompletedInstitutionVisible =
newEmailMatchedInstitution && !isInstitutionFieldsVisible
newEmailMatchedDomain && !isInstitutionFieldsVisible
const isRoleAndDepartmentVisible =
isAutocompletedInstitutionVisible || isUniversityDirty
@ -139,7 +139,7 @@ function InstitutionFields({
{isAutocompletedInstitutionVisible ? (
// Display the institution name after autocompletion
<UniversityName
name={newEmailMatchedInstitution.university.name}
name={newEmailMatchedDomain.university.name}
onClick={handleSelectUniversityManually}
/>
) : (

View file

@ -1,34 +1,32 @@
import { Trans, useTranslation } from 'react-i18next'
import { InstitutionInfo } from './input'
import { DomainInfo } from './input'
import { ExposedSettings } from '../../../../../../../types/exposed-settings'
import getMeta from '../../../../../utils/meta'
type SSOLinkingInfoProps = {
institutionInfo: InstitutionInfo
domainInfo: DomainInfo
email: string
}
function SsoLinkingInfo({ institutionInfo, email }: SSOLinkingInfoProps) {
function SsoLinkingInfo({ domainInfo, email }: SSOLinkingInfoProps) {
const { samlInitPath } = getMeta('ol-ExposedSettings') as ExposedSettings
const { t } = useTranslation()
return (
<>
<p className="affiliations-table-label">
{institutionInfo.university.name}
</p>
<p className="affiliations-table-label">{domainInfo.university.name}</p>
<p>
<Trans
i18nKey="to_add_email_accounts_need_to_be_linked_2"
components={[<strong />]} // eslint-disable-line react/jsx-key
values={{ institutionName: institutionInfo.university.name }}
values={{ institutionName: domainInfo.university.name }}
/>
</p>
<p>
<Trans
i18nKey="doing_this_will_verify_affiliation_and_allow_log_in_2"
components={[<strong />]} // eslint-disable-line react/jsx-key
values={{ institutionName: institutionInfo.university.name }}
values={{ institutionName: domainInfo.university.name }}
/>{' '}
<a
href="/learn/how-to/Institutional_Login"
@ -40,7 +38,7 @@ function SsoLinkingInfo({ institutionInfo, email }: SSOLinkingInfoProps) {
</p>
<a
className="btn-sm btn btn-primary btn-link-accounts"
href={`${samlInitPath}?university_id=${institutionInfo.university.id}&auto=/user/settings&email=${email}`}
href={`${samlInitPath}?university_id=${domainInfo.university.id}&auto=/user/settings&email=${email}`}
>
{t('link_accounts_and_add_email')}
</a>

View file

@ -1,9 +1,9 @@
import getMeta from '../../../utils/meta'
import { InstitutionInfo } from '../components/emails/add-email/input'
import { DomainInfo } from '../components/emails/add-email/input'
import { ExposedSettings } from '../../../../../types/exposed-settings'
import { Institution } from '../../../../../types/institution'
export const ssoAvailableForDomain = (domain: InstitutionInfo | null) => {
export const ssoAvailableForDomain = (domain: DomainInfo | null) => {
const { hasSamlBeta, hasSamlFeature } = getMeta(
'ol-ExposedSettings'
) as ExposedSettings