Merge intermediate component wrappers into OL-prefixed components (#34996)

* Merge intermediate component wrappers into OL-prefixed components

* Replace all intermediate wrapper consumers with OL-prefixed components directly

* Fix jsx/js files still importing deleted shim components

* Remove duplicate OLNotification imports left by first pass

* Rename OLTagIcon to TagIcon, remove OL prefix

* Rename OLDropdownMenuItem to DropdownMenuItem, remove OL prefix

* Remove OLNotification, use Notification directly

* Move Notification to the main shared component folder

* Update tag-icon import path out of ol/

* Move TagIcon to the main shared component folder

* Update dropdown-menu-item import path out of ol/

* Move DropdownMenuItem to the main shared component folder

* Fix dropdown-menu-item import path to dropdown/ subfolder

* Remove BS5 alias prefixes from shared components

* Restore notification-list wrapper in Notification component

* Add translation for loading button

* Remove redundant import aliasing

* Resolve conflicts

* Restore notification container `notification-list`

GitOrigin-RevId: 24a5af18599a3e02ac6fd61c09cf5a49ef6e0020
This commit is contained in:
Rebeka Dekany
2026-09-17 11:19:34 +00:00
committed by Copybot
parent 39e1447258
commit e2a8bf768b
128 changed files with 1712 additions and 1661 deletions
@@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLButton from '@/shared/components/ol/ol-button'
import RailPanelHeader from '@/features/ide-react/components/rail/rail-panel-header'
@@ -16,7 +16,9 @@ function ChatFallbackError({ reconnect }: ChatFallbackErrorProps) {
<div className="chat-wrapper">
<aside className="chat" aria-label={t('chat')}>
<div className="chat-error">
<OLNotification type="error" content={t('chat_error')} />
<div className="notification-list">
<Notification type="error" content={t('chat_error')} />
</div>
{reconnect && (
<p className="text-center">
<OLButton variant="secondary" onClick={reconnect}>
@@ -1,14 +1,14 @@
import { FC } from 'react'
import { Tag as TagType } from '../../../../../app/src/Features/Tags/types'
import { getTagColor } from '@/features/project-list/util/tag'
import Tag from '@/shared/components/tag'
import OLTag from '@/shared/components/ol/ol-tag'
export const CloneProjectTag: FC<{
tag: TagType
removeTag: (tag: TagType) => void
}> = ({ tag, removeTag }) => {
return (
<Tag
<OLTag
prepend={
<i
className="badge-tag-circle"
@@ -21,6 +21,6 @@ export const CloneProjectTag: FC<{
className="ms-2 mb-2"
>
{tag.name}
</Tag>
</OLTag>
)
}
@@ -10,7 +10,7 @@ import {
OLModalTitle,
} from '@/shared/components/ol/ol-modal'
import OLTooltip from '@/shared/components/ol/ol-tooltip'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLButton from '@/shared/components/ol/ol-button'
import OLIconButton from '@/shared/components/ol/ol-icon-button'
import { learnedWords as initialLearnedWords } from '@/features/source-editor/extensions/spelling/learned-words'
@@ -55,13 +55,14 @@ export default function DictionaryModalContent({
<OLModalHeader>
<OLModalTitle>{t('edit_dictionary')}</OLModalTitle>
</OLModalHeader>
<OLModalBody>
{isError ? (
<OLNotification
type="error"
content={t('generic_something_went_wrong')}
/>
<div className="notification-list">
<Notification
type="error"
content={t('generic_something_went_wrong')}
/>
</div>
) : null}
{learnedWords.size > 0 ? (
@@ -93,7 +94,6 @@ export default function DictionaryModalContent({
</p>
)}
</OLModalBody>
<OLModalFooter>
<OLButton variant="secondary" onClick={handleHide}>
{t('close')}
@@ -1,9 +1,13 @@
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
export default function DangerMessage({
children,
}: {
children: React.ReactNode
}) {
return <OLNotification type="error" content={children} />
return (
<div className="notification-list">
<Notification type="error" content={children} />
</div>
)
}
@@ -9,7 +9,7 @@ import {
import OLFormGroup from '@/shared/components/ol/ol-form-group'
import OLFormLabel from '@/shared/components/ol/ol-form-label'
import OLFormControl from '@/shared/components/ol/ol-form-control'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
/**
* A form component that renders a text input with label,
@@ -57,7 +57,6 @@ export default function FileTreeCreateNameInput({
return (
<OLFormGroup controlId="new-doc-name" className={classes.formGroup}>
<OLFormLabel>{label || t('file_name')}</OLFormLabel>
<OLFormControl
type="text"
placeholder={placeholder || t('file_name')}
@@ -67,15 +66,15 @@ export default function FileTreeCreateNameInput({
ref={inputRef}
disabled={inFlight}
/>
{touchedName && !validName && (
<OLNotification
type="error"
className="row-spaced-small"
content={t('files_cannot_include_invalid_characters')}
/>
<div className="notification-list">
<Notification
type="error"
className="row-spaced-small"
content={t('files_cannot_include_invalid_characters')}
/>
</div>
)}
{error && <ErrorMessage error={error} />}
</OLFormGroup>
)
@@ -91,29 +90,35 @@ function ErrorMessage({ error }: { error: string | Record<string, any> }) {
switch (error.constructor) {
case DuplicateFilenameError:
return (
<OLNotification
type="error"
className="row-spaced-small"
content={t('file_already_exists')}
/>
<div className="notification-list">
<Notification
type="error"
className="row-spaced-small"
content={t('file_already_exists')}
/>
</div>
)
case InvalidFilenameError:
return (
<OLNotification
type="error"
className="row-spaced-small"
content={t('files_cannot_include_invalid_characters')}
/>
<div className="notification-list">
<Notification
type="error"
className="row-spaced-small"
content={t('files_cannot_include_invalid_characters')}
/>
</div>
)
case BlockedFilenameError:
return (
<OLNotification
type="error"
className="row-spaced-small"
content={t('blocked_filename')}
/>
<div className="notification-list">
<Notification
type="error"
className="row-spaced-small"
content={t('blocked_filename')}
/>
</div>
)
default:
@@ -11,7 +11,7 @@ import importOverleafModules from '../../../../../macros/import-overleaf-module.
import { ElementType, lazy, Suspense } from 'react'
import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner'
import getMeta from '@/utils/meta'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
const createFileModeModules = importOverleafModules('createFileModes') as {
import: { CreateFilePane: ElementType; CreateFileMode: ElementType }
@@ -34,12 +34,14 @@ export default function FileTreeModalCreateFileBody() {
if (typeof fileCount !== 'number' && fileCount.status === 'error') {
return (
<div className="p-4">
<OLNotification
type="error"
content={t('project_has_too_many_files_limit', {
limit: fileCount.limit,
})}
/>
<div className="notification-list">
<Notification
type="error"
content={t('project_has_too_many_files_limit', {
limit: fileCount.limit,
})}
/>
</div>
</div>
)
}
@@ -96,16 +98,18 @@ export default function FileTreeModalCreateFileBody() {
>
{typeof fileCount !== 'number' &&
fileCount.status === 'warning' && (
<OLNotification
type="warning"
className={`mb-3 ${newFileCreateMode === 'upload' ? 'mt-0' : 'mt-3'}`}
content={
<>
{t('project_approaching_file_limit')} ({fileCount.value}/
{fileCount.limit})
</>
}
/>
<div className="notification-list">
<Notification
type="warning"
className={`mb-3 ${newFileCreateMode === 'upload' ? 'mt-0' : 'mt-3'}`}
content={
<>
{t('project_approaching_file_limit')} ({fileCount.value}
/{fileCount.limit})
</>
}
/>
</div>
)}
{newFileCreateMode === 'doc' && (
<FileTreeCreateNameProvider initialName="name.tex">
@@ -9,7 +9,7 @@ import {
OLModalTitle,
} from '@/shared/components/ol/ol-modal'
import OLButton from '@/shared/components/ol/ol-button'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { useFileTreeSelectable } from '../../contexts/file-tree-selectable'
function FileTreeModalDelete() {
@@ -42,7 +42,6 @@ function FileTreeModalDelete() {
<OLModalHeader>
<OLModalTitle>{t('delete')}</OLModalTitle>
</OLModalHeader>
<OLModalBody>
<p>{t('sure_you_want_to_delete')}</p>
<ul>
@@ -51,13 +50,14 @@ function FileTreeModalDelete() {
))}
</ul>
{error && (
<OLNotification
type="error"
content={t('generic_something_went_wrong')}
/>
<div className="notification-list">
<Notification
type="error"
content={t('generic_something_went_wrong')}
/>
</div>
)}
</OLModalBody>
<OLModalFooter>
{inFlight ? (
<OLButton
@@ -2,7 +2,7 @@ import type { ElementType } from 'react'
import { useTranslation } from 'react-i18next'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
import { BinaryFile } from '../types/binary-file'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
type FileViewRefreshErrorProps = {
file: BinaryFile
@@ -35,14 +35,16 @@ export default function FileViewRefreshError({
} else {
return (
<div className="file-view-error">
<OLNotification
type="error"
content={
<span>
{t('access_denied')}: {refreshError}
</span>
}
/>
<div className="notification-list">
<Notification
type="error"
content={
<span>
{t('access_denied')}: {refreshError}
</span>
}
/>
</div>
</div>
)
}
@@ -5,7 +5,7 @@ import withErrorBoundary from '@/infrastructure/error-boundary'
import useAbortController from '@/shared/hooks/use-abort-controller'
import LoadingSpinner from '@/shared/components/loading-spinner'
import Notification from '@/shared/components/notification'
import IconButton from '@/shared/components/button/icon-button'
import OLIconButton from '@/shared/components/ol/ol-icon-button'
import {
Card,
Row,
@@ -14,8 +14,8 @@ import {
FormLabel,
FormControl,
} from 'react-bootstrap'
import FormText from '@/shared/components/form/form-text'
import Button from '@/shared/components/button/button'
import OLFormText from '@/shared/components/ol/ol-form-text'
import OLButton from '@/shared/components/ol/ol-button'
import PoNumber from '@/features/group-management/components/add-seats/po-number'
import CostSummary from '@/features/group-management/components/add-seats/cost-summary'
import RequestStatus from '@/features/group-management/components/request-status'
@@ -336,7 +336,7 @@ function AddSeats() {
<Row>
<Col xxl={5} xl={6} lg={7} md={9} className="mx-auto">
<div className="group-heading" data-testid="group-heading">
<IconButton
<OLIconButton
variant="ghost"
href="/user/subscription"
size="lg"
@@ -394,7 +394,7 @@ function AddSeats() {
isInvalid={Boolean(addSeatsInputError)}
/>
{Boolean(addSeatsInputError) && (
<FormText type="error">{addSeatsInputError}</FormText>
<OLFormText type="error">{addSeatsInputError}</OLFormText>
)}
</FormGroup>
{isCollectionMethodManual && (
@@ -425,7 +425,7 @@ function AddSeats() {
{t('upgrade_my_plan')}
</a>
)}
<Button
<OLButton
variant="secondary"
href="/user/subscription"
onClick={() =>
@@ -435,8 +435,8 @@ function AddSeats() {
}
>
{t('cancel')}
</Button>
<Button
</OLButton>
<OLButton
variant="primary"
type="submit"
disabled={
@@ -445,9 +445,10 @@ function AddSeats() {
isSendingMailToSales
}
isLoading={isAddingSeats || isSendingMailToSales}
loadingLabel={t('loading')}
>
{shouldContactSales ? t('send_request') : t('buy_licenses')}
</Button>
</OLButton>
</div>
</form>
</Card.Body>
@@ -1,7 +1,7 @@
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FormControl, FormGroup, FormLabel } from 'react-bootstrap'
import FormText from '@/shared/components/form/form-text'
import OLFormText from '@/shared/components/ol/ol-form-text'
import OLFormCheckbox from '@/shared/components/ol/ol-form-checkbox'
type PoNumberProps = {
@@ -34,7 +34,7 @@ function PoNumber({ error, validate }: PoNumberProps) {
onChange={async e => await validate(e.target.value)}
isInvalid={Boolean(error)}
/>
{Boolean(error) && <FormText type="error">{error}</FormText>}
{Boolean(error) && <OLFormText type="error">{error}</OLFormText>}
</FormGroup>
)}
</>
@@ -1,4 +1,4 @@
import IconButton from '@/shared/components/button/icon-button'
import OLIconButton from '@/shared/components/ol/ol-icon-button'
type BackButtonProps = {
href: string
@@ -7,7 +7,7 @@ type BackButtonProps = {
function BackButton({ href, accessibilityLabel }: BackButtonProps) {
return (
<IconButton
<OLIconButton
variant="ghost"
href={href}
size="lg"
@@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next'
import getMeta from '@/utils/meta'
import useWaitForI18n from '@/shared/hooks/use-wait-for-i18n'
import { Card as BSCard, CardBody, Col, Row } from 'react-bootstrap'
import IconButton from '@/shared/components/button/icon-button'
import OLIconButton from '@/shared/components/ol/ol-icon-button'
type CardProps = {
children: React.ReactNode
@@ -22,7 +22,7 @@ function Card({ children }: CardProps) {
<Row>
<Col xl={{ span: 4, offset: 4 }} md={{ span: 6, offset: 3 }}>
<div className="group-heading" data-testid="group-heading">
<IconButton
<OLIconButton
variant="ghost"
href="/user/subscription"
size="lg"
@@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
export type APIError = {
message?: string
@@ -18,14 +18,18 @@ export default function ErrorAlert({ error }: ErrorAlertProps) {
if (error.message) {
return (
<OLNotification
type="error"
content={`${t('error')}: ${error.message}`}
/>
<div className="notification-list">
<Notification
type="error"
content={`${t('error')}: ${error.message}`}
/>
</div>
)
}
return (
<OLNotification type="error" content={t('generic_something_went_wrong')} />
<div className="notification-list">
<Notification type="error" content={t('generic_something_went_wrong')} />
</div>
)
}
@@ -13,7 +13,7 @@ import OLCard from '@/shared/components/ol/ol-card'
import OLButton from '@/shared/components/ol/ol-button'
import OLFormControl from '@/shared/components/ol/ol-form-control'
import OLFormText from '@/shared/components/ol/ol-form-text'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLFormLabel from '@/shared/components/ol/ol-form-label'
export default function GroupMembers() {
@@ -144,11 +144,13 @@ export default function GroupMembers() {
data-testid="add-more-members-form"
>
{memberAdded && (
<OLNotification
content={t('members_added')}
type="success"
className="mt-2 mb-3"
/>
<div className="notification-list">
<Notification
content={t('members_added')}
type="success"
className="mt-2 mb-3"
/>
</div>
)}
<ErrorAlert error={inviteError} />
<form onSubmit={onAddMembersSubmit}>
@@ -11,7 +11,7 @@ import OLCard from '@/shared/components/ol/ol-card'
import OLCol from '@/shared/components/ol/ol-col'
import OLFormCheckbox from '@/shared/components/ol/ol-form-checkbox'
import OLFormSelect from '@/shared/components/ol/ol-form-select'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLRow from '@/shared/components/ol/ol-row'
import OLTable from '@/shared/components/ol/ol-table'
import OLTag from '@/shared/components/ol/ol-tag'
@@ -160,31 +160,33 @@ export default function GroupUsers() {
</OLRow>
<OLRow className="license-info">
<OLNotification
type="info"
content={
allocatedLicenses === 1
? t('you_have_1_license_and_your_plan_supports_up_to_y', {
groupSize,
})
: t('you_have_x_licenses_and_your_plan_supports_up_to_y', {
addedUsersSize: allocatedLicenses,
groupSize,
})
}
action={
canUseAddSeatsFeature ? (
<a
href="/user/subscription/group/add-users"
className={classNames({
'btn btn-premium': allocatedLicenses === groupSize,
})}
>
{t('buy_more_licenses')}
</a>
) : undefined
}
/>
<div className="notification-list">
<Notification
type="info"
content={
allocatedLicenses === 1
? t('you_have_1_license_and_your_plan_supports_up_to_y', {
groupSize,
})
: t('you_have_x_licenses_and_your_plan_supports_up_to_y', {
addedUsersSize: allocatedLicenses,
groupSize,
})
}
action={
canUseAddSeatsFeature ? (
<a
href="/user/subscription/group/add-users"
className={classNames({
'btn btn-premium': allocatedLicenses === groupSize,
})}
>
{t('buy_more_licenses')}
</a>
) : undefined
}
/>
</div>
</OLRow>
<OLRow>
@@ -1,5 +1,5 @@
import { Trans, useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import Card from '@/features/group-management/components/card'
import getMeta from '@/utils/meta'
@@ -9,30 +9,32 @@ function ManuallyCollectedSubscription() {
return (
<Card>
<OLNotification
type="error"
title={t('account_billed_manually')}
content={
errorType === 'plan-upgrade' ? (
<Trans
i18nKey="it_looks_like_your_account_is_billed_manually_upgrading_subscription"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a href="/contact" rel="noreferrer noopener" />,
]}
/>
) : (
<Trans
i18nKey="it_looks_like_your_account_is_billed_manually_purchasing_additional_license_or_upgrading_subscription"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a href="/contact" rel="noreferrer noopener" />,
]}
/>
)
}
className="m-0"
/>
<div className="notification-list">
<Notification
type="error"
title={t('account_billed_manually')}
content={
errorType === 'plan-upgrade' ? (
<Trans
i18nKey="it_looks_like_your_account_is_billed_manually_upgrading_subscription"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a href="/contact" rel="noreferrer noopener" />,
]}
/>
) : (
<Trans
i18nKey="it_looks_like_your_account_is_billed_manually_purchasing_additional_license_or_upgrading_subscription"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a href="/contact" rel="noreferrer noopener" />,
]}
/>
)
}
className="m-0"
/>
</div>
</Card>
)
}
@@ -1,7 +1,7 @@
import { Trans } from 'react-i18next'
import type { GroupUserAlertVariant } from '../../utils/types'
import NotificationScrolledTo from '@/shared/components/notification-scrolled-to'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
type GroupUsersListAlertProps = {
variant: GroupUserAlertVariant
@@ -85,25 +85,27 @@ function ResendManagedUserInviteSuccess({
userEmail,
}: GroupUsersListAlertComponentProps) {
return (
<OLNotification
type="success"
content={
<Trans
i18nKey="managed_user_invite_has_been_sent_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
<div className="notification-list">
<Notification
type="success"
content={
<Trans
i18nKey="managed_user_invite_has_been_sent_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
</div>
)
}
@@ -112,25 +114,27 @@ function ResendSSOLinkInviteSuccess({
userEmail,
}: GroupUsersListAlertComponentProps) {
return (
<OLNotification
type="success"
content={
<Trans
i18nKey="sso_link_invite_has_been_sent_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
<div className="notification-list">
<Notification
type="success"
content={
<Trans
i18nKey="sso_link_invite_has_been_sent_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
</div>
)
}
@@ -139,25 +143,27 @@ function FailedToResendManagedInvite({
userEmail,
}: GroupUsersListAlertComponentProps) {
return (
<OLNotification
type="error"
content={
<Trans
i18nKey="failed_to_send_managed_user_invite_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
<div className="notification-list">
<Notification
type="error"
content={
<Trans
i18nKey="failed_to_send_managed_user_invite_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
</div>
)
}
function FailedToResendSSOLink({
@@ -165,25 +171,27 @@ function FailedToResendSSOLink({
userEmail,
}: GroupUsersListAlertComponentProps) {
return (
<OLNotification
type="error"
content={
<Trans
i18nKey="failed_to_send_sso_link_invite_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
<div className="notification-list">
<Notification
type="error"
content={
<Trans
i18nKey="failed_to_send_sso_link_invite_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
</div>
)
}
@@ -192,25 +200,27 @@ function ResendGroupInviteSuccess({
userEmail,
}: GroupUsersListAlertComponentProps) {
return (
<OLNotification
type="success"
content={
<Trans
i18nKey="group_invite_has_been_sent_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
<div className="notification-list">
<Notification
type="success"
content={
<Trans
i18nKey="group_invite_has_been_sent_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
</div>
)
}
@@ -219,25 +229,27 @@ function FailedToResendGroupInvite({
userEmail,
}: GroupUsersListAlertComponentProps) {
return (
<OLNotification
type="error"
content={
<Trans
i18nKey="failed_to_send_group_invite_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
<div className="notification-list">
<Notification
type="error"
content={
<Trans
i18nKey="failed_to_send_group_invite_to_email"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
</div>
)
}
@@ -246,24 +258,26 @@ function TooManyRequests({
userEmail,
}: GroupUsersListAlertComponentProps) {
return (
<OLNotification
type="error"
content={
<Trans
i18nKey="an_email_has_already_been_sent_to"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
<div className="notification-list">
<Notification
type="error"
content={
<Trans
i18nKey="an_email_has_already_been_sent_to"
values={{
email: userEmail,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
}
isDismissible
onDismiss={onDismiss}
/>
</div>
)
}
@@ -14,7 +14,7 @@ import {
} from '@/shared/components/ol/ol-modal'
import OLFormGroup from '@/shared/components/ol/ol-form-group'
import OLButton from '@/shared/components/ol/ol-button'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLFormControl from '@/shared/components/ol/ol-form-control'
import OLFormLabel from '@/shared/components/ol/ol-form-label'
import OLFormSelect from '@/shared/components/ol/ol-form-select'
@@ -137,7 +137,9 @@ export default function OffboardManagedUserModal({
/>
</OLFormGroup>
{error && (
<OLNotification type="error" content={error} className="mb-0" />
<div className="notification-list">
<Notification type="error" content={error} className="mb-0" />
</div>
)}
</OLModalBody>
<OLModalFooter>
@@ -14,7 +14,7 @@ import {
} from '@/shared/components/ol/ol-modal'
import OLFormGroup from '@/shared/components/ol/ol-form-group'
import OLButton from '@/shared/components/ol/ol-button'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLFormControl from '@/shared/components/ol/ol-form-control'
import OLFormLabel from '@/shared/components/ol/ol-form-label'
import { sendMB } from '@/infrastructure/event-tracking'
@@ -117,7 +117,9 @@ export default function RemoveManagedUserModal({
/>
</OLFormGroup>
{error && (
<OLNotification type="error" content={error} className="mb-0" />
<div className="notification-list">
<Notification type="error" content={error} className="mb-0" />
</div>
)}
</OLModalBody>
<OLModalFooter>
@@ -1,5 +1,5 @@
import { Trans, useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import Card from '@/features/group-management/components/card'
function MissingBillingInformation() {
@@ -7,25 +7,27 @@ function MissingBillingInformation() {
return (
<Card>
<OLNotification
type="error"
title={t('missing_payment_details')}
content={
<Trans
i18nKey="it_looks_like_your_payment_details_are_missing_please_update_your_billing_information"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a
href="/user/subscription/payment/billing-details"
rel="noreferrer noopener"
/>,
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a href="/contact" rel="noreferrer noopener" />,
]}
/>
}
className="m-0"
/>
<div className="notification-list">
<Notification
type="error"
title={t('missing_payment_details')}
content={
<Trans
i18nKey="it_looks_like_your_payment_details_are_missing_please_update_your_billing_information"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a
href="/user/subscription/payment/billing-details"
rel="noreferrer noopener"
/>,
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a href="/contact" rel="noreferrer noopener" />,
]}
/>
}
className="m-0"
/>
</div>
</Card>
)
}
@@ -1,9 +1,9 @@
import { useTranslation } from 'react-i18next'
import { Card, CardBody, Row, Col } from 'react-bootstrap'
import Button from '@/shared/components/button/button'
import OLButton from '@/shared/components/ol/ol-button'
import MaterialIcon from '@/shared/components/material-icon'
import getMeta from '@/utils/meta'
import IconButton from '@/shared/components/button/icon-button'
import OLIconButton from '@/shared/components/ol/ol-icon-button'
import classnames from 'classnames'
type RequestStatusProps = {
@@ -22,7 +22,7 @@ function RequestStatus({ icon, title, content, variant }: RequestStatusProps) {
<Row>
<Col xxl={5} xl={6} lg={7} md={9} className="mx-auto">
<div className="group-heading" data-testid="group-heading">
<IconButton
<OLIconButton
variant="ghost"
href="/user/subscription"
size="lg"
@@ -49,9 +49,9 @@ function RequestStatus({ icon, title, content, variant }: RequestStatusProps) {
)}
</div>
<div className="text-center">
<Button variant="secondary" href="/user/subscription">
<OLButton variant="secondary" href="/user/subscription">
{t('go_to_subscriptions')}
</Button>
</OLButton>
</div>
</CardBody>
</Card>
@@ -1,23 +1,25 @@
import { Trans } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import Card from '@/features/group-management/components/card'
function SubtotalLimitExceeded() {
return (
<Card>
<OLNotification
type="error"
content={
<Trans
i18nKey="sorry_there_was_an_issue_upgrading_your_subscription"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a href="/contact" rel="noreferrer noopener" />,
]}
/>
}
className="m-0"
/>
<div className="notification-list">
<Notification
type="error"
content={
<Trans
i18nKey="sorry_there_was_an_issue_upgrading_your_subscription"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a href="/contact" rel="noreferrer noopener" />,
]}
/>
}
className="m-0"
/>
</div>
</Card>
)
}
@@ -2,8 +2,8 @@ import getMeta from '@/utils/meta'
import { FetchError, postJSON } from '@/infrastructure/fetch-json'
import { useTranslation, Trans } from 'react-i18next'
import { Card, Row, Col } from 'react-bootstrap'
import IconButton from '@/shared/components/button/icon-button'
import Button from '@/shared/components/button/button'
import OLIconButton from '@/shared/components/ol/ol-icon-button'
import OLButton from '@/shared/components/ol/ol-button'
import UpgradeSubscriptionPlanDetails from './upgrade-subscription-plan-details'
import RequestStatus from '../request-status'
import UpgradeSummary, {
@@ -90,7 +90,7 @@ function UpgradeSubscription() {
<Row>
<Col xl={{ span: 8, offset: 2 }}>
<div className="group-heading" data-testid="group-heading">
<IconButton
<OLIconButton
variant="ghost"
href="/user/subscription"
size="lg"
@@ -135,7 +135,7 @@ function UpgradeSubscription() {
>
{t('add_more_licenses_to_my_plan')}
</a>
<Button
<OLButton
href="/user/subscription"
variant="secondary"
disabled={isLoading}
@@ -146,14 +146,15 @@ function UpgradeSubscription() {
}}
>
{t('cancel')}
</Button>
<Button
</OLButton>
<OLButton
variant="primary"
onClick={onSubmit}
isLoading={isLoading}
loadingLabel={t('loading')}
>
{t('upgrade')}
</Button>
</OLButton>
</div>
</Card.Body>
</Card>
@@ -1,7 +1,7 @@
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import OLTagIcon from '@/shared/components/ol/ol-tag-icon'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import TagIcon from '@/shared/components/tag-icon'
import AddLabelModal from '../../add-label-modal'
type AddLabelProps = {
@@ -20,15 +20,15 @@ function AddLabel({ version, closeDropdown, ...props }: AddLabelProps) {
return (
<>
<OLDropdownMenuItem
<DropdownMenuItem
onClick={handleClick}
leadingIcon={<OLTagIcon />}
leadingIcon={<TagIcon />}
as="button"
className="dropdown-item-material-icon-small"
{...props}
>
{t('history_label_this_version')}
</OLDropdownMenuItem>
</DropdownMenuItem>
<AddLabelModal
show={showModal}
setShow={setShowModal}
@@ -1,7 +1,7 @@
import { useHistoryContext } from '../../../../context/history-context'
import { UpdateRange } from '../../../../services/types/update'
import { ReactNode } from 'react'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
type CompareProps = {
comparisonRange: UpdateRange
@@ -32,7 +32,7 @@ function CompareDropDownItem({
}
return (
<OLDropdownMenuItem
<DropdownMenuItem
{...props}
leadingIcon={icon}
as="button"
@@ -40,7 +40,7 @@ function CompareDropDownItem({
className="dropdown-item-material-icon-small"
>
{text}
</OLDropdownMenuItem>
</DropdownMenuItem>
)
}
@@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import MaterialIcon from '@/shared/components/material-icon'
type DownloadProps = {
@@ -17,7 +17,7 @@ function Download({
const { t } = useTranslation()
return (
<OLDropdownMenuItem
<DropdownMenuItem
href={`/project/${projectId}/version/${version}/zip`}
download={`${projectId}_v${version}.zip`}
rel="noreferrer"
@@ -26,7 +26,7 @@ function Download({
{...props}
>
{t('history_download_this_version')}
</OLDropdownMenuItem>
</DropdownMenuItem>
)
}
@@ -1,5 +1,5 @@
import { useCallback, useState } from 'react'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import { useTranslation } from 'react-i18next'
import { RestoreProjectModal } from '../../../diff-view/modals/restore-project-modal'
import { useSplitTestContext } from '@/shared/context/split-test-context'
@@ -44,13 +44,13 @@ const RestoreProject = ({
return (
<>
<OLDropdownMenuItem
<DropdownMenuItem
as="button"
leadingIcon={<MaterialIcon type="undo" />}
onClick={handleClick}
>
{t('restore_project_to_this_version')}
</OLDropdownMenuItem>
</DropdownMenuItem>
<RestoreProjectModal
setShow={setShowModal}
show={showModal}
@@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
// Using this workaround due to inconsistent and improper error responses from the server
type ModalErrorProps = {
@@ -16,20 +16,24 @@ function ModalError({ error }: ModalErrorProps) {
if (error.response?.status === 400 && error.data?.message) {
return (
<OLNotification
type="error"
content={error.data.message}
className="row-spaced-small"
/>
<div className="notification-list">
<Notification
type="error"
content={error.data.message}
className="row-spaced-small"
/>
</div>
)
}
return (
<OLNotification
type="error"
content={t('generic_something_went_wrong')}
className="row-spaced-small"
/>
<div className="notification-list">
<Notification
type="error"
content={t('generic_something_went_wrong')}
className="row-spaced-small"
/>
</div>
)
}
@@ -21,7 +21,7 @@ import { FormatTimeBasedOnYear } from '@/shared/components/format-time-based-on-
import { useEditorContext } from '@/shared/context/editor-context'
import OLTag from '@/shared/components/ol/ol-tag'
import OLButton from '@/shared/components/ol/ol-button'
import OLTagIcon from '@/shared/components/ol/ol-tag-icon'
import TagIcon from '@/shared/components/tag-icon'
type TagProps = {
label: LoadedLabel
@@ -79,7 +79,7 @@ const ChangeTag = forwardRef<HTMLElement, TagProps>(
<>
<OLTag
ref={ref}
prepend={<OLTagIcon />}
prepend={<TagIcon />}
closeBtnProps={
showCloseButton
? { 'aria-label': t('delete'), onClick: showConfirmationModal }
@@ -169,7 +169,7 @@ function TagTooltip({ label, currentUserId, showTooltip }: LabelBadgesProps) {
className="history-version-label-tooltip-row-comment"
translate="no"
>
<OLTagIcon />
<TagIcon />
&nbsp;
{label.comment}
</b>
@@ -3,7 +3,7 @@ import { Diff } from '../../services/types/doc'
import DocumentDiffViewer from './document-diff-viewer'
import LoadingSpinner from '../../../../shared/components/loading-spinner'
import { useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
type MainProps = {
diff: Nullable<Diff>
@@ -24,7 +24,9 @@ function Main({ diff, isLoading }: MainProps) {
if (diff.binary) {
return (
<div className="history-content">
<OLNotification content={t('binary_history_error')} type="info" />
<div className="notification-list">
<Notification content={t('binary_history_error')} type="info" />
</div>
</div>
)
}
@@ -5,7 +5,7 @@ import { debugging } from '@/utils/debugging'
import { ElementType } from 'react'
import { createPortal } from 'react-dom'
import { useGlobalAlertsContainer } from '@/features/ide-react/context/global-alerts-context'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
const rollingBuildsUpdatedAlert: Array<{
@@ -39,10 +39,12 @@ export function Alerts() {
{connectionState.forceDisconnected &&
// hide "disconnected" banner when displaying out of sync modal
connectionState.error !== 'out-of-sync' ? (
<OLNotification
type="error"
content={<strong>{t('disconnected')}</strong>}
/>
<div className="notification-list">
<Notification
type="error"
content={<strong>{t('disconnected')}</strong>}
/>
</div>
) : null}
{connectionState.reconnectAt ? (
@@ -53,10 +55,12 @@ export function Alerts() {
) : null}
{isStillReconnecting ? (
<OLNotification
type="warning"
content={<strong>{t('reconnecting')}…</strong>}
/>
<div className="notification-list">
<Notification
type="warning"
content={<strong>{t('reconnecting')}…</strong>}
/>
</div>
) : null}
{connectionState.inactiveDisconnect ||
@@ -64,19 +68,23 @@ export function Alerts() {
(connectionState.error === 'rate-limited' ||
connectionState.error === 'unable-to-connect') &&
!secondsUntilReconnect()) ? (
<OLNotification
type="warning"
content={
<strong>{t('editor_disconected_click_to_reconnect')}</strong>
}
/>
<div className="notification-list">
<Notification
type="warning"
content={
<strong>{t('editor_disconected_click_to_reconnect')}</strong>
}
/>
</div>
) : null}
{debugging ? (
<OLNotification
type="warning"
content={<strong>Connected: {isConnected.toString()}</strong>}
/>
<div className="notification-list">
<Notification
type="warning"
content={<strong>Connected: {isConnected.toString()}</strong>}
/>
</div>
) : null}
</>,
globalAlertsContainer
@@ -1,7 +1,7 @@
import { useTranslation } from 'react-i18next'
import { useEffect, useState } from 'react'
import { secondsUntil } from '@/features/ide-react/connection/utils'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLButton from '@/shared/components/ol/ol-button'
type LostConnectionAlertProps = {
@@ -26,24 +26,26 @@ export function LostConnectionAlert({
}, [reconnectAt])
return (
<OLNotification
type="warning"
content={
<>
<strong>{t('lost_connection')}</strong>{' '}
{t('reconnecting_in_x_secs', { seconds: secondsUntilReconnect })}.
</>
}
action={
<OLButton
id="try-reconnect-now-button"
onClick={() => tryReconnectNow()}
size="sm"
variant="secondary"
>
{t('try_now')}
</OLButton>
}
/>
<div className="notification-list">
<Notification
type="warning"
content={
<>
<strong>{t('lost_connection')}</strong>{' '}
{t('reconnecting_in_x_secs', { seconds: secondsUntilReconnect })}.
</>
}
action={
<OLButton
id="try-reconnect-now-button"
onClick={() => tryReconnectNow()}
size="sm"
variant="secondary"
>
{t('try_now')}
</OLButton>
}
/>
</div>
)
}
@@ -1,5 +1,5 @@
import { useCommandProvider } from '@/features/ide-react/hooks/use-command-provider'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import OLTooltip from '@/shared/components/ol/ol-tooltip'
import { isSmallDevice, sendMB } from '@/infrastructure/event-tracking'
import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context'
@@ -31,14 +31,14 @@ export const DownloadProjectZip = () => {
)
return (
<OLDropdownMenuItem
<DropdownMenuItem
href={`/project/${projectId}/download/zip`}
target="_blank"
rel="noreferrer"
onClick={sendDownloadEvent}
>
{t('download_as_source_zip')}
</OLDropdownMenuItem>
</DropdownMenuItem>
)
}
@@ -75,7 +75,7 @@ export const DownloadProjectPDF = () => {
)
const button = (
<OLDropdownMenuItem
<DropdownMenuItem
href={pdfDownloadUrl || pdfUrl}
target="_blank"
rel="noreferrer"
@@ -83,7 +83,7 @@ export const DownloadProjectPDF = () => {
disabled={!pdfUrl}
>
{t('download_as_pdf')}
</OLDropdownMenuItem>
</DropdownMenuItem>
)
if (!pdfUrl) {
@@ -1,5 +1,5 @@
import EditorCloneProjectModalWrapper from '@/features/clone-project-modal/components/editor-clone-project-modal-wrapper'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
import useOpenProject from '@/shared/hooks/use-open-project'
import getMeta from '@/utils/meta'
@@ -24,9 +24,9 @@ export const DuplicateProject = () => {
return (
<>
<OLDropdownMenuItem onClick={handleShowModal}>
<DropdownMenuItem onClick={handleShowModal}>
{t('make_a_copy')}
</OLDropdownMenuItem>
</DropdownMenuItem>
<EditorCloneProjectModalWrapper
show={showModal}
handleHide={() => setShowModal(false)}
@@ -3,7 +3,7 @@ import { isSplitTestEnabled } from '@/utils/splitTestUtils'
import { FC } from 'react'
import useConvertProject from '../../hooks/use-convert-project'
import { useCommandProvider } from '../../hooks/use-command-provider'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import { useRootDoc } from '@/shared/hooks/use-root-doc'
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
@@ -52,8 +52,6 @@ export const ExportProjectWithConversionButton: FC<
}
return (
<OLDropdownMenuItem onClick={downloadConversion}>
{label}
</OLDropdownMenuItem>
<DropdownMenuItem onClick={downloadConversion}>{label}</DropdownMenuItem>
)
}
@@ -12,7 +12,7 @@ import { useEditorContext } from '@/shared/context/editor-context'
import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
import { DownloadProjectPDF, DownloadProjectZip } from './download-project'
import { useCallback, useState } from 'react'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import EditableLabel from './editable-label'
import { DuplicateProject } from './duplicate-project'
import { ExportProjectWithConversionButton } from './export-project-with-conversion-button'
@@ -99,14 +99,14 @@ export const ToolbarProjectTitle = () => {
/>
<DropdownDivider />
<DuplicateProject />
<OLDropdownMenuItem
<DropdownMenuItem
onClick={() => {
setIsRenaming(true)
}}
disabled={!hasRenamePermissions}
>
{t('rename')}
</OLDropdownMenuItem>
</DropdownMenuItem>
</DropdownMenu>
</Dropdown>
)
@@ -1,7 +1,7 @@
import { DropdownDivider } from '@/shared/components/dropdown/dropdown-menu'
import { useTranslation } from 'react-i18next'
import { useEditorPropertiesContext } from '../../context/editor-properties-context'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import { sendMB } from '@/infrastructure/event-tracking'
import { useIdeReactContext } from '../../context/ide-react-context'
import { usePermissionsContext } from '../../context/permissions-context'
@@ -43,7 +43,7 @@ const ReviewModeOptions: React.FC = () => {
<>
<DropdownDivider />
<NestedMenuBarDropdown id="editing-mode-group" title={t('editing_mode')}>
<OLDropdownMenuItem
<DropdownMenuItem
as="button"
disabled={!write || !user.id}
onClick={() => {
@@ -61,8 +61,8 @@ const ReviewModeOptions: React.FC = () => {
active={write && mode === 'edit'}
>
{t('editing')}
</OLDropdownMenuItem>
<OLDropdownMenuItem
</DropdownMenuItem>
<DropdownMenuItem
as="button"
disabled={permissionsLevel === 'readOnly' || !user.id}
onClick={() => {
@@ -87,15 +87,15 @@ const ReviewModeOptions: React.FC = () => {
active={trackedWrite && mode === 'review'}
>
{t('reviewing')}
</OLDropdownMenuItem>
</DropdownMenuItem>
{showViewOption && (
<OLDropdownMenuItem
<DropdownMenuItem
as="button"
leadingIcon="visibility"
active={mode === 'view'}
>
{t('viewing')}
</OLDropdownMenuItem>
</DropdownMenuItem>
)}
</NestedMenuBarDropdown>
</>
@@ -1,7 +1,7 @@
import { FC, useEffect, useMemo, useRef } from 'react'
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
import { useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { sendMB } from '@/infrastructure/event-tracking'
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
@@ -50,12 +50,14 @@ const UnsavedDocAlert: FC<{ docId: string; seconds: number }> = ({
}
return (
<OLNotification
type="warning"
content={t('saving_notification_with_seconds', {
docname: doc.entity.name,
seconds,
})}
/>
<div className="notification-list">
<Notification
type="warning"
content={t('saving_notification_with_seconds', {
docname: doc.entity.name,
seconds,
})}
/>
</div>
)
}
@@ -1,6 +1,6 @@
import { FC, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
@@ -18,14 +18,16 @@ export const UnsavedDocsLockedAlert: FC = () => {
}, [reportError, openDocs])
return (
<OLNotification
type="warning"
content={
<>
<strong>{t('connection_lost_with_unsaved_changes')}</strong>{' '}
{t('dont_reload_or_close_this_tab')} {t('your_changes_will_save')}
</>
}
/>
<div className="notification-list">
<Notification
type="warning"
content={
<>
<strong>{t('connection_lost_with_unsaved_changes')}</strong>{' '}
{t('dont_reload_or_close_this_tab')} {t('your_changes_will_save')}
</>
}
/>
</div>
)
}
@@ -1,6 +1,6 @@
import useTutorial from '@/shared/hooks/promotions/use-tutorial'
import { useProjectContext } from '@/shared/context/project-context'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { useTranslation, Trans } from 'react-i18next'
import { useCallback } from 'react'
import { onRollingBuild } from '@/shared/utils/rolling-build'
@@ -38,14 +38,16 @@ const RollingCompileImageChangedAlert = () => {
)
return (
<OLNotification
className="mt-5"
isDismissible
onDismiss={onClose}
content={content}
type="info"
title={t('a_new_version_of_the_rolling_texlive_build_released')}
/>
<div className="notification-list">
<Notification
className="mt-5"
isDismissible
onDismiss={onClose}
content={content}
type="info"
title={t('a_new_version_of_the_rolling_texlive_build_released')}
/>
</div>
)
}
@@ -8,7 +8,7 @@ import {
DropdownMenu,
DropdownToggle,
} from '@/shared/components/dropdown/dropdown-menu'
import FormControl from '@/shared/components/form/form-control'
import OLFormControl from '@/shared/components/ol/ol-form-control'
import { isMac } from '@/shared/utils/os'
import { Shortcut } from '@/shared/components/shortcut'
@@ -87,7 +87,7 @@ function PdfZoomDropdown({
className="pdfjs-custom-zoom-menu-item"
eventKey="custom-zoom"
>
<FormControl
<OLFormControl
onFocus={event => event.target.select()}
value={customZoomValue}
type="text"
@@ -1,4 +1,4 @@
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { useTranslation, Trans } from 'react-i18next'
import { useProjectContext } from '@/shared/context/project-context'
import { onRollingBuild } from '@/shared/utils/rolling-build'
@@ -21,12 +21,14 @@ const RollingBuildSelectedReminder = () => {
)
return (
<OLNotification
title={t('this_project_is_compiled_using_untested_version')}
content={content}
type="info"
className="mb-0"
/>
<div className="notification-list">
<Notification
title={t('this_project_is_compiled_using_untested_version')}
content={content}
type="info"
className="mb-0"
/>
</div>
)
}
@@ -12,7 +12,7 @@ import {
import OLButton from '@/shared/components/ol/ol-button'
import '@uppy/core/dist/style.css'
import '@uppy/dashboard/dist/style.css'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
function ImportDocumentModal({
type,
@@ -104,31 +104,33 @@ function ImportDocumentModal({
const ErrorNotification = ({ message }: { message: string }) => {
const { t } = useTranslation()
return (
<OLNotification
type="error"
className="import-error-notification"
content={
<div>
<Trans
i18nKey="your_document_couldnt_be_imported_check_our_guidance_or_expand_conversion_error_details"
components={[
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
<a
href="https://docs.overleaf.com/managing-projects-and-files/importing-and-exporting-files#common-issues-and-how-to-address-them"
target="_BLANK"
rel="noopener noreferrer"
/>,
]}
/>
{message && (
<details style={{ maxHeight: '200px', overflow: 'auto' }}>
<summary>{t('conversion_error_details')}</summary>
<code style={{ wordBreak: 'break-all' }}>{message}</code>
</details>
)}
</div>
}
/>
<div className="notification-list">
<Notification
type="error"
className="import-error-notification"
content={
<div>
<Trans
i18nKey="your_document_couldnt_be_imported_check_our_guidance_or_expand_conversion_error_details"
components={[
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
<a
href="https://docs.overleaf.com/managing-projects-and-files/importing-and-exporting-files#common-issues-and-how-to-address-them"
target="_BLANK"
rel="noopener noreferrer"
/>,
]}
/>
{message && (
<details style={{ maxHeight: '200px', overflow: 'auto' }}>
<summary>{t('conversion_error_details')}</summary>
<code style={{ wordBreak: 'break-all' }}>{message}</code>
</details>
)}
</div>
}
/>
</div>
)
}
@@ -1,5 +1,5 @@
import { useTranslation, Trans } from 'react-i18next'
import Notification from '../../../../../shared/components/notification'
import Notification from '@/shared/components/notification'
import getMeta from '../../../../../utils/meta'
function GroupSsoSetupSuccess() {
@@ -1,8 +1,8 @@
import classnames from 'classnames'
import NewNotification from '@/shared/components/notification'
import BaseNotification from '@/shared/components/notification'
type NotificationProps = Pick<
React.ComponentProps<typeof NewNotification>,
React.ComponentProps<typeof BaseNotification>,
| 'type'
| 'action'
| 'content'
@@ -15,7 +15,7 @@ type NotificationProps = Pick<
function Notification({ className, ...props }: NotificationProps) {
const notificationComponent = (
<NewNotification isDismissible={props.onDismiss != null} {...props} />
<BaseNotification isDismissible={props.onDismiss != null} {...props} />
)
return notificationComponent ? (
@@ -12,7 +12,7 @@ import ProjectListTitle from './title/project-list-title'
import LoadMore from './load-more'
import OLCol from '@/shared/components/ol/ol-col'
import OLRow from '@/shared/components/ol/ol-row'
import { TableContainer } from '@/shared/components/table'
import { TableContainer } from '@/shared/components/ol/ol-table'
import DashApiError from '@/features/project-list/components/dash-api-error'
import getMeta from '@/utils/meta'
import DefaultNavbar from '@/shared/components/navbar/default-navbar'
@@ -4,7 +4,7 @@ import { Tag as TagType } from '../../../../../../../app/src/Features/Tags/types
import { useProjectListContext } from '../../../context/project-list-context'
import { removeProjectFromTag } from '../../../util/api'
import { getTagColor } from '../../../util/tag'
import Tag from '@/shared/components/tag'
import OLTag from '@/shared/components/ol/ol-tag'
type InlineTagsProps = {
projectId: string
@@ -42,7 +42,7 @@ function InlineTag({ tag, projectId }: InlineTagProps) {
[removeProjectFromTagInView]
)
return (
<Tag
<OLTag
prepend={
<i
className="badge-tag-circle"
@@ -60,7 +60,7 @@ function InlineTag({ tag, projectId }: InlineTagProps) {
translate="no"
>
{tag.name}
</Tag>
</OLTag>
)
}
@@ -1,6 +1,6 @@
import { memo, useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import CloneProjectModal from '../../../../../clone-project-modal/components/clone-project-modal'
import useIsMounted from '../../../../../../shared/hooks/use-is-mounted'
import { useProjectListContext } from '../../../../context/project-list-context'
@@ -64,9 +64,9 @@ function CopyProjectMenuItem() {
return (
<>
<OLDropdownMenuItem onClick={handleOpenModal} as="button" tabIndex={-1}>
<DropdownMenuItem onClick={handleOpenModal} as="button" tabIndex={-1}>
{t('make_a_copy')}
</OLDropdownMenuItem>
</DropdownMenuItem>
<CloneProjectModal
show={showModal}
handleHide={handleCloseModal}
@@ -2,7 +2,7 @@ import { memo, useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useProjectListContext } from '../../../../context/project-list-context'
import useIsMounted from '../../../../../../shared/hooks/use-is-mounted'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import RenameProjectModal from '../../../modals/rename-project-modal'
function RenameProjectMenuItem() {
@@ -34,9 +34,9 @@ function RenameProjectMenuItem() {
return (
<>
<OLDropdownMenuItem onClick={handleOpenModal} as="button" tabIndex={-1}>
<DropdownMenuItem onClick={handleOpenModal} as="button" tabIndex={-1}>
{t('rename')}
</OLDropdownMenuItem>
</DropdownMenuItem>
<RenameProjectModal
handleCloseModal={handleCloseModal}
showModal={showModal}
@@ -4,7 +4,7 @@ import {
DropdownMenu,
DropdownToggle,
} from '@/shared/components/dropdown/dropdown-menu'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import MaterialIcon from '@/shared/components/material-icon'
import classNames from 'classnames'
import { useTrackChangesStateActionsContext } from '../context/track-changes-state-context'
@@ -35,7 +35,7 @@ function ReviewModeDropdownItems() {
return (
<>
<OLDropdownMenuItem
<DropdownMenuItem
disabled={!write}
onClick={() => {
if (mode === 'edit') {
@@ -59,8 +59,8 @@ function ReviewModeDropdownItems() {
active={write && mode === 'edit'}
>
{t('editing')}
</OLDropdownMenuItem>
<OLDropdownMenuItem
</DropdownMenuItem>
<DropdownMenuItem
disabled={permissionsLevel === 'readOnly'}
onClick={() => {
if (mode === 'review') {
@@ -95,15 +95,15 @@ function ReviewModeDropdownItems() {
active={trackedWrite && mode === 'review'}
>
{t('reviewing')}
</OLDropdownMenuItem>
</DropdownMenuItem>
{showViewOption && (
<OLDropdownMenuItem
<DropdownMenuItem
description={t('can_view_content')}
leadingIcon="visibility"
active={mode === 'view'}
>
{t('viewing')}
</OLDropdownMenuItem>
</DropdownMenuItem>
)}
</>
)
@@ -1,10 +1,9 @@
import Tooltip from '@/shared/components/tooltip'
import { ComponentProps, memo, MouseEventHandler } from 'react'
import OLTooltip from '@/shared/components/ol/ol-tooltip'
import { ComponentProps, memo, MouseEventHandler } from 'react'
import { PreventSelectingEntry } from '@/features/review-panel/components/review-panel-prevent-selecting'
import MaterialIcon from '@/shared/components/material-icon'
const changeActionTooltipProps: Partial<ComponentProps<typeof Tooltip>> = {
const changeActionTooltipProps: Partial<ComponentProps<typeof OLTooltip>> = {
overlayProps: { placement: 'bottom' },
tooltipProps: { className: 'review-panel-tooltip' },
}
@@ -8,7 +8,7 @@ import getMeta from '../../../utils/meta'
import useAsync from '../../../shared/hooks/use-async'
import { useUserContext } from '../../../shared/context/user-context'
import OLButton from '@/shared/components/ol/ol-button'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLFormGroup from '@/shared/components/ol/ol-form-group'
import OLFormLabel from '@/shared/components/ol/ol-form-label'
import OLFormControl from '@/shared/components/ol/ol-form-control'
@@ -105,18 +105,22 @@ function AccountInfoSection() {
/>
{isSuccess ? (
<OLFormGroup>
<OLNotification
type="success"
content={t('thanks_settings_updated')}
/>
<div className="notification-list">
<Notification
type="success"
content={t('thanks_settings_updated')}
/>
</div>
</OLFormGroup>
) : null}
{isError ? (
<OLFormGroup>
<OLNotification
type="error"
content={getUserFacingMessage(error) ?? ''}
/>
<div className="notification-list">
<Notification
type="error"
content={getUserFacingMessage(error) ?? ''}
/>
</div>
</OLFormGroup>
) : null}
{canUpdateEmail || canUpdateNames ? (
@@ -3,7 +3,7 @@ import { useTranslation, Trans } from 'react-i18next'
import { postJSON, getUserFacingMessage } from '@/infrastructure/fetch-json'
import useAsync from '@/shared/hooks/use-async'
import OLButton from '@/shared/components/ol/ol-button'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import getMeta from '@/utils/meta'
function EmailPreferencesForm() {
@@ -25,20 +25,23 @@ function EmailPreferencesForm() {
return (
<>
{isError && (
<OLNotification
type="error"
content={getUserFacingMessage(error)}
className="mb-3"
/>
<div className="notification-list">
<Notification
type="error"
content={getUserFacingMessage(error)}
className="mb-3"
/>
</div>
)}
{isSuccess && (
<OLNotification
type="success"
content={t('thanks_settings_updated')}
className="mb-3"
/>
<div className="notification-list">
<Notification
type="success"
content={t('thanks_settings_updated')}
className="mb-3"
/>
</div>
)}
<p>
{subscribed ? (
<Trans
@@ -52,7 +55,6 @@ function EmailPreferencesForm() {
/>
)}
</p>
<p className="text-center">
{subscribed ? (
<OLButton
@@ -76,7 +78,6 @@ function EmailPreferencesForm() {
</OLButton>
)}
</p>
{subscribed && <p>{t('newsletter_info_note')}</p>}
</>
)
@@ -8,7 +8,7 @@ import {
import EmailsHeader from './emails/header'
import EmailsRow from './emails/row'
import AddEmail from './emails/add-email'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import LoadingSpinner from '@/shared/components/loading-spinner'
function EmailsSectionContent() {
@@ -78,10 +78,12 @@ function EmailsSectionContent() {
)}
{isInitializingSuccess && !hideAddSecondaryEmail && <AddEmail />}
{isInitializingError && (
<OLNotification
type="error"
content={t('error_performing_request')}
/>
<div className="notification-list">
<Notification
type="error"
content={t('error_performing_request')}
/>
</div>
)}
</>
</>
@@ -1,7 +1,7 @@
import { UseAsyncReturnType } from '../../../../../shared/hooks/use-async'
import { getUserFacingMessage } from '../../../../../infrastructure/fetch-json'
import OLRow from '@/shared/components/ol/ol-row'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
type LayoutProps = {
children: React.ReactNode
@@ -14,10 +14,12 @@ function Layout({ isError, error, children }: LayoutProps) {
<div className="affiliations-table-row-highlighted">
<OLRow>{children}</OLRow>
{isError && (
<OLNotification
type="error"
content={getUserFacingMessage(error) ?? ''}
/>
<div className="notification-list">
<Notification
type="error"
content={getUserFacingMessage(error) ?? ''}
/>
</div>
)}
</div>
)
@@ -5,7 +5,7 @@ import ReconfirmationInfoSuccess from './reconfirmation-info/reconfirmation-info
import ReconfirmationInfoPromptText from './reconfirmation-info/reconfirmation-info-prompt-text'
import OLRow from '@/shared/components/ol/ol-row'
import OLCol from '@/shared/components/ol/ol-col'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { useUserEmailsContext } from '@/features/settings/context/user-email-context'
import { ssoAvailableForInstitution } from '@/features/settings/utils/sso'
import { useTranslation } from 'react-i18next'
@@ -44,14 +44,16 @@ function ReconfirmationInfo({ userEmailData }: ReconfirmationInfoProps) {
return (
<OLRow>
<OLCol lg={12}>
<OLNotification
type="info"
content={
<ReconfirmationInfoSuccess
institution={affiliation.institution}
/>
}
/>
<div className="notification-list">
<Notification
type="info"
content={
<ReconfirmationInfoSuccess
institution={affiliation.institution}
/>
}
/>
</div>
</OLCol>
</OLRow>
)
@@ -62,39 +64,41 @@ function ReconfirmationInfo({ userEmailData }: ReconfirmationInfoProps) {
}
return (
<OLNotification
type="info"
content={
<ReconfirmationInfoPromptText
institutionName={affiliation.institution.name}
primary={userEmailData.default}
/>
}
action={
affiliation?.institution && ssoAvailable ? (
<OLButton
variant="secondary"
disabled={isPending}
onClick={() => {
setIsPending(true)
location.assign(
`${samlInitPath}?university_id=${affiliation.institution.id}&reconfirm=/user/settings`
)
}}
>
{t('confirm_affiliation')}
</OLButton>
) : (
<ResendConfirmationCodeModal
email={userEmailData.email}
setGroupLoading={setUserEmailsContextLoading}
groupLoading={state.isLoading}
onSuccess={getEmails}
triggerVariant="secondary"
<div className="notification-list">
<Notification
type="info"
content={
<ReconfirmationInfoPromptText
institutionName={affiliation.institution.name}
primary={userEmailData.default}
/>
)
}
/>
}
action={
affiliation?.institution && ssoAvailable ? (
<OLButton
variant="secondary"
disabled={isPending}
onClick={() => {
setIsPending(true)
location.assign(
`${samlInitPath}?university_id=${affiliation.institution.id}&reconfirm=/user/settings`
)
}}
>
{t('confirm_affiliation')}
</OLButton>
) : (
<ResendConfirmationCodeModal
email={userEmailData.email}
setGroupLoading={setUserEmailsContextLoading}
groupLoading={state.isLoading}
onSuccess={getEmails}
triggerVariant="secondary"
/>
)
}
/>
</div>
)
}
@@ -1,7 +1,7 @@
import { useState } from 'react'
import { useTranslation, Trans } from 'react-i18next'
import getMeta from '../../../../utils/meta'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
export function SSOAlert() {
const { t } = useTranslation()
@@ -38,12 +38,14 @@ export function SSOAlert() {
)
return !errorClosed ? (
<OLNotification
type="error"
content={content}
isDismissible
onDismiss={handleErrorClosed}
/>
<div className="notification-list">
<Notification
type="error"
content={content}
isDismissible
onDismiss={handleErrorClosed}
/>
</div>
) : null
}
@@ -54,51 +56,57 @@ export function SSOAlert() {
return (
<>
{!infoClosed && (
<OLNotification
type="info"
content={
<>
<p>
<Trans
i18nKey="institution_acct_successfully_linked_2"
components={[<strong />]} // eslint-disable-line react/jsx-key
values={{ institutionName: institutionLinked.universityName }}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
/>
</p>
{institutionLinked.hasEntitlement && (
<div className="notification-list">
<Notification
type="info"
content={
<>
<p>
<Trans
i18nKey="this_grants_access_to_features_2"
i18nKey="institution_acct_successfully_linked_2"
components={[<strong />]} // eslint-disable-line react/jsx-key
values={{ featureType: t('commons') }}
values={{
institutionName: institutionLinked.universityName,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
/>
</p>
)}
</>
}
isDismissible
onDismiss={handleInfoClosed}
/>
{institutionLinked.hasEntitlement && (
<p>
<Trans
i18nKey="this_grants_access_to_features_2"
components={[<strong />]} // eslint-disable-line react/jsx-key
values={{ featureType: t('commons') }}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
/>
</p>
)}
</>
}
isDismissible
onDismiss={handleInfoClosed}
/>
</div>
)}
{!warningClosed && institutionEmailNonCanonical && (
<OLNotification
type="warning"
content={
<Trans
i18nKey="in_order_to_match_institutional_metadata_2"
components={[<strong />]} // eslint-disable-line react/jsx-key
values={{ email: institutionEmailNonCanonical }}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
/>
}
isDismissible
onDismiss={handleWarningClosed}
/>
<div className="notification-list">
<Notification
type="warning"
content={
<Trans
i18nKey="in_order_to_match_institutional_metadata_2"
components={[<strong />]} // eslint-disable-line react/jsx-key
values={{ email: institutionEmailNonCanonical }}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
/>
}
isDismissible
onDismiss={handleWarningClosed}
/>
</div>
)}
</>
)
@@ -5,7 +5,7 @@ import {
OLModalHeader,
OLModalTitle,
} from '@/shared/components/ol/ol-modal'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLButton from '@/shared/components/ol/ol-button'
import { postJSON } from '@/infrastructure/fetch-json'
import { debugConsole } from '@/utils/debugging'
@@ -69,10 +69,12 @@ export default function UnlinkCommonsSSOModal({
{hasLicence && <p>{t('unlink_commons_sso_lose_licence')}</p>}
{!hasPassword && <p>{t('unlink_commons_sso_no_login')}</p>}
{isError && (
<OLNotification
type="error"
content={t('unlink_commons_sso_error')}
/>
<div className="notification-list">
<Notification
type="error"
content={t('unlink_commons_sso_error')}
/>
</div>
)}
</OLModalBody>
<OLModalFooter>
@@ -1,7 +1,7 @@
import { useTranslation, Trans } from 'react-i18next'
import getMeta from '../../../../utils/meta'
import { FetchError } from '../../../../infrastructure/fetch-json'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
type LeaveModalFormErrorProps = {
error: FetchError
@@ -31,20 +31,22 @@ function LeaveModalFormError({ error }: LeaveModalFormErrorProps) {
}
return (
<OLNotification
type="error"
content={
<>
{errorMessage}
{errorTip ? (
<>
<br />
{errorTip}
</>
) : null}
</>
}
/>
<div className="notification-list">
<Notification
type="error"
content={
<>
{errorMessage}
{errorTip ? (
<>
<br />
{errorTip}
</>
) : null}
</>
}
/>
</div>
)
}
@@ -5,7 +5,7 @@ import { useSSOContext, SSOSubscription } from '../context/sso-context'
import { SSOLinkingWidget } from './linking/sso-widget'
import getMeta from '../../../utils/meta'
import { useBroadcastUser } from '@/shared/hooks/user-channel/use-broadcast-user'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
const availableIntegrationLinkingWidgets = importOverleafModules(
'integrationLinkingWidgets'
@@ -104,10 +104,12 @@ function LinkingSection() {
<>
<h3 id="project-sync">{t('project_synchronisation')}</h3>
{projectSyncSuccessMessage ? (
<OLNotification
type="success"
content={projectSyncSuccessMessage}
/>
<div className="notification-list">
<Notification
type="success"
content={projectSyncSuccessMessage}
/>
</div>
) : null}
<div className="settings-widgets-container">
{allIntegrationLinkingWidgets.map(
@@ -144,10 +146,12 @@ function LinkingSection() {
<>
<h3 id="linked-accounts">{t('linked_accounts')}</h3>
{ssoErrorMessage ? (
<OLNotification
type="error"
content={`${t('sso_link_error')}: ${ssoErrorMessage}`}
/>
<div className="notification-list">
<Notification
type="error"
content={`${t('sso_link_error')}: ${ssoErrorMessage}`}
/>
</div>
) : null}
<div className="settings-widgets-container">
{Object.values(subscriptions).map(
@@ -8,7 +8,7 @@ import {
import getMeta from '../../../utils/meta'
import useAsync from '../../../shared/hooks/use-async'
import OLButton from '@/shared/components/ol/ol-button'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLFormGroup from '@/shared/components/ol/ol-form-group'
import OLFormLabel from '@/shared/components/ol/ol-form-label'
import OLFormControl from '@/shared/components/ol/ol-form-control'
@@ -156,44 +156,48 @@ function PasswordForm() {
/>
{isSuccess && data?.message?.text ? (
<OLFormGroup>
<OLNotification type="success" content={data.message.text} />
<div className="notification-list">
<Notification type="success" content={data.message.text} />
</div>
</OLFormGroup>
) : null}
{isError ? (
<OLFormGroup>
<OLNotification
type="error"
content={
getErrorMessageKey(error) === 'password-must-be-strong' ? (
<>
<Trans
i18nKey="password_was_detected_on_a_public_list_of_known_compromised_passwords"
components={[
/* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
<a
href="https://haveibeenpwned.com/passwords"
target="_blank"
rel="noreferrer noopener"
/>,
]}
/>
{t('use_a_different_password')}.
</>
) : getErrorMessageKey(error) === 'password-contains-email' ? (
<>
{t('invalid_password_contains_email')}{' '}
{t('use_a_different_password')}.
</>
) : getErrorMessageKey(error) === 'password-too-similar' ? (
<>
{t('invalid_password_too_similar')}{' '}
{t('use_a_different_password')}.
</>
) : (
(getUserFacingMessage(error) ?? '')
)
}
/>
<div className="notification-list">
<Notification
type="error"
content={
getErrorMessageKey(error) === 'password-must-be-strong' ? (
<>
<Trans
i18nKey="password_was_detected_on_a_public_list_of_known_compromised_passwords"
components={[
/* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
<a
href="https://haveibeenpwned.com/passwords"
target="_blank"
rel="noreferrer noopener"
/>,
]}
/>
{t('use_a_different_password')}.
</>
) : getErrorMessageKey(error) === 'password-contains-email' ? (
<>
{t('invalid_password_contains_email')}{' '}
{t('use_a_different_password')}.
</>
) : getErrorMessageKey(error) === 'password-too-similar' ? (
<>
{t('invalid_password_too_similar')}{' '}
{t('use_a_different_password')}.
</>
) : (
(getUserFacingMessage(error) ?? '')
)
}
/>
</div>
</OLFormGroup>
) : null}
<OLFormGroup>
@@ -21,7 +21,7 @@ import {
DropdownMenu,
DropdownToggle,
} from '@/shared/components/dropdown/dropdown-menu'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import { useFeatureFlag } from '@/shared/context/split-test-context'
import classnames from 'classnames'
@@ -268,7 +268,7 @@ export default function EditMember({
</DropdownToggle>
</div>
<DropdownMenu>
<OLDropdownMenuItem
<DropdownMenuItem
as="button"
eventKey="owner"
leadingIcon={<MaterialIcon type="person_edit" unfilled />}
@@ -276,8 +276,8 @@ export default function EditMember({
trailingIcon={privileges === 'owner' ? 'check' : undefined}
>
{t('make_owner')}
</OLDropdownMenuItem>
<OLDropdownMenuItem
</DropdownMenuItem>
<DropdownMenuItem
as="button"
eventKey="readAndWrite"
leadingIcon={<MaterialIcon type="edit" unfilled />}
@@ -287,9 +287,9 @@ export default function EditMember({
description={getPrivilegeSubtitle('readAndWrite')}
>
{t('editor')}
</OLDropdownMenuItem>
</DropdownMenuItem>
{features.trackChangesVisible && (
<OLDropdownMenuItem
<DropdownMenuItem
as="button"
eventKey="review"
leadingIcon={<MaterialIcon type="mode_comment" unfilled />}
@@ -299,9 +299,9 @@ export default function EditMember({
description={getPrivilegeSubtitle('review')}
>
{t('reviewer')}
</OLDropdownMenuItem>
</DropdownMenuItem>
)}
<OLDropdownMenuItem
<DropdownMenuItem
as="button"
eventKey="readOnly"
leadingIcon={<MaterialIcon type="visibility" unfilled />}
@@ -309,8 +309,8 @@ export default function EditMember({
trailingIcon={privileges === 'readOnly' ? 'check' : undefined}
>
{t('viewer')}
</OLDropdownMenuItem>
<OLDropdownMenuItem
</DropdownMenuItem>
<DropdownMenuItem
as="button"
eventKey="removeAccess"
variant="danger"
@@ -319,7 +319,7 @@ export default function EditMember({
trailingIcon={privileges === 'removeAccess' ? 'check' : undefined}
>
{t('remove_access')}
</OLDropdownMenuItem>
</DropdownMenuItem>
</DropdownMenu>
</Dropdown>
{confirmRemoval && (
@@ -10,7 +10,7 @@ import OLCol from '@/shared/components/ol/ol-col'
import OLTooltip from '@/shared/components/ol/ol-tooltip'
import OLButton from '@/shared/components/ol/ol-button'
import OLBadge from '@/shared/components/ol/ol-badge'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import {
Dropdown,
DropdownMenu,
@@ -120,14 +120,14 @@ function ResendInvite({ invite }: { invite: ProjectMember }) {
)
return isSharingUpdatesEnabled ? (
<OLDropdownMenuItem
<DropdownMenuItem
as="button"
leadingIcon={<MaterialIcon type="mail" unfilled />}
onClick={handleClick}
disabled={inFlight}
>
{t('resend_invite')}
</OLDropdownMenuItem>
</DropdownMenuItem>
) : (
<OLButton
variant="link"
@@ -167,14 +167,14 @@ function RevokeInvite({ invite }: { invite: ProjectMember }) {
}
return isSharingUpdatesEnabled ? (
<OLDropdownMenuItem
<DropdownMenuItem
as="button"
leadingIcon={<MaterialIcon type="block" unfilled />}
variant="danger"
onClick={handleClick}
>
{t('revoke_invite')}
</OLDropdownMenuItem>
</DropdownMenuItem>
) : (
<OLTooltip
id="revoke-invite"
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import ShareProjectModalRow from '@/features/share-project-modal/components/share-project-modal-row'
import MaterialIcon from '@/shared/components/material-icon'
import OLButton from '@/shared/components/ol/ol-button'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import {
Dropdown,
DropdownDivider,
@@ -321,7 +321,7 @@ function ProjectAccess({
<MaterialIcon type="keyboard_arrow_down" />
</DropdownToggle>
<DropdownMenu>
<OLDropdownMenuItem
<DropdownMenuItem
as="button"
eventKey="readAndWrite"
leadingIcon={<MaterialIcon type="edit" unfilled />}
@@ -331,8 +331,8 @@ function ProjectAccess({
}
>
{t('editor')}
</OLDropdownMenuItem>
<OLDropdownMenuItem
</DropdownMenuItem>
<DropdownMenuItem
as="button"
eventKey="review"
leadingIcon={<MaterialIcon type="mode_comment" unfilled />}
@@ -340,8 +340,8 @@ function ProjectAccess({
trailingIcon={privileges === 'review' ? 'check' : undefined}
>
{t('reviewer')}
</OLDropdownMenuItem>
<OLDropdownMenuItem
</DropdownMenuItem>
<DropdownMenuItem
as="button"
eventKey="readOnly"
leadingIcon={<MaterialIcon type="visibility" unfilled />}
@@ -349,7 +349,7 @@ function ProjectAccess({
trailingIcon={privileges === 'readOnly' ? 'check' : undefined}
>
{t('viewer')}
</OLDropdownMenuItem>
</DropdownMenuItem>
</DropdownMenu>
</Dropdown>
)}
@@ -3,7 +3,7 @@ import { useProjectContext } from '@/shared/context/project-context'
import { useEditorContext } from '@/shared/context/editor-context'
import OLRow from '@/shared/components/ol/ol-row'
import OLCol from '@/shared/components/ol/ol-col'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { useFeatureFlag } from '@/shared/context/split-test-context'
function SendInvitesNotice() {
@@ -23,25 +23,29 @@ function SendInvitesNotice() {
return (
<div>
{isPendingEditor && (
<OLNotification
isActionBelowContent
type="info"
title={t('youve_lost_collaboration_access')}
content={
<div>
<p>{t('this_project_already_has_maximum_collaborators')}</p>
<p>
{t(
'please_ask_the_project_owner_to_upgrade_more_collaborators'
)}
</p>
</div>
}
/>
<div className="notification-list">
<Notification
isActionBelowContent
type="info"
title={t('youve_lost_collaboration_access')}
content={
<div>
<p>{t('this_project_already_has_maximum_collaborators')}</p>
<p>
{t(
'please_ask_the_project_owner_to_upgrade_more_collaborators'
)}
</p>
</div>
}
/>
</div>
)}
{accessLevelText &&
(isSharingUpdatesEnabled ? (
<OLNotification type="info" content={accessLevelText} />
<div className="notification-list">
<Notification type="info" content={accessLevelText} />
</div>
) : (
<OLRow className="public-access-level public-access-level-notice">
<OLCol className="text-center">
@@ -11,7 +11,7 @@ import { useMemo } from 'react'
import RecaptchaConditions from '@/shared/components/recaptcha-conditions'
import getMeta from '@/utils/meta'
import { useFeatureFlag } from '@/shared/context/split-test-context'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import ErrorMessage from '@/features/share-project-modal/components/error-message'
import ProjectAccess from '@/features/share-project-modal/components/project-access'
import InvitedPeople from '@/features/share-project-modal/components/invited-people'
@@ -124,14 +124,15 @@ export default function ShareModalBody({
) : (
<SendInvitesNotice />
)}
{isSharingUpdatesEnabled ? (
<>
{error && (
<OLNotification
type="error"
content={<ErrorMessage error={error} />}
/>
<div className="notification-list">
<Notification
type="error"
content={<ErrorMessage error={error} />}
/>
</div>
)}
{isInvitedPeopleScreen || !isProjectOwner ? (
<InvitedPeople
@@ -185,7 +186,6 @@ export default function ShareModalBody({
))}
</>
)}
{!getMeta('ol-ExposedSettings').recaptchaDisabled?.invite && (
<RecaptchaConditions />
)}
@@ -10,7 +10,7 @@ import {
OLModalHeader,
OLModalTitle,
} from '@/shared/components/ol/ol-modal'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLButton from '@/shared/components/ol/ol-button'
import OLSpinner from '@/shared/components/ol/ol-spinner'
import MaterialIcon from '@/shared/components/material-icon'
@@ -100,7 +100,6 @@ function ShareProjectModalContentInner({
{isSharingUpdatesEnabled && isProjectOwner && <GiveFeedbackLink />}
</div>
</OLModalHeader>
<OLModalBody
className={classNames('modal-body-share modal-link-share', {
'modal-redesign': isSharingUpdatesEnabled,
@@ -123,15 +122,16 @@ function ShareProjectModalContentInner({
)}
</Suspense>
{!isSharingUpdatesEnabled && error && (
<OLNotification
type="error"
content={<ErrorMessage error={error} />}
className="mb-0 mt-3"
/>
<div className="notification-list">
<Notification
type="error"
content={<ErrorMessage error={error} />}
className="mb-0 mt-3"
/>
</div>
)}
</div>
</OLModalBody>
<OLModalFooter>
<div className="d-flex flex-grow-1 flex-wrap gap-2">
{isSharingUpdatesEnabled ? (
@@ -10,7 +10,7 @@ import {
OLModalHeader,
OLModalTitle,
} from '@/shared/components/ol/ol-modal'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLButton from '@/shared/components/ol/ol-button'
import { ProjectMember } from '@/shared/context/types/project-metadata'
import OLSpinner from '@/shared/components/ol/ol-spinner'
@@ -61,11 +61,13 @@ export default function TransferOwnershipModal({
</p>
<p>{t('project_ownership_transfer_confirmation_2')}</p>
{error && (
<OLNotification
type="error"
content={t('generic_something_went_wrong')}
className="mb-0 mt-3"
/>
<div className="notification-list">
<Notification
type="error"
content={t('generic_something_went_wrong')}
className="mb-0 mt-3"
/>
</div>
)}
</OLModalBody>
<OLModalFooter>
@@ -2,7 +2,7 @@ import React from 'react'
import classnames from 'classnames'
import type { ConnectionStatus } from './types'
import { Badge, Button } from 'react-bootstrap'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import MaterialIcon from '@/shared/components/material-icon'
const variants = {
@@ -44,7 +44,11 @@ export const DiagnosticItem = ({
)
export function ErrorAlert({ message }: { message: string }) {
return <OLNotification type="error" content={message} className="mt-3" />
return (
<div className="notification-list">
<Notification type="error" content={message} className="mt-3" />
</div>
)
}
export function ActionButton({
@@ -11,7 +11,7 @@ import { FigureModalCurrentProjectSource } from './file-sources/figure-modal-pro
import { FigureModalUploadFileSource } from './file-sources/figure-modal-upload-source'
import { FigureModalUrlSource } from './file-sources/figure-modal-url-source'
import { useCallback } from 'react'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
const sourceModes = new Map([
[FigureModalSource.FILE_TREE, FigureModalCurrentProjectSource],
@@ -44,7 +44,9 @@ export default function FigureModalBody() {
return (
<>
{error && (
<OLNotification type="error" onDismiss={onDismiss} content={error} />
<div className="notification-list">
<Notification type="error" onDismiss={onDismiss} content={error} />
</div>
)}
<Body />
<FigureModalFigureOptions />
@@ -5,7 +5,7 @@ import { useCurrentProjectFolders } from '@/features/source-editor/hooks/use-cur
import OLFormControl from '@/shared/components/ol/ol-form-control'
import OLFormLabel from '@/shared/components/ol/ol-form-label'
import OLFormGroup from '@/shared/components/ol/ol-form-group'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
type FileNameInputProps = Omit<
React.ComponentProps<typeof OLFormControl>,
@@ -85,13 +85,15 @@ export const FileNameInput = ({
<OLFormLabel>{label}</OLFormLabel>
<OLFormControl onFocus={onFocus} {...props} />
{overlap && (
<OLNotification
type="warning"
content={t(
'a_file_with_that_name_already_exists_and_will_be_overriden'
)}
className="mt-1 mb-0"
/>
<div className="notification-list">
<Notification
type="warning"
content={t(
'a_file_with_that_name_already_exists_and_will_be_overriden'
)}
className="mt-1 mb-0"
/>
</div>
)}
</OLFormGroup>
</>
@@ -23,7 +23,7 @@ import {
import { mathPreviewStateField } from '../extensions/math-preview'
import { getTooltip } from '@codemirror/view'
import ReactDOM from 'react-dom'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
const MathPreviewTooltipContainer: FC = () => {
const state = useCodeMirrorStateContext()
@@ -94,7 +94,7 @@ const MathPreviewTooltipMenu: FC = () => {
/>
</DropdownToggle>
<DropdownMenu flip={false}>
<OLDropdownMenuItem
<DropdownMenuItem
onClick={onHide}
description={t('temporarily_hides_the_preview')}
trailingIcon={
@@ -104,13 +104,13 @@ const MathPreviewTooltipMenu: FC = () => {
}
>
{t('hide')}
</OLDropdownMenuItem>
<OLDropdownMenuItem
</DropdownMenuItem>
<DropdownMenuItem
onClick={openDisableModal}
description={t('permanently_disables_the_preview')}
>
{t('disable')}
</OLDropdownMenuItem>
</DropdownMenuItem>
</DropdownMenu>
</Dropdown>
@@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next'
import OLRow from '@/shared/components/ol/ol-row'
import OLCol from '@/shared/components/ol/ol-col'
import OLPageContentCard from '@/shared/components/ol/ol-page-content-card'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
function Canceled() {
const { t } = useTranslation()
@@ -13,17 +13,19 @@ function Canceled() {
<OLCol lg={{ span: 8, offset: 2 }}>
<OLPageContentCard>
<h2>{t('subscription_canceled')}</h2>
<OLNotification
type="info"
content={
<div className="d-flex justify-content-between align-items-center gap-3">
<span>{t('to_modify_your_subscription_go_to')}</span>
<a href="/user/subscription" rel="noopener noreferrer">
{t('manage_subscription')}
</a>
</div>
}
/>
<div className="notification-list">
<Notification
type="info"
content={
<div className="d-flex justify-content-between align-items-center gap-3">
<span>{t('to_modify_your_subscription_go_to')}</span>
<a href="/user/subscription" rel="noopener noreferrer">
{t('manage_subscription')}
</a>
</div>
}
/>
</div>
<p>
<a
className="btn btn-primary"
@@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
export default function GenericErrorAlert({
className,
@@ -9,16 +9,18 @@ export default function GenericErrorAlert({
const { t } = useTranslation()
return (
<OLNotification
className={className}
aria-live="polite"
type="error"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
<div className="notification-list">
<Notification
className={className}
aria-live="polite"
type="error"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
</div>
)
}
@@ -1,7 +1,7 @@
import { Trans } from 'react-i18next'
import { Institution } from '../../../../../../types/institution'
import { useSubscriptionDashboardContext } from '../../context/subscription-dashboard-context'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
function InstitutionMemberships() {
const { institutionMemberships } = useSubscriptionDashboardContext()
@@ -10,16 +10,18 @@ function InstitutionMemberships() {
if (!institutionMemberships) {
return (
<OLNotification
type="warning"
content={
<p>
Sorry, something went wrong. Subscription information related to
institutional affiliations may not be displayed. Please try again
later.
</p>
}
/>
<div className="notification-list">
<Notification
type="warning"
content={
<p>
Sorry, something went wrong. Subscription information related to
institutional affiliations may not be displayed. Please try again
later.
</p>
}
/>
</div>
)
}
@@ -10,7 +10,7 @@ import {
} from '@/shared/components/ol/ol-modal'
import { Select } from '@/shared/components/select'
import OLFormGroup from '@/shared/components/ol/ol-form-group'
import Button from '@/shared/components/button/button'
import OLButton from '@/shared/components/ol/ol-button'
import { Stack } from 'react-bootstrap'
import { debugConsole } from '@/utils/debugging'
import * as eventTracking from '../../../../infrastructure/event-tracking'
@@ -119,19 +119,19 @@ export default function PauseSubscriptionModal() {
/>
</OLFormGroup>
<Stack gap={2}>
<Button
<OLButton
onClick={handleConfirmPauseSubscriptionClick}
disabled={inflight}
>
{t('pause_subscription')}
</Button>
<Button
</OLButton>
<OLButton
onClick={handleCancelSubscriptionClick}
disabled={inflight}
variant="danger-ghost"
>
{t('cancel_subscription')}
</Button>
</OLButton>
</Stack>
</OLModalBody>
</OLModal>
@@ -3,7 +3,7 @@ import { useSubscriptionDashboardContext } from '../../context/subscription-dash
import getMeta from '../../../../utils/meta'
import useAsync from '../../../../shared/hooks/use-async'
import { postJSON } from '../../../../infrastructure/fetch-json'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLButton from '@/shared/components/ol/ol-button'
import OLFormGroup from '@/shared/components/ol/ol-form-group'
@@ -29,10 +29,12 @@ function PersonalSubscriptionSyncEmail() {
<form onSubmit={handleSubmit}>
<OLFormGroup>
{isSuccess ? (
<OLNotification
type="success"
content={t('recurly_email_updated')}
/>
<div className="notification-list">
<Notification
type="success"
content={t('recurly_email_updated')}
/>
</div>
) : (
<>
<p>
@@ -6,7 +6,7 @@ import { CanceledSubscription } from './states/canceled'
import { ExpiredSubscription } from './states/expired'
import { useSubscriptionDashboardContext } from '../../context/subscription-dashboard-context'
import PersonalSubscriptionSyncEmail from './personal-subscription-sync-email'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
function PastDueSubscriptionAlert({
subscription,
@@ -15,21 +15,23 @@ function PastDueSubscriptionAlert({
}) {
const { t } = useTranslation()
return (
<OLNotification
type="error"
content={
<>
{t('account_has_past_due_invoice_change_plan_warning')}{' '}
<a
href={subscription.payment.accountManagementLink}
target="_blank"
rel="noreferrer noopener"
>
{t('view_your_invoices')}
</a>
</>
}
/>
<div className="notification-list">
<Notification
type="error"
content={
<>
{t('account_has_past_due_invoice_change_plan_warning')}{' '}
<a
href={subscription.payment.accountManagementLink}
target="_blank"
rel="noreferrer noopener"
>
{t('view_your_invoices')}
</a>
</>
}
/>
</div>
)
}
@@ -82,10 +84,12 @@ function PersonalSubscription() {
subscription={personalSubscription as PaidSubscription}
/>
{recurlyLoadError && (
<OLNotification
type="warning"
content={<strong>{t('payment_provider_unreachable_error')}</strong>}
/>
<div className="notification-list">
<Notification
type="warning"
content={<strong>{t('payment_provider_unreachable_error')}</strong>}
/>
</div>
)}
<hr />
<PersonalSubscriptionSyncEmail />
@@ -1,5 +1,5 @@
import { Trans, useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import OLButton from '@/shared/components/ol/ol-button'
function RedirectAlerts() {
@@ -41,7 +41,9 @@ function RedirectAlerts() {
}
return (
<OLNotification type="warning" content={<>{warning}</>} action={action} />
<div className="notification-list">
<Notification type="warning" content={<>{warning}</>} action={action} />
</div>
)
}
export default RedirectAlerts
@@ -4,7 +4,7 @@ import getMeta from '@/utils/meta'
import { Dropdown, DropdownMenu, DropdownToggle } from 'react-bootstrap'
import { postJSON } from '@/infrastructure/fetch-json'
import { debugConsole } from '@/utils/debugging'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import OLSpinner from '@/shared/components/ol/ol-spinner'
import MaterialIcon from '@/shared/components/material-icon'
import { useLocation } from '@/shared/hooks/use-location'
@@ -119,22 +119,22 @@ function AddOn({
</DropdownToggle>
<DropdownMenu flip={false}>
{pendingCancellation ? (
<OLDropdownMenuItem
<DropdownMenuItem
onClick={() => handleReactivateClick(addOnCode)}
as="button"
tabIndex={-1}
>
{t('reactivate')}
</OLDropdownMenuItem>
</DropdownMenuItem>
) : (
<OLDropdownMenuItem
<DropdownMenuItem
onClick={() => handleCancelClick(addOnCode)}
as="button"
tabIndex={-1}
variant="danger"
>
{t('cancel')}
</OLDropdownMenuItem>
</DropdownMenuItem>
)}
</DropdownMenu>
</Dropdown>
@@ -12,7 +12,7 @@ import {
OLModalTitle,
} from '@/shared/components/ol/ol-modal'
import OLButton from '@/shared/components/ol/ol-button'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import {
AI_ADD_ON_CODE,
ADD_ON_NAME,
@@ -66,19 +66,20 @@ export function CancelAiAddOnModal() {
<OLModalHeader>
<OLModalTitle>{t('cancel_add_on')}</OLModalTitle>
</OLModalHeader>
<OLModalBody>
{error && (
<OLNotification
type="error"
aria-live="polite"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
<div className="notification-list">
<Notification
type="error"
aria-live="polite"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
</div>
)}
<p>
<Trans
@@ -93,7 +94,6 @@ export function CancelAiAddOnModal() {
</p>
<p>{t('the_add_on_will_remain_active_until')}</p>
</OLModalBody>
<OLModalFooter>
<OLButton
variant="secondary"
@@ -29,7 +29,7 @@ import OLFormCheckbox from '@/shared/components/ol/ol-form-checkbox'
import { useContactUsModal } from '@/shared/hooks/use-contact-us-modal'
import { UserProvider } from '@/shared/context/user-context'
import OLButton from '@/shared/components/ol/ol-button'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import handleStripePaymentAction from '@/features/subscription/util/handle-stripe-payment-action'
const educationalPercentDiscount = 40
@@ -311,16 +311,18 @@ export function ChangeToGroupModal() {
</p>
<hr className="thin my-3" />
{error && (
<OLNotification
type="error"
aria-live="polite"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
<div className="notification-list">
<Notification
type="error"
aria-live="polite"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
</div>
)}
<OLButton
variant="primary"
@@ -16,7 +16,7 @@ import {
OLModalTitle,
} from '@/shared/components/ol/ol-modal'
import OLButton from '@/shared/components/ol/ol-button'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
export function KeepCurrentPlanModal() {
const modalId: SubscriptionDashModalIds = 'keep-current-plan'
@@ -53,19 +53,20 @@ export function KeepCurrentPlanModal() {
<OLModalHeader>
<OLModalTitle>{t('change_plan')}</OLModalTitle>
</OLModalHeader>
<OLModalBody>
{error && (
<OLNotification
type="error"
aria-live="polite"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
<div className="notification-list">
<Notification
type="error"
aria-live="polite"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
</div>
)}
<p>
<Trans
@@ -82,7 +83,6 @@ export function KeepCurrentPlanModal() {
/>
</p>
</OLModalBody>
<OLModalFooter>
<OLButton
variant="secondary"
@@ -11,7 +11,7 @@ import {
import OLButton from '@/shared/components/ol/ol-button'
import sparkle from '@/shared/svgs/sparkle.svg'
import { Dropdown, DropdownMenu, DropdownToggle } from 'react-bootstrap'
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
import DropdownMenuItem from '@/shared/components/dropdown/dropdown-menu-item'
import MaterialIcon from '@/shared/components/material-icon'
import { ADD_ON_NAME } from '@/features/subscription/data/add-on-codes'
import getMeta from '@/utils/meta'
@@ -102,9 +102,9 @@ function WritefullGrantedAddOn({
/>
</DropdownToggle>
<DropdownMenu flip={false}>
<OLDropdownMenuItem tabIndex={-1} onClick={handleManageOnWritefull}>
<DropdownMenuItem tabIndex={-1} onClick={handleManageOnWritefull}>
{t('manage_subscription')}
</OLDropdownMenuItem>
</DropdownMenuItem>
</DropdownMenu>
</Dropdown>
</div>
@@ -12,7 +12,7 @@ import {
import OLButton from '@/shared/components/ol/ol-button'
import { postJSON } from '@/infrastructure/fetch-json'
import { useLocation } from '@/shared/hooks/use-location'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
export function ConfirmUnpauseSubscriptionModal() {
@@ -53,19 +53,20 @@ export function ConfirmUnpauseSubscriptionModal() {
<OLModalHeader>
<OLModalTitle>{t('pick_up_where_you_left_off')}</OLModalTitle>
</OLModalHeader>
<OLModalBody>
{error && (
<OLNotification
type="error"
aria-live="polite"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
<div className="notification-list">
<Notification
type="error"
aria-live="polite"
content={
<>
{t('generic_something_went_wrong')}. {t('try_again')}.{' '}
{t('generic_if_problem_continues_contact_us')}.
</>
}
/>
</div>
)}
<p>
<Trans
@@ -13,7 +13,7 @@ import PremiumFeaturesLink from './premium-features-link'
import OLPageContentCard from '@/shared/components/ol/ol-page-content-card'
import OLRow from '@/shared/components/ol/ol-row'
import OLCol from '@/shared/components/ol/ol-col'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import WritefullManagedBundleAddOn from './states/active/change-plan/modals/writefull-bundle-management-modal'
import RedirectAlerts from './redirect-alerts'
import { PaidSubscription } from '@ol-types/subscription/dashboard/subscription'
@@ -49,52 +49,58 @@ function SubscriptionDashboard() {
<OLRow>
<OLCol lg={{ span: 8, offset: 2 }}>
{hasPendingPlan && (
<OLNotification
className="mb-4"
aria-live="polite"
content={
<div>
<Trans
i18nKey="pending_subscription_message"
values={{
planName: personalSubscription?.pendingPlan?.name,
activationDate: nextPaymentDueDate,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
</div>
}
type="success"
/>
<div className="notification-list">
<Notification
className="mb-4"
aria-live="polite"
content={
<div>
<Trans
i18nKey="pending_subscription_message"
values={{
planName: personalSubscription?.pendingPlan?.name,
activationDate: nextPaymentDueDate,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
</div>
}
type="success"
/>
</div>
)}
{fromPlansPage && (
<OLNotification
className="mb-4"
aria-live="polite"
content={t('you_already_have_a_subscription')}
type="warning"
/>
<div className="notification-list">
<Notification
className="mb-4"
aria-live="polite"
content={t('you_already_have_a_subscription')}
type="warning"
/>
</div>
)}
{hasRedirectedPaymentError && (
<OLNotification
className="mb-4"
aria-live="polite"
content={
<Trans
i18nKey="payment_error_generic"
components={[
/* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
<a href="/contact" target="_blank" />,
]}
/>
}
type="error"
/>
<div className="notification-list">
<Notification
className="mb-4"
aria-live="polite"
content={
<Trans
i18nKey="payment_error_generic"
components={[
/* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
<a href="/contact" target="_blank" />,
]}
/>
}
type="error"
/>
</div>
)}
<RedirectAlerts />
<OLPageContentCard>
@@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import getMeta from '@/utils/meta'
export default function TrialDisabledNotification() {
@@ -11,11 +11,13 @@ export default function TrialDisabledNotification() {
}
return (
<OLNotification
className="mb-4"
aria-live="polite"
content={t('youre_not_eligible_for_a_free_trial')}
type="warning"
/>
<div className="notification-list">
<Notification
className="mb-4"
aria-live="polite"
content={t('youre_not_eligible_for_a_free_trial')}
type="warning"
/>
</div>
)
}
@@ -1,6 +1,6 @@
import { FetchError } from '@/infrastructure/fetch-json'
import { Trans } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { billingPortalUrl } from '../../data/subscription-url'
type Props = {
@@ -62,5 +62,9 @@ export default function PaymentErrorNotification({ error }: Props) {
}
}
return <OLNotification type="error" aria-live="polite" content={message} />
return (
<div className="notification-list">
<Notification type="error" aria-live="polite" content={message} />
</div>
)
}
@@ -1,5 +1,5 @@
import { Trans } from 'react-i18next'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import getMeta from '@/utils/meta'
export default function RedirectedPaymentErrorNotification() {
@@ -12,19 +12,21 @@ export default function RedirectedPaymentErrorNotification() {
}
return (
<OLNotification
className="mb-4"
aria-live="polite"
content={
<Trans
i18nKey="payment_error_generic"
components={[
/* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
<a href="/contact" target="_blank" />,
]}
/>
}
type="error"
/>
<div className="notification-list">
<Notification
className="mb-4"
aria-live="polite"
content={
<Trans
i18nKey="payment_error_generic"
components={[
/* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
<a href="/contact" target="_blank" />,
]}
/>
}
type="error"
/>
</div>
)
}
@@ -6,7 +6,7 @@ import { useSubscriptionDashboardContext } from '../../context/subscription-dash
import OLRow from '@/shared/components/ol/ol-row'
import OLCol from '@/shared/components/ol/ol-col'
import OLPageContentCard from '@/shared/components/ol/ol-page-content-card'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import {
AI_ADD_ON_CODE,
ADD_ON_NAME,
@@ -44,37 +44,39 @@ function SuccessfulSubscription() {
<OLCol lg={{ span: 8, offset: 2 }}>
<OLPageContentCard>
<h2>{t('thanks_for_subscribing')}</h2>
<OLNotification
type="success"
content={
<>
{subscription.payment.trialEndsAt && (
<>
<p>
<Trans
i18nKey="next_payment_of_x_collectected_on_y"
values={{
paymentAmmount: subscription.payment.displayPrice,
collectionDate:
subscription.payment.nextPaymentDueAt,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[<strong />, <strong />]} // eslint-disable-line react/jsx-key
/>
</p>
<PriceExceptions subscription={subscription} />
</>
)}
<div className="d-flex justify-content-between align-items-center gap-3">
<span>{t('to_modify_your_subscription_go_to')}</span>
<a href="/user/subscription" rel="noopener noreferrer">
{t('manage_subscription')}
</a>
</div>
</>
}
/>
<div className="notification-list">
<Notification
type="success"
content={
<>
{subscription.payment.trialEndsAt && (
<>
<p>
<Trans
i18nKey="next_payment_of_x_collectected_on_y"
values={{
paymentAmmount: subscription.payment.displayPrice,
collectionDate:
subscription.payment.nextPaymentDueAt,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[<strong />, <strong />]} // eslint-disable-line react/jsx-key
/>
</p>
<PriceExceptions subscription={subscription} />
</>
)}
<div className="d-flex justify-content-between align-items-center gap-3">
<span>{t('to_modify_your_subscription_go_to')}</span>
<a href="/user/subscription" rel="noopener noreferrer">
{t('manage_subscription')}
</a>
</div>
</>
}
/>
</div>
{subscription.groupPlan && (
<p>
<a
@@ -155,17 +157,19 @@ function UpgradeSuccess({
<OLCol lg={{ span: 8, offset: 2 }}>
<OLPageContentCard>
<h2>{t('welcome_to_plan', { planName: planDisplayName })}</h2>
<OLNotification
type="success"
content={
<div className="d-flex justify-content-between align-items-center gap-3">
<span>{t('youve_upgraded_your_subscription')}</span>
<a href="/user/subscription" rel="noopener noreferrer">
{t('manage_subscription')}
</a>
</div>
}
/>
<div className="notification-list">
<Notification
type="success"
content={
<div className="d-flex justify-content-between align-items-center gap-3">
<span>{t('youve_upgraded_your_subscription')}</span>
<a href="/user/subscription" rel="noopener noreferrer">
{t('manage_subscription')}
</a>
</div>
}
/>
</div>
<p>
<Trans
i18nKey="next_payment_of_x_collectected_on_y"
@@ -1,10 +1,12 @@
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import { useTranslation } from 'react-i18next'
export const WordCountError = () => {
const { t } = useTranslation()
return (
<OLNotification type="error" content={t('generic_something_went_wrong')} />
<div className="notification-list">
<Notification type="error" content={t('generic_something_went_wrong')} />
</div>
)
}
@@ -2,7 +2,7 @@ import { FC, useMemo } from 'react'
import { WordCountData } from '@/features/word-count-modal/components/word-count-data'
import { useTranslation } from 'react-i18next'
import { Container, Row, Col, Form } from 'react-bootstrap'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
import usePersistedState from '@/shared/hooks/use-persisted-state'
const numberFormat = new Intl.NumberFormat()
@@ -77,16 +77,17 @@ export const WordCountsClient: FC<{ data: WordCountData }> = ({ data }) => {
{data.messages && (
<Row>
<Col xs={12}>
<OLNotification
type="error"
content={
<p style={{ whiteSpace: 'pre-wrap' }}>{data.messages}</p>
}
/>
<div className="notification-list">
<Notification
type="error"
content={
<p style={{ whiteSpace: 'pre-wrap' }}>{data.messages}</p>
}
/>
</div>
</Col>
</Row>
)}
<Row className="mb-4">
<table style={{ width: 'auto' }}>
<thead>
@@ -138,19 +139,16 @@ export const WordCountsClient: FC<{ data: WordCountData }> = ({ data }) => {
</tbody>
</table>
</Row>
<Row className="border-top py-2">
<Col xs={12}>
<b>{t('headers')}:</b> {data.headers}
</Col>
</Row>
<Row className="border-top py-2">
<Col xs={12}>
<b>{t('inline_math')}:</b> {data.mathInline}
</Col>
</Row>
<Row className="border-top py-2 pb-0">
<Col xs={12}>
<b>{t('display_math')}:</b> {data.mathDisplay}
@@ -2,7 +2,7 @@ import { FC } from 'react'
import { ServerWordCountData } from '@/features/word-count-modal/components/word-count-data'
import { useTranslation } from 'react-i18next'
import { Container, Row, Col } from 'react-bootstrap'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
export const WordCounts: FC<{
data: ServerWordCountData
@@ -14,16 +14,17 @@ export const WordCounts: FC<{
{data.messages && (
<Row>
<Col xs={12}>
<OLNotification
type="error"
content={
<p style={{ whiteSpace: 'pre-wrap' }}>{data.messages}</p>
}
/>
<div className="notification-list">
<Notification
type="error"
content={
<p style={{ whiteSpace: 'pre-wrap' }}>{data.messages}</p>
}
/>
</div>
</Col>
</Row>
)}
<Row>
<Col xs={4}>
<div className="float-end">{t('total_words')}:</div>
@@ -36,14 +37,12 @@ export const WordCounts: FC<{
</Col>
<Col xs={6}>{data.headers}</Col>
</Row>
<Row>
<Col xs={4}>
<div className="float-end">{t('math_inline')}:</div>
</Col>
<Col xs={6}>{data.mathInline}</Col>
</Row>
<Row>
<Col xs={4}>
<div className="float-end">{t('math_display')}:</div>
@@ -1,6 +1,6 @@
import classNames from 'classnames'
import type { MergeAndOverride } from '../../../../../types/utils'
import Badge, { type BadgeProps } from './badge'
import Badge, { type OLBadgeProps as BadgeProps } from '../ol/ol-badge'
export type BadgeLinkProps = MergeAndOverride<
BadgeProps,
@@ -1,23 +0,0 @@
import { Badge as BSBadge, BadgeProps as BSBadgeProps } from 'react-bootstrap'
import { MergeAndOverride } from '../../../../../types/utils'
export type BadgeProps = MergeAndOverride<
BSBadgeProps,
{
prepend?: React.ReactNode
badgeContentRef?: React.RefObject<HTMLElement>
}
>
function Badge({ prepend, children, badgeContentRef, ...rest }: BadgeProps) {
return (
<BSBadge {...rest}>
{prepend && <span className="badge-prepend">{prepend}</span>}
<span className="badge-content" ref={badgeContentRef}>
{children}
</span>
</BSBadge>
)
}
export default Badge
@@ -1,77 +0,0 @@
import { forwardRef } from 'react'
import { Button as BS5Button } from 'react-bootstrap'
import type { ButtonProps } from '@/shared/components/types/button-props'
import classNames from 'classnames'
import { useTranslation } from 'react-i18next'
import MaterialIcon from '@/shared/components/material-icon'
import OLSpinner from '../ol/ol-spinner'
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(
{
children,
className,
leadingIcon,
isLoading = false,
loadingLabel,
trailingIcon,
variant = 'primary',
...props
},
ref
) => {
const { t } = useTranslation()
const buttonClassName = classNames('d-inline-grid', className, {
'button-loading': isLoading,
})
const loadingSpinnerClassName =
props.size === 'lg' ? 'loading-spinner-large' : 'loading-spinner-small'
const materialIconClassName =
props.size === 'lg' ? 'icon-large' : 'icon-small'
const leadingIconComponent =
leadingIcon && typeof leadingIcon === 'string' ? (
<MaterialIcon type={leadingIcon} className={materialIconClassName} />
) : (
leadingIcon
)
const trailingIconComponent =
trailingIcon && typeof trailingIcon === 'string' ? (
<MaterialIcon type={trailingIcon} className={materialIconClassName} />
) : (
trailingIcon
)
return (
<BS5Button
className={buttonClassName}
variant={variant}
{...props}
ref={ref}
disabled={isLoading || props.disabled}
data-ol-loading={isLoading}
role={undefined}
>
{isLoading && (
<span className="spinner-container">
<OLSpinner size="sm" className={loadingSpinnerClassName} />
<span className="visually-hidden">
{loadingLabel ?? t('loading')}
</span>
</span>
)}
<span className="button-content" aria-hidden={isLoading}>
{leadingIconComponent}
{children}
{trailingIconComponent}
</span>
</BS5Button>
)
}
)
Button.displayName = 'Button'
export default Button
@@ -1,46 +0,0 @@
import { forwardRef } from 'react'
import classNames from 'classnames'
import MaterialIcon from '@/shared/components/material-icon'
import Button from './button'
import type { IconButtonProps } from '@/shared/components/types/icon-button-props'
const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
(
{
accessibilityLabel,
icon,
isLoading = false,
size,
className,
unfilled,
...props
},
ref
) => {
const iconButtonClassName = classNames(className, {
'icon-button': !size,
'icon-button-small': size === 'sm',
'icon-button-large': size === 'lg',
})
const iconSizeClassName = size === 'lg' ? 'icon-large' : 'icon-small'
const materialIconClassName = classNames(iconSizeClassName, {
'button-content-hidden': isLoading,
unfilled,
})
return (
<Button
className={iconButtonClassName}
isLoading={isLoading}
aria-label={accessibilityLabel}
{...props}
ref={ref}
>
<MaterialIcon className={materialIconClassName} type={icon} />
</Button>
)
}
)
IconButton.displayName = 'IconButton'
export default IconButton
@@ -3,7 +3,7 @@ import { DropdownItemProps } from '@/shared/components/types/dropdown-menu-props
import DropdownListItem from '@/shared/components/dropdown/dropdown-list-item'
// This represents a menu item. It wraps the item within an <li> element.
function OLDropdownMenuItem(props: DropdownItemProps) {
function DropdownMenuItem(props: DropdownItemProps) {
return (
<DropdownListItem>
<DropdownItem {...props} />
@@ -11,4 +11,4 @@ function OLDropdownMenuItem(props: DropdownItemProps) {
)
}
export default OLDropdownMenuItem
export default DropdownMenuItem
@@ -1,5 +1,5 @@
import { Form } from 'react-bootstrap'
import FormText from '@/shared/components/form/form-text'
import OLFormText from '@/shared/components/ol/ol-form-text'
import { ComponentProps } from 'react'
export type FormFeedbackProps = Pick<
@@ -10,9 +10,9 @@ export type FormFeedbackProps = Pick<
function DSFormFeedback(props: FormFeedbackProps) {
return (
<Form.Control.Feedback {...props}>
<FormText type={props.type === 'invalid' ? 'error' : 'success'}>
<OLFormText type={props.type === 'invalid' ? 'error' : 'success'}>
{props.children}
</FormText>
</OLFormText>
</Form.Control.Feedback>
)
}
@@ -1,13 +1,15 @@
import { FC, ReactNode } from 'react'
import { DefaultMessage } from './default-message'
import OLNotification from '@/shared/components/ol/ol-notification'
import Notification from '@/shared/components/notification'
export const ErrorBoundaryFallback: FC<
React.PropsWithChildren<{ modal?: ReactNode }>
> = ({ children, modal }) => {
return (
<div className="error-boundary-alert">
<OLNotification type="error" content={children || <DefaultMessage />} />
<div className="notification-list">
<Notification type="error" content={children || <DefaultMessage />} />
</div>
{modal}
</div>
)

Some files were not shown because too many files have changed in this diff Show More