Explorar o código

Merge pull request #8074 from overleaf/ii-ts-strict-fixes-1

GitOrigin-RevId: b99c5c998de9cc36cffffaab5b318331b45e931d
Alf Eaton %!s(int64=4) %!d(string=hai) anos
pai
achega
5e08d5f505

+ 12 - 6
services/web/frontend/js/features/settings/components/account-info-section.tsx

@@ -39,16 +39,18 @@ function AccountInfoSection() {
   const { isLoading, isSuccess, isError, error, runAsync } = useAsync()
   const [isFormValid, setIsFormValid] = useState(true)
 
-  const handleEmailChange = event => {
+  const handleEmailChange = (event: React.ChangeEvent<HTMLInputElement>) => {
     setEmail(event.target.value)
     setIsFormValid(event.target.validity.valid)
   }
 
-  const handleFirstNameChange = event => {
+  const handleFirstNameChange = (
+    event: React.ChangeEvent<HTMLInputElement>
+  ) => {
     setFirstName(event.target.value)
   }
 
-  const handleLastNameChange = event => {
+  const handleLastNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
     setLastName(event.target.value)
   }
 
@@ -56,7 +58,7 @@ function AccountInfoSection() {
     !hasAffiliationsFeature && !isExternalAuthenticationSystemUsed
   const canUpdateNames = shouldAllowEditingDetails
 
-  const handleSubmit = event => {
+  const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
     event.preventDefault()
     if (!isFormValid) {
       return
@@ -151,11 +153,15 @@ function ReadOrWriteFormGroup({
 }: ReadOrWriteFormGroupProps) {
   const [validationMessage, setValidationMessage] = useState('')
 
-  const handleInvalid = event => {
+  const handleInvalid = (
+    event: React.InvalidEvent<HTMLInputElement & FormControl>
+  ) => {
     event.preventDefault()
   }
 
-  const handleChangeAndValidity = event => {
+  const handleChangeAndValidity = (
+    event: React.ChangeEvent<HTMLInputElement & FormControl>
+  ) => {
     handleChange(event)
     setValidationMessage(event.target.validationMessage)
   }

+ 10 - 10
services/web/frontend/js/features/settings/components/emails/add-email/input.tsx

@@ -70,20 +70,20 @@ function Input({ onChange, handleAddNewEmail }: InputProps) {
     (event: ChangeEvent<HTMLInputElement>) => {
       const hint = event.target.value
       setInputValue(hint)
-      const match = matchLocalAndDomain(hint)
-      if (!matchedDomain?.hostname.startsWith(match.domain)) {
+      const { local, domain } = matchLocalAndDomain(hint)
+      if (domain && !matchedDomain?.hostname.startsWith(domain)) {
         setSuggestion(null)
       }
-      if (!match.domain) {
+      if (!domain) {
         return
       }
-      if (domainCache.has(match.domain)) {
-        const cachedDomain = domainCache.get(match.domain)
-        setSuggestion(`${match.local}@${cachedDomain.hostname}`)
+      if (domainCache.has(domain)) {
+        const cachedDomain = domainCache.get(domain) as DomainInfo
+        setSuggestion(`${local}@${cachedDomain.hostname}`)
         setMatchedDomain(cachedDomain)
         return
       }
-      const query = `?hostname=${match.domain}&limit=1`
+      const query = `?hostname=${domain}&limit=1`
       getJSON<Nullable<DomainInfo[]>>(`/institutions/domains${query}`, {
         signal,
       })
@@ -96,8 +96,8 @@ function Input({ onChange, handleAddNewEmail }: InputProps) {
           }
           const hostname = data[0]?.hostname
           if (hostname) {
-            domainCache.set(match.domain, data[0])
-            setSuggestion(`${match.local}@${hostname}`)
+            domainCache.set(domain, data[0])
+            setSuggestion(`${local}@${hostname}`)
             setMatchedDomain(data[0])
           } else {
             setSuggestion(null)
@@ -142,7 +142,7 @@ function Input({ onChange, handleAddNewEmail }: InputProps) {
   )
 
   useEffect(() => {
-    if (suggestion && !suggestion.startsWith(inputValue)) {
+    if (suggestion && inputValue && !suggestion.startsWith(inputValue)) {
       setSuggestion(null)
     }
   }, [suggestion, inputValue])

+ 14 - 18
services/web/frontend/js/features/settings/components/emails/sso-alert.tsx

@@ -35,24 +35,20 @@ export function SSOAlert() {
   const handleErrorClosed = () => setErrorClosed(true)
 
   if (samlError) {
-    return (
-      !errorClosed && (
-        <Alert bsStyle="danger" className="mb-0" onDismiss={handleErrorClosed}>
-          <p className="text-center">
-            <Icon
-              type="exclamation-triangle"
-              accessibilityLabel={t('generic_something_went_wrong')}
-            />{' '}
-            {samlError.translatedMessage
-              ? samlError.translatedMessage
-              : samlError.message}
-          </p>
-          {samlError.tryAgain && (
-            <p className="text-center">{t('try_again')}</p>
-          )}
-        </Alert>
-      )
-    )
+    return !errorClosed ? (
+      <Alert bsStyle="danger" className="mb-0" onDismiss={handleErrorClosed}>
+        <p className="text-center">
+          <Icon
+            type="exclamation-triangle"
+            accessibilityLabel={t('generic_something_went_wrong')}
+          />{' '}
+          {samlError.translatedMessage
+            ? samlError.translatedMessage
+            : samlError.message}
+        </p>
+        {samlError.tryAgain && <p className="text-center">{t('try_again')}</p>}
+      </Alert>
+    ) : null
   }
 
   if (!institutionLinked) {

+ 7 - 3
services/web/frontend/js/features/settings/components/leave/modal-form.tsx

@@ -24,11 +24,15 @@ function LeaveModalForm({
   const [confirmation, setConfirmation] = useState(false)
   const [error, setError] = useState<FetchError | null>(null)
 
-  const handleEmailChange = event => {
+  const handleEmailChange = (
+    event: React.ChangeEvent<HTMLFormElement & FormControl>
+  ) => {
     setEmail(event.target.value)
   }
 
-  const handlePasswordChange = event => {
+  const handlePasswordChange = (
+    event: React.ChangeEvent<HTMLFormElement & FormControl>
+  ) => {
     setPassword(event.target.value)
   }
 
@@ -36,7 +40,7 @@ function LeaveModalForm({
     setConfirmation(prev => !prev)
   }
 
-  const handleSubmit = event => {
+  const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
     event.preventDefault()
     if (!isFormValid) {
       return

+ 3 - 3
services/web/frontend/js/features/settings/components/linking-section.tsx

@@ -13,12 +13,12 @@ function LinkingSection() {
   const projectSyncSuccessMessage = getMeta(
     'ol-projectSyncSuccessMessage'
   ) as string
-  const [integrationLinkingWidgets] = useState(
+  const [integrationLinkingWidgets] = useState<any[]>(
     () =>
       getMeta('integrationLinkingWidgets') ||
       importOverleafModules('integrationLinkingWidgets')
   )
-  const [referenceLinkingWidgets] = useState(
+  const [referenceLinkingWidgets] = useState<any[]>(
     () =>
       getMeta('referenceLinkingWidgets') ||
       importOverleafModules('referenceLinkingWidgets')
@@ -139,7 +139,7 @@ function SSOLinkingWidgetContainer({
   const { t } = useTranslation()
   const { unlink } = useSSOContext()
 
-  let description = null
+  let description = ''
   switch (subscription.providerId) {
     case 'collabratec':
       description = t('linked_collabratec_description')

+ 3 - 1
services/web/frontend/js/features/settings/components/linking/integration-widget.tsx

@@ -141,7 +141,9 @@ function UnlinkConfirmationModal({
 }: UnlinkConfirmModalProps) {
   const { t } = useTranslation()
 
-  const handleCancel = event => {
+  const handleCancel = (
+    event: React.MouseEvent<HTMLButtonElement & Button>
+  ) => {
     event.preventDefault()
     handleHide()
   }

+ 2 - 1
services/web/frontend/js/features/settings/components/linking/sso-widget.tsx

@@ -8,7 +8,7 @@ import GoogleLogo from '../../../../shared/svgs/google-logo'
 import OrcidLogo from '../../../../shared/svgs/orcid-logo'
 import LinkingStatus from './status'
 
-const providerLogos = {
+const providerLogos: { readonly [p: string]: JSX.Element } = {
   collabratec: <IEEELogo />,
   google: <GoogleLogo />,
   orcid: <OrcidLogo />,
@@ -95,6 +95,7 @@ export function SSOLinkingWidget({
     </div>
   )
 }
+
 type ActionButtonProps = {
   unlinkRequestInflight: boolean
   accountIsLinked?: boolean

+ 1 - 1
services/web/frontend/js/features/settings/components/linking/status.tsx

@@ -4,7 +4,7 @@ import Icon from '../../../../shared/components/icon'
 type Status = 'pending' | 'success' | 'error'
 
 type LinkingStatusProps = {
-  status?: Status
+  status: Status
   description: string | ReactNode
 }
 

+ 17 - 7
services/web/frontend/js/features/settings/components/password-section.tsx

@@ -72,16 +72,22 @@ function PasswordForm() {
   const [isNewPasswordValid, setIsNewPasswordValid] = useState(false)
   const [isFormValid, setIsFormValid] = useState(false)
 
-  const handleCurrentPasswordChange = event => {
+  const handleCurrentPasswordChange = (
+    event: React.ChangeEvent<HTMLInputElement>
+  ) => {
     setCurrentPassword(event.target.value)
   }
 
-  const handleNewPassword1Change = event => {
+  const handleNewPassword1Change = (
+    event: React.ChangeEvent<HTMLInputElement>
+  ) => {
     setNewPassword1(event.target.value)
     setIsNewPasswordValid(event.target.validity.valid)
   }
 
-  const handleNewPassword2Change = event => {
+  const handleNewPassword2Change = (
+    event: React.ChangeEvent<HTMLInputElement>
+  ) => {
     setNewPassword2(event.target.value)
   }
 
@@ -91,7 +97,7 @@ function PasswordForm() {
     )
   }, [currentPassword, newPassword1, newPassword2, isNewPasswordValid])
 
-  const handleSubmit = event => {
+  const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
     event.preventDefault()
     if (!isFormValid) {
       return
@@ -157,7 +163,7 @@ type PasswordFormGroupProps = {
   id: string
   label: string
   value: string
-  handleChange: (event: any) => void
+  handleChange: (event: React.ChangeEvent<HTMLInputElement>) => void
   minLength?: number
   validationMessage?: string
 }
@@ -173,11 +179,15 @@ function PasswordFormGroup({
   const [validationMessage, setValidationMessage] = useState('')
   const [hadInteraction, setHadInteraction] = useState(false)
 
-  const handleInvalid = event => {
+  const handleInvalid = (
+    event: React.InvalidEvent<HTMLInputElement & FormControl>
+  ) => {
     event.preventDefault()
   }
 
-  const handleChangeAndValidity = event => {
+  const handleChangeAndValidity = (
+    event: React.ChangeEvent<HTMLInputElement & FormControl>
+  ) => {
     handleChange(event)
     setHadInteraction(true)
     setValidationMessage(event.target.validationMessage)

+ 10 - 5
services/web/frontend/js/infrastructure/fetch-json.ts

@@ -79,7 +79,9 @@ export class FetchError extends OError {
   getUserFacingMessage() {
     const statusCode = this.response?.status
     const defaultMessage = getErrorMessageForStatusCode(statusCode)
-    const message = this.data?.message?.text || this.data?.message
+    const message = (this.data?.message?.text || this.data?.message) as
+      | string
+      | undefined
     if (message && message !== defaultMessage) return message
 
     const statusCodes: { readonly [K: number]: string } = {
@@ -208,11 +210,14 @@ async function parseResponseBody(response: Response) {
   return {}
 }
 
-export function getUserFacingMessage(error: Error): string {
+export function getUserFacingMessage(error: Error | null) {
+  if (!error) {
+    return undefined
+  }
+
   if (error instanceof FetchError) {
     return error.getUserFacingMessage()
-  } else {
-    // checking existence of `error` to prevent errors when called from Javascript
-    return error?.message
   }
+
+  return error.message
 }

+ 1 - 1
services/web/frontend/js/shared/hooks/use-persisted-state.ts

@@ -38,7 +38,7 @@ function usePersistedState<T>(
 
   useEffect(() => {
     if (listen) {
-      const listener = event => {
+      const listener = (event: StorageEvent) => {
         if (event.key === key) {
           // note: this value is read via getItem rather than from event.newValue
           // because getItem handles deserializing the JSON that's stored in localStorage.