mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #8119 from overleaf/msm-refactor-settings
[Settings] Type refactoring GitOrigin-RevId: c2b5e76bda463508aa3a1d7ee22fd7839ec26075
This commit is contained in:
parent
506010cb14
commit
082a333773
5 changed files with 43 additions and 47 deletions
|
@ -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>
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
) : (
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue