diff --git a/e2e-tests/cypress/tests/integration/channels/collapsed_reply_threads/channel_notifications_spec.js b/e2e-tests/cypress/tests/integration/channels/collapsed_reply_threads/channel_notifications_spec.js index c34cb4022de8..6f1aa45dca80 100644 --- a/e2e-tests/cypress/tests/integration/channels/collapsed_reply_threads/channel_notifications_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/collapsed_reply_threads/channel_notifications_spec.js @@ -53,10 +53,15 @@ describe('CRT Desktop notifications', () => { cy.visit(testChannelUrl); cy.uiOpenChannelMenu('Notification Preferences'); - cy.get('[data-testid="muteChannel"]').click().then(() => { - cy.get('.AlertBanner--app').should('be.visible'); - }); - cy.get('.channel-notifications-settings-modal__save-btn').should('be.visible').click(); + + // # Click on Mute Channel to Unmute Channel + cy.findByText('Mute channel').should('be.visible').click({force: true}); + + // * Verify that channel is muted alert is visible + cy.findByText('This channel is muted').should('be.visible'); + + // # Save the changes + cy.findByText('Save').should('be.visible').click(); // Setup notification spy spyNotificationAs('notifySpy', 'granted'); @@ -64,8 +69,8 @@ describe('CRT Desktop notifications', () => { // # Set users notification settings cy.uiOpenChannelMenu('Notification Preferences'); - // # click on Mute Channel to Unmute Channel - cy.get('[data-testid="muteChannel"]').click(); + // # Click on Mute Channel to Unmute Channel + cy.findByText('Mute channel').should('be.visible').click({force: true}); // # Click "Desktop Notifications" cy.findByText('Desktop Notifications').should('be.visible'); @@ -83,15 +88,16 @@ describe('CRT Desktop notifications', () => { cy.get('.channel-notifications-settings-modal__body').scrollTo('center').get('#desktopNotification-none').should('be.visible').click(); cy.get('.channel-notifications-settings-modal__body').get('#desktopNotification-none').should('be.checked'); - // # click on Save button - cy.get('.channel-notifications-settings-modal__save-btn').should('be.visible').click(); + // # Save the changes + cy.findByText('Save').should('be.visible').click(); // # Set users notification settings cy.uiOpenChannelMenu('Notification Preferences'); cy.get('.channel-notifications-settings-modal__body').scrollTo('center').get('#desktopNotification-none').should('be.checked'); cy.get('.channel-notifications-settings-modal__body').get('#desktopNotification-all').scrollIntoView().should('be.visible').click(); - cy.get('.channel-notifications-settings-modal__save-btn').should('be.visible').click(); + // # Save the changes + cy.findByText('Save').should('be.visible').click(); // # Post a root message as other user cy.postMessageAs({sender, message: 'This is a not followed root message', channelId: testChannelId, rootId: ''}).then(({id: postId}) => { @@ -137,6 +143,7 @@ describe('CRT Desktop notifications', () => { it('MM-T4417_2 Click on sameMobileSettingsDesktop and check if additional settings still appears', () => { cy.visit(testChannelUrl); cy.uiOpenChannelMenu('Notification Preferences'); + cy.get('.channel-notifications-settings-modal__body').scrollTo('center').get('#desktopNotification-mention').should('be.visible').click().then(() => { cy.get('[data-testid="desktopReplyThreads"]').should('be.visible').click(); }); @@ -157,8 +164,8 @@ describe('CRT Desktop notifications', () => { cy.get('[data-testid="autoFollowThreads"]').should('be.visible').click(); - // # click on Save button - cy.get('.channel-notifications-settings-modal__save-btn').should('be.visible').click(); + // # Save the changes + cy.findByText('Save').should('be.visible').click(); }); it('MM-T4417_3 Trigger notifications only on mention replies when channel setting is unchecked', () => { @@ -168,7 +175,9 @@ describe('CRT Desktop notifications', () => { spyNotificationAs('notifySpy', 'granted'); cy.uiOpenChannelMenu('Notification Preferences'); cy.get('.channel-notifications-settings-modal__body').scrollTo('center').get('#desktopNotification-mention').should('be.visible').click(); - cy.get('.channel-notifications-settings-modal__save-btn').should('be.visible').click(); + + // # Save the changes + cy.findByText('Save').should('be.visible').click(); // # Post a root message as other user cy.postMessageAs({sender, message: 'This is a not followed root message', channelId: testChannelId, rootId: ''}).then(({id: postId}) => { diff --git a/webapp/channels/src/components/alert_banner.tsx b/webapp/channels/src/components/alert_banner.tsx deleted file mode 100644 index 82a0e47483a7..000000000000 --- a/webapp/channels/src/components/alert_banner.tsx +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import classNames from 'classnames'; -import React, {useCallback, useState} from 'react'; -import {useIntl} from 'react-intl'; - -import { - AlertOutlineIcon, - CheckIcon, - CloseIcon, - InformationOutlineIcon, -} from '@mattermost/compass-icons/components'; - -import OverlayTrigger from 'components/overlay_trigger'; -import Tooltip from 'components/tooltip'; - -import Constants from 'utils/constants'; - -import './alert_banner.scss'; - -export type ModeType = 'danger' | 'warning' | 'info' | 'success'; - -export type AlertBannerProps = { - id?: string; - mode: ModeType; - title?: React.ReactNode; - customIcon?: React.ReactNode; - message?: React.ReactNode; - children?: React.ReactNode; - className?: string; - hideIcon?: boolean; - actionButtonLeft?: React.ReactNode; - actionButtonRight?: React.ReactNode; - footerMessage?: React.ReactNode; - closeBtnTooltip?: React.ReactNode; - onDismiss?: () => void; - variant?: 'sys' | 'app'; -} - -const AlertBanner = ({ - id, - mode, - title, - customIcon, - message, - className, - variant = 'sys', - onDismiss, - actionButtonLeft, - actionButtonRight, - closeBtnTooltip, - footerMessage, - hideIcon, - children, -}: AlertBannerProps) => { - const {formatMessage} = useIntl(); - const closeText = formatMessage({id: 'alert_banner.tooltipCloseBtn', defaultMessage: 'Close'}); - const [tooltipId] = useState(`alert_banner_close_btn_tooltip_${Math.random()}`); - - const bannerIcon = useCallback(() => { - if (customIcon) { - return customIcon; - } - if (mode === 'danger' || mode === 'warning') { - return ( - <AlertOutlineIcon - size={24} - />); - } else if (mode === 'success') { - return ( - <CheckIcon - size={24} - />); - } - return ( - <InformationOutlineIcon - size={24} - />); - }, [mode, customIcon]); - - return ( - <div - data-testid={id} - className={classNames( - 'AlertBanner', - mode, - className, - `AlertBanner--${variant}`, - )} - > - {!hideIcon && ( - <div className='AlertBanner__icon'> - {bannerIcon()} - </div> - )} - <div className='AlertBanner__body'> - {title && <div className='AlertBanner__title'>{title}</div>} - {message && ( - <div - className={classNames({ - AlertBanner__message: Boolean(title), - })} - > - {message} - </div> - )} - {children} - {(actionButtonLeft || actionButtonRight) && ( - <div className='AlertBanner__actionButtons'> - {actionButtonLeft} - {actionButtonRight} - </div> - )} - { - footerMessage && ( - <div className='AlertBanner__footerMessage'> - {footerMessage} - </div> - ) - } - </div> - {onDismiss && ( - <OverlayTrigger - trigger={['hover', 'focus']} - delayShow={Constants.OVERLAY_TIME_DELAY} - placement='left' - overlay={closeBtnTooltip || ( - <Tooltip id={tooltipId}>{closeText}</Tooltip> - )} - > - <button - aria-label={closeText} - className='AlertBanner__closeButton' - onClick={onDismiss} - > - <CloseIcon - size={18} - /> - </button> - </OverlayTrigger> - )} - </div> - ); -}; - -export default AlertBanner; diff --git a/webapp/channels/src/components/__snapshots__/alert_banner.test.tsx.snap b/webapp/channels/src/components/alert_banner/__snapshots__/index.test.tsx.snap similarity index 100% rename from webapp/channels/src/components/__snapshots__/alert_banner.test.tsx.snap rename to webapp/channels/src/components/alert_banner/__snapshots__/index.test.tsx.snap diff --git a/webapp/channels/src/components/alert_banner.scss b/webapp/channels/src/components/alert_banner/alert_banner.scss similarity index 99% rename from webapp/channels/src/components/alert_banner.scss rename to webapp/channels/src/components/alert_banner/alert_banner.scss index 8989ce39cd3f..0113d7e89ca0 100644 --- a/webapp/channels/src/components/alert_banner.scss +++ b/webapp/channels/src/components/alert_banner/alert_banner.scss @@ -3,7 +3,6 @@ .AlertBanner { display: flex; - overflow: hidden; align-items: flex-start; padding: 14px; border: 1px solid; diff --git a/webapp/channels/src/components/alert_banner.test.tsx b/webapp/channels/src/components/alert_banner/index.test.tsx similarity index 97% rename from webapp/channels/src/components/alert_banner.test.tsx rename to webapp/channels/src/components/alert_banner/index.test.tsx index 654a0091732c..dd56cdd31706 100644 --- a/webapp/channels/src/components/alert_banner.test.tsx +++ b/webapp/channels/src/components/alert_banner/index.test.tsx @@ -4,7 +4,7 @@ import {shallow} from 'enzyme'; import React from 'react'; -import AlertBanner from './alert_banner'; +import AlertBanner from 'components/alert_banner'; describe('Components/AlertBanner', () => { test('should match snapshot', () => { diff --git a/webapp/channels/src/components/alert_banner/index.tsx b/webapp/channels/src/components/alert_banner/index.tsx new file mode 100644 index 000000000000..a399f5c53e08 --- /dev/null +++ b/webapp/channels/src/components/alert_banner/index.tsx @@ -0,0 +1,139 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import classNames from 'classnames'; +import type {ReactNode} from 'react'; +import React, {useMemo} from 'react'; +import {useIntl} from 'react-intl'; + +import { + AlertOutlineIcon, + CheckIcon, + CloseIcon, + InformationOutlineIcon, +} from '@mattermost/compass-icons/components'; + +import WithTooltip from 'components/with_tooltip'; + +import './alert_banner.scss'; + +export type ModeType = 'danger' | 'warning' | 'info' | 'success'; + +export type AlertBannerProps = { + id?: string; + mode: ModeType; + title?: ReactNode; + customIcon?: ReactNode; + message?: ReactNode; + children?: ReactNode; + className?: string; + hideIcon?: boolean; + actionButtonLeft?: ReactNode; + actionButtonRight?: ReactNode; + footerMessage?: ReactNode; + closeBtnTooltip?: string; + onDismiss?: () => void; + variant?: 'sys' | 'app'; +} + +const AlertBanner = ({ + id, + mode, + title, + customIcon, + message, + className, + variant = 'sys', + onDismiss, + actionButtonLeft, + actionButtonRight, + closeBtnTooltip, + footerMessage, + hideIcon, + children, +}: AlertBannerProps) => { + const {formatMessage} = useIntl(); + + const bannerIcon = useMemo(() => { + if (customIcon) { + return customIcon; + } + + if (mode === 'danger' || mode === 'warning') { + return <AlertOutlineIcon size={24}/>; + } else if (mode === 'success') { + return <CheckIcon size={24}/>; + } + return <InformationOutlineIcon size={24}/>; + }, [mode, customIcon]); + + const dismissButton = useMemo(() => { + return ( + <button + className='AlertBanner__closeButton' + aria-label={formatMessage({id: 'alert_banner.tooltipCloseBtn', defaultMessage: 'Close'})} + onClick={onDismiss} + > + <CloseIcon size={18}/> + </button> + ); + }, [onDismiss]); + + return ( + <div + data-testid={id} + className={classNames( + 'AlertBanner', + mode, + className, + `AlertBanner--${variant}`, + )} + > + {!hideIcon && ( + <div className='AlertBanner__icon'> + {bannerIcon} + </div> + )} + <div className='AlertBanner__body'> + {title && + <div className='AlertBanner__title'> + {title} + </div> + } + {message && ( + <div + className={classNames({AlertBanner__message: Boolean(title)})} + > + {message} + </div> + )} + {children} + {(actionButtonLeft || actionButtonRight) && ( + <div className='AlertBanner__actionButtons'> + {actionButtonLeft} + {actionButtonRight} + </div> + )} + {footerMessage && ( + <div className='AlertBanner__footerMessage'> + {footerMessage} + </div> + )} + </div> + {onDismiss && closeBtnTooltip && ( + <WithTooltip + id={`alertBannerTooltip_${id}`} + title={closeBtnTooltip} + placement='left' + > + {dismissButton} + </WithTooltip> + )} + {onDismiss && !closeBtnTooltip && ( + dismissButton + )} + </div> + ); +}; + +export default AlertBanner; diff --git a/webapp/channels/src/components/channel_notifications_modal/__snapshots__/channel_notifications_modal.test.tsx.snap b/webapp/channels/src/components/channel_notifications_modal/__snapshots__/channel_notifications_modal.test.tsx.snap index d00414fa8de4..0b27528c3983 100644 --- a/webapp/channels/src/components/channel_notifications_modal/__snapshots__/channel_notifications_modal.test.tsx.snap +++ b/webapp/channels/src/components/channel_notifications_modal/__snapshots__/channel_notifications_modal.test.tsx.snap @@ -52,20 +52,11 @@ Object { class="mm-modal-header__ctr" > <button - class="style--none mm-modal-header__close-btn" + class="btn btn-icon" > - <svg - fill="currentcolor" - height="24" - version="1.1" - viewBox="0 0 24 24" - width="24" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" - /> - </svg> + <i + class="icon icon-close" + /> </button> </div> </header> @@ -76,16 +67,16 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > <h4 - class="mm-modal-generic-section__title" + class="modalSectionTitle" > Mute or ignore </h4> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -108,14 +99,13 @@ Object { /> Mute channel </label> - <br /> </fieldset> </div> <p class="mm-modal-generic-section-item__description" data-testid="mm-modal-generic-section-item__description" > - Turns off notifications for this channel. You’ll still see badges if you’re mentioned. + Turns off notifications for this channel. You'll still see badges if you're mentioned. </p> </div> <div @@ -139,7 +129,6 @@ Object { /> Ignore mentions for @channel, @here and @all </label> - <br /> </fieldset> </div> <p @@ -158,25 +147,21 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Desktop Notifications - </h4> - </div> + Desktop Notifications + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Available on Chrome, Edge, Firefox, and the Mattermost Desktop App. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -244,16 +229,12 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Mobile Notifications - </h4> + Mobile Notifications <button class="channel-notifications-settings-modal__reset-btn" > @@ -271,15 +252,15 @@ Object { </svg> Reset to default </button> - </div> + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Notification alerts are pushed to your mobile device when there is activity in Mattermost. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -302,7 +283,6 @@ Object { /> Use the same notification settings as desktop </label> - <br /> </fieldset> </div> </div> @@ -370,12 +350,12 @@ Object { > <button - class="channel-notifications-settings-modal__cancel-btn" + class="btn btn-tertiary btn-md" > Cancel </button> <button - class="channel-notifications-settings-modal__save-btn" + class="btn btn-primary btn-md" > Save </button> @@ -496,20 +476,11 @@ Object { class="mm-modal-header__ctr" > <button - class="style--none mm-modal-header__close-btn" + class="btn btn-icon" > - <svg - fill="currentcolor" - height="24" - version="1.1" - viewBox="0 0 24 24" - width="24" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" - /> - </svg> + <i + class="icon icon-close" + /> </button> </div> </header> @@ -520,16 +491,16 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > <h4 - class="mm-modal-generic-section__title" + class="modalSectionTitle" > Mute or ignore </h4> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -552,14 +523,13 @@ Object { /> Mute channel </label> - <br /> </fieldset> </div> <p class="mm-modal-generic-section-item__description" data-testid="mm-modal-generic-section-item__description" > - Turns off notifications for this channel. You’ll still see badges if you’re mentioned. + Turns off notifications for this channel. You'll still see badges if you're mentioned. </p> </div> <div @@ -583,7 +553,6 @@ Object { /> Ignore mentions for @channel, @here and @all </label> - <br /> </fieldset> </div> <p @@ -602,16 +571,12 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Desktop Notifications - </h4> + Desktop Notifications <button class="channel-notifications-settings-modal__reset-btn" > @@ -629,15 +594,15 @@ Object { </svg> Reset to default </button> - </div> + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Available on Chrome, Edge, Firefox, and the Mattermost Desktop App. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -705,16 +670,12 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Mobile Notifications - </h4> + Mobile Notifications <button class="channel-notifications-settings-modal__reset-btn" > @@ -732,15 +693,15 @@ Object { </svg> Reset to default </button> - </div> + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Notification alerts are pushed to your mobile device when there is activity in Mattermost. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -763,7 +724,6 @@ Object { /> Use the same notification settings as desktop </label> - <br /> </fieldset> </div> </div> @@ -831,12 +791,12 @@ Object { > <button - class="channel-notifications-settings-modal__cancel-btn" + class="btn btn-tertiary btn-md" > Cancel </button> <button - class="channel-notifications-settings-modal__save-btn" + class="btn btn-primary btn-md" > Save </button> @@ -957,20 +917,11 @@ Object { class="mm-modal-header__ctr" > <button - class="style--none mm-modal-header__close-btn" + class="btn btn-icon" > - <svg - fill="currentcolor" - height="24" - version="1.1" - viewBox="0 0 24 24" - width="24" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" - /> - </svg> + <i + class="icon icon-close" + /> </button> </div> </header> @@ -981,16 +932,16 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > <h4 - class="mm-modal-generic-section__title" + class="modalSectionTitle" > Mute or ignore </h4> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -1013,14 +964,13 @@ Object { /> Mute channel </label> - <br /> </fieldset> </div> <p class="mm-modal-generic-section-item__description" data-testid="mm-modal-generic-section-item__description" > - Turns off notifications for this channel. You’ll still see badges if you’re mentioned. + Turns off notifications for this channel. You'll still see badges if you're mentioned. </p> </div> <div @@ -1044,7 +994,6 @@ Object { /> Ignore mentions for @channel, @here and @all </label> - <br /> </fieldset> </div> <p @@ -1063,25 +1012,21 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Desktop Notifications - </h4> - </div> + Desktop Notifications + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Available on Chrome, Edge, Firefox, and the Mattermost Desktop App. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -1149,16 +1094,12 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Mobile Notifications - </h4> + Mobile Notifications <button class="channel-notifications-settings-modal__reset-btn" > @@ -1176,15 +1117,15 @@ Object { </svg> Reset to default </button> - </div> + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Notification alerts are pushed to your mobile device when there is activity in Mattermost. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -1207,7 +1148,6 @@ Object { /> Use the same notification settings as desktop </label> - <br /> </fieldset> </div> </div> @@ -1275,12 +1215,12 @@ Object { > <button - class="channel-notifications-settings-modal__cancel-btn" + class="btn btn-tertiary btn-md" > Cancel </button> <button - class="channel-notifications-settings-modal__save-btn" + class="btn btn-primary btn-md" > Save </button> @@ -1401,20 +1341,11 @@ Object { class="mm-modal-header__ctr" > <button - class="style--none mm-modal-header__close-btn" + class="btn btn-icon" > - <svg - fill="currentcolor" - height="24" - version="1.1" - viewBox="0 0 24 24" - width="24" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" - /> - </svg> + <i + class="icon icon-close" + /> </button> </div> </header> @@ -1425,16 +1356,16 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > <h4 - class="mm-modal-generic-section__title" + class="modalSectionTitle" > Mute or ignore </h4> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -1457,14 +1388,13 @@ Object { /> Mute channel </label> - <br /> </fieldset> </div> <p class="mm-modal-generic-section-item__description" data-testid="mm-modal-generic-section-item__description" > - Turns off notifications for this channel. You’ll still see badges if you’re mentioned. + Turns off notifications for this channel. You'll still see badges if you're mentioned. </p> </div> <div @@ -1488,7 +1418,6 @@ Object { /> Ignore mentions for @channel, @here and @all </label> - <br /> </fieldset> </div> <p @@ -1502,6 +1431,7 @@ Object { </section> <div class="AlertBanner info AlertBanner--app" + data-testid="channelNotificationsMutedBanner" > <div class="AlertBanner__icon" @@ -1540,12 +1470,12 @@ Object { > <button - class="channel-notifications-settings-modal__cancel-btn" + class="btn btn-tertiary btn-md" > Cancel </button> <button - class="channel-notifications-settings-modal__save-btn" + class="btn btn-primary btn-md" > Save </button> @@ -1666,20 +1596,11 @@ Object { class="mm-modal-header__ctr" > <button - class="style--none mm-modal-header__close-btn" + class="btn btn-icon" > - <svg - fill="currentcolor" - height="24" - version="1.1" - viewBox="0 0 24 24" - width="24" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" - /> - </svg> + <i + class="icon icon-close" + /> </button> </div> </header> @@ -1690,16 +1611,16 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > <h4 - class="mm-modal-generic-section__title" + class="modalSectionTitle" > Mute or ignore </h4> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -1722,14 +1643,13 @@ Object { /> Mute channel </label> - <br /> </fieldset> </div> <p class="mm-modal-generic-section-item__description" data-testid="mm-modal-generic-section-item__description" > - Turns off notifications for this channel. You’ll still see badges if you’re mentioned. + Turns off notifications for this channel. You'll still see badges if you're mentioned. </p> </div> <div @@ -1753,7 +1673,6 @@ Object { /> Ignore mentions for @channel, @here and @all </label> - <br /> </fieldset> </div> <p @@ -1772,25 +1691,21 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Desktop Notifications - </h4> - </div> + Desktop Notifications + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Available on Chrome, Edge, Firefox, and the Mattermost Desktop App. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -1858,16 +1773,12 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Mobile Notifications - </h4> + Mobile Notifications <button class="channel-notifications-settings-modal__reset-btn" > @@ -1885,15 +1796,15 @@ Object { </svg> Reset to default </button> - </div> + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Notification alerts are pushed to your mobile device when there is activity in Mattermost. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -1916,7 +1827,6 @@ Object { /> Use the same notification settings as desktop </label> - <br /> </fieldset> </div> </div> @@ -1928,12 +1838,12 @@ Object { > <button - class="channel-notifications-settings-modal__cancel-btn" + class="btn btn-tertiary btn-md" > Cancel </button> <button - class="channel-notifications-settings-modal__save-btn" + class="btn btn-primary btn-md" > Save </button> @@ -2054,20 +1964,11 @@ Object { class="mm-modal-header__ctr" > <button - class="style--none mm-modal-header__close-btn" + class="btn btn-icon" > - <svg - fill="currentcolor" - height="24" - version="1.1" - viewBox="0 0 24 24" - width="24" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" - /> - </svg> + <i + class="icon icon-close" + /> </button> </div> </header> @@ -2078,16 +1979,16 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > <h4 - class="mm-modal-generic-section__title" + class="modalSectionTitle" > Mute or ignore </h4> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -2110,14 +2011,13 @@ Object { /> Mute channel </label> - <br /> </fieldset> </div> <p class="mm-modal-generic-section-item__description" data-testid="mm-modal-generic-section-item__description" > - Turns off notifications for this channel. You’ll still see badges if you’re mentioned. + Turns off notifications for this channel. You'll still see badges if you're mentioned. </p> </div> <div @@ -2141,7 +2041,6 @@ Object { /> Ignore mentions for @channel, @here and @all </label> - <br /> </fieldset> </div> <p @@ -2160,25 +2059,21 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Desktop Notifications - </h4> - </div> + Desktop Notifications + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Available on Chrome, Edge, Firefox, and the Mattermost Desktop App. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -2246,16 +2141,12 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > - <div - class="mm-modal-generic-section__row" + <h4 + class="modalSectionTitle" > - <h4 - class="mm-modal-generic-section__title" - > - Mobile Notifications - </h4> + Mobile Notifications <button class="channel-notifications-settings-modal__reset-btn" > @@ -2273,15 +2164,15 @@ Object { </svg> Reset to default </button> - </div> + </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > Notification alerts are pushed to your mobile device when there is activity in Mattermost. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -2304,7 +2195,6 @@ Object { /> Use the same notification settings as desktop </label> - <br /> </fieldset> </div> </div> @@ -2373,21 +2263,21 @@ Object { class="mm-modal-generic-section" > <div - class="mm-modal-generic-section__title-description-ctr" + class="modalSectionHeader" > <h4 - class="mm-modal-generic-section__title" + class="modalSectionTitle" > Follow all threads in this channel </h4> <p - class="mm-modal-generic-section__description" + class="modalSectionDescription" > When enabled, all new replies in this channel will be automatically followed and will appear in your Threads view. </p> </div> <div - class="mm-modal-generic-section__content" + class="modalSectionContent" > <div class="mm-modal-generic-section-item" @@ -2410,7 +2300,6 @@ Object { /> Automatically follow threads in this channel </label> - <br /> </fieldset> </div> </div> @@ -2422,12 +2311,12 @@ Object { > <button - class="channel-notifications-settings-modal__cancel-btn" + class="btn btn-tertiary btn-md" > Cancel </button> <button - class="channel-notifications-settings-modal__save-btn" + class="btn btn-primary btn-md" > Save </button> diff --git a/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.scss b/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.scss index 84d87c5990c1..ee01847fc267 100644 --- a/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.scss +++ b/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.scss @@ -31,7 +31,7 @@ max-width: 1024px; min-height: 150px; flex-direction: column; - padding: 32px; + padding: 28px 32px; gap: 24px; overflow-x: hidden; overflow-y: auto; @@ -72,48 +72,6 @@ color: var(--error-text); } - &__save-btn { - padding: 12px 20px 12px 20px; - border: none; - border-radius: 4px; - background: var(--button-bg); - color: var(--button-color); - font-size: 14px; - font-weight: 600; - line-height: 14px; - text-transform: capitalize; - - &:hover, - &:active { - background: rgba(var(--button-bg-rgb), 0.12); - background: linear-gradient(0deg, rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.08)), var(--button-bg); - } - - &:focus { - box-sizing: border-box; - padding: 10px 18px; - border: 2px solid var(--sidebar-text-active-border); - box-shadow: none; - } - } - - &__cancel-btn { - padding: 12px 20px 12px 20px; - border: none; - border-radius: 4px; - background: rgba(var(--button-bg-rgb), 0.08); - color: var(--button-bg); - font-size: 14px; - font-weight: 600; - line-height: 14px; - text-transform: capitalize; - - &:hover, - &:active { - background: rgba(var(--button-bg-rgb), 0.12); - } - } - &__divider { border-bottom: 1px solid rgba(var(--center-channel-color-rgb), 0.08); } diff --git a/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.tsx b/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.tsx index 38f52bda616a..1c12e76c5cb0 100644 --- a/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.tsx +++ b/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.tsx @@ -43,10 +43,8 @@ type Props = PropsFromRedux & { }; function getUseSameDesktopSetting(currentUserNotifyProps: UserNotifyProps, channelMemberNotifyProps?: ChannelMemberNotifyProps) { - const isSameAsDesktop = channelMemberNotifyProps ? channelMemberNotifyProps?.desktop === channelMemberNotifyProps?.push : - currentUserNotifyProps.push === currentUserNotifyProps.desktop; - const isSameAsDesktopThreads = channelMemberNotifyProps ? channelMemberNotifyProps?.desktop_threads === channelMemberNotifyProps?.push_threads : - currentUserNotifyProps.push_threads === currentUserNotifyProps.desktop_threads; + const isSameAsDesktop = channelMemberNotifyProps ? channelMemberNotifyProps?.desktop === channelMemberNotifyProps?.push : currentUserNotifyProps.push === currentUserNotifyProps.desktop; + const isSameAsDesktopThreads = channelMemberNotifyProps ? channelMemberNotifyProps?.desktop_threads === channelMemberNotifyProps?.push_threads : currentUserNotifyProps.push_threads === currentUserNotifyProps.desktop_threads; return isSameAsDesktop && isSameAsDesktopThreads; } @@ -106,16 +104,34 @@ export default function ChannelNotificationsModal(props: Props) { setSettings((prevSettings) => ({...prevSettings, push: prevSettings.desktop, push_threads: prevSettings.desktop_threads})); }, []); - const MuteIgnoreSectionContent = ( + const MuteOrIgnoreSectionContent = ( <> <CheckboxSettingItem - description={utils.MuteChannelDesc} + inputFieldTitle={ + <FormattedMessage + id='channel_notifications.muteChannelTitle' + defaultMessage='Mute channel' + /> + } + description={formatMessage({ + id: 'channel_notifications.muteChannelDesc', + defaultMessage: 'Turns off notifications for this channel. You\'ll still see badges if you\'re mentioned.', + })} inputFieldValue={settings.mark_unread === 'mention'} inputFieldData={utils.MuteChannelInputFieldData} handleChange={(e) => handleChange({mark_unread: e ? 'mention' : 'all'})} /> <CheckboxSettingItem - description={utils.IgnoreMentionsDesc} + inputFieldTitle={ + <FormattedMessage + id='channel_notifications.ignoreMentionsTitle' + defaultMessage='Ignore mentions for @channel, @here and @all' + /> + } + description={formatMessage({ + id: 'channel_notifications.ignoreMentionsDesc', + defaultMessage: 'When enabled, @channel, @here and @all will not trigger mentions or mention notifications in this channel', + })} inputFieldValue={settings.ignore_channel_mentions === 'on'} inputFieldData={utils.IgnoreMentionsInputFieldData} handleChange={(e) => handleChange({ignore_channel_mentions: e ? 'on' : 'off'})} @@ -126,16 +142,28 @@ export default function ChannelNotificationsModal(props: Props) { const DesktopNotificationsSectionContent = ( <> <RadioSettingItem - title={utils.NotifyMeTitle} + title={formatMessage({ + id: 'channel_notifications.NotifyMeTitle', + defaultMessage: 'Notify me about…', + })} inputFieldValue={settings.desktop} inputFieldData={utils.desktopNotificationInputFieldData(props.currentUser.notify_props.desktop)} handleChange={(e) => handleChange({desktop: e.target.value})} /> {props.collapsedReplyThreads && settings.desktop === 'mention' && <CheckboxSettingItem - title={utils.ThreadsReplyTitle} + title={formatMessage({ + id: 'channel_notifications.ThreadsReplyTitle', + defaultMessage: 'Thread reply notifications', + })} inputFieldValue={settings.desktop_threads === 'all'} inputFieldData={utils.DesktopReplyThreadsInputFieldData} + inputFieldTitle={ + <FormattedMessage + id='channel_notifications.checkbox.threadsReplyTitle' + defaultMessage="Notify me about replies to threads I\'m following" + /> + } handleChange={(e) => handleChange({desktop_threads: e ? 'all' : 'mention'})} />} </> @@ -144,6 +172,12 @@ export default function ChannelNotificationsModal(props: Props) { const MobileNotificationsSectionContent = ( <> <CheckboxSettingItem + inputFieldTitle={ + <FormattedMessage + id='channel_notifications.checkbox.sameMobileSettingsDesktop' + defaultMessage='Use the same notification settings as desktop' + /> + } inputFieldValue={mobileSettingsSameAsDesktop} inputFieldData={utils.sameMobileSettingsDesktopInputFieldData} handleChange={() => handleMobileSettingsChange()} @@ -151,14 +185,26 @@ export default function ChannelNotificationsModal(props: Props) { {!mobileSettingsSameAsDesktop && ( <> <RadioSettingItem - title={utils.NotifyMeTitle} + title={formatMessage({ + id: 'channel_notifications.NotifyMeTitle', + defaultMessage: 'Notify me about…', + })} inputFieldValue={settings.push} inputFieldData={utils.mobileNotificationInputFieldData(props.currentUser.notify_props.push)} handleChange={(e) => handleChange({push: e.target.value})} /> {props.collapsedReplyThreads && settings.push === 'mention' && <CheckboxSettingItem - title={utils.ThreadsReplyTitle} + title={formatMessage({ + id: 'channel_notifications.ThreadsReplyTitle', + defaultMessage: 'Thread reply notifications', + })} + inputFieldTitle={ + <FormattedMessage + id='channel_notifications.checkbox.threadsReplyTitle' + defaultMessage="Notify me about replies to threads I\'m following" + /> + } inputFieldValue={settings.push_threads === 'all'} inputFieldData={utils.MobileReplyThreadsInputFieldData} handleChange={(e) => handleChange({push_threads: e ? 'all' : 'mention'})} @@ -169,13 +215,17 @@ export default function ChannelNotificationsModal(props: Props) { ); const AutoFollowThreadsSectionContent = ( - <> - <CheckboxSettingItem - inputFieldValue={settings.channel_auto_follow_threads === 'on'} - inputFieldData={utils.AutoFollowThreadsInputFieldData} - handleChange={(e) => handleChange({channel_auto_follow_threads: e ? 'on' : 'off'})} - /> - </> + <CheckboxSettingItem + inputFieldTitle={ + <FormattedMessage + id='channel_notifications.checkbox.autoFollowThreadsTitle' + defaultMessage='Automatically follow threads in this channel' + /> + } + inputFieldValue={settings.channel_auto_follow_threads === 'on'} + inputFieldData={utils.AutoFollowThreadsInputFieldData} + handleChange={(e) => handleChange({channel_auto_follow_threads: e ? 'on' : 'off'})} + /> ); function handleSave() { @@ -229,25 +279,38 @@ export default function ChannelNotificationsModal(props: Props) { ); }, [props.currentUser, settings]); - const settingsAndAlertBanner = settings.mark_unread === 'all' ? ( + const desktopAndMobileNotificationSectionContent = settings.mark_unread === 'all' ? ( <> <div className='channel-notifications-settings-modal__divider'/> <ModalSection - title={utils.DesktopNotificationsSectionTitle} - description={utils.DesktopNotificationsSectionDesc} - content={DesktopNotificationsSectionContent} + title={formatMessage({ + id: 'channel_notifications.desktopNotificationsTitle', + defaultMessage: 'Desktop Notifications', + })} titleSuffix={resetToDefaultBtn('desktop')} + description={formatMessage({ + id: 'channel_notifications.desktopNotificationsDesc', + defaultMessage: 'Available on Chrome, Edge, Firefox, and the Mattermost Desktop App.', + })} + content={DesktopNotificationsSectionContent} /> <div className='channel-notifications-settings-modal__divider'/> <ModalSection - title={utils.MobileNotificationsSectionTitle} - description={utils.MobileNotificationsSectionDesc} - content={MobileNotificationsSectionContent} + title={formatMessage({ + id: 'channel_notifications.mobileNotificationsTitle', + defaultMessage: 'Mobile Notifications', + })} titleSuffix={resetToDefaultBtn('push')} + description={formatMessage({ + id: 'channel_notifications.mobileNotificationsDesc', + defaultMessage: 'Notification alerts are pushed to your mobile device when there is activity in Mattermost.', + })} + content={MobileNotificationsSectionContent} /> </> ) : ( <AlertBanner + id='channelNotificationsMutedBanner' mode='info' variant='app' customIcon={ @@ -292,16 +355,25 @@ export default function ChannelNotificationsModal(props: Props) { /> <main className='channel-notifications-settings-modal__body'> <ModalSection - title={utils.MuteAndIgnoreSectionTitle} - content={MuteIgnoreSectionContent} + title={formatMessage({ + id: 'channel_notifications.muteAndIgnore', + defaultMessage: 'Mute or ignore', + })} + content={MuteOrIgnoreSectionContent} /> - {settingsAndAlertBanner} + {desktopAndMobileNotificationSectionContent} {props.collapsedReplyThreads && <> <div className='channel-notifications-settings-modal__divider'/> <ModalSection - title={utils.AutoFollowThreadsTitle} - description={utils.AutoFollowThreadsDesc} + title={formatMessage({ + id: 'channel_notifications.autoFollowThreadsTitle', + defaultMessage: 'Follow all threads in this channel', + })} + description={formatMessage({ + id: 'channel_notifications.autoFollowThreadsDesc', + defaultMessage: 'When enabled, all new replies in this channel will be automatically followed and will appear in your Threads view.', + })} content={AutoFollowThreadsSectionContent} /> </> @@ -314,8 +386,8 @@ export default function ChannelNotificationsModal(props: Props) { </span> } <button + className='btn btn-tertiary btn-md' onClick={handleHide} - className='channel-notifications-settings-modal__cancel-btn' > <FormattedMessage id='generic_btn.cancel' @@ -323,7 +395,7 @@ export default function ChannelNotificationsModal(props: Props) { /> </button> <button - className={'channel-notifications-settings-modal__save-btn'} + className='btn btn-primary btn-md' onClick={handleSave} > <FormattedMessage diff --git a/webapp/channels/src/components/channel_notifications_modal/utils.tsx b/webapp/channels/src/components/channel_notifications_modal/utils.tsx index dd90e455df7a..96ec724e2f34 100644 --- a/webapp/channels/src/components/channel_notifications_modal/utils.tsx +++ b/webapp/channels/src/components/channel_notifications_modal/utils.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react'; -import {FormattedMessage, defineMessages} from 'react-intl'; +import {FormattedMessage} from 'react-intl'; import type {ChannelNotifyProps} from '@mattermost/types/channels'; import type {UserNotifyProps} from '@mattermost/types/users'; @@ -14,163 +14,47 @@ import {NotificationLevels} from 'utils/constants'; export type ChannelMemberNotifyProps = Partial<ChannelNotifyProps> & Pick<UserNotifyProps, 'desktop_threads' | 'push_threads'> -const translations = defineMessages({ - MuteAndIgnoreSectionTitle: { - id: 'channel_notifications.muteAndIgnore', - defaultMessage: 'Mute or ignore', - }, - NotifyMeTitle: { - id: 'channel_notifications.NotifyMeTitle', - defaultMessage: 'Notify me about…', - }, - ThreadsReplyTitle: { - id: 'channel_notifications.ThreadsReplyTitle', - defaultMessage: 'Thread reply notifications', - }, - - DesktopNotificationsSectionTitle: { - id: 'channel_notifications.desktopNotificationsTitle', - defaultMessage: 'Desktop Notifications', - }, - - DesktopNotificationsSectionDesc: { - id: 'channel_notifications.desktopNotificationsDesc', - defaultMessage: 'Available on Chrome, Edge, Firefox, and the Mattermost Desktop App.', - }, - - MobileNotificationsSectionTitle: { - id: 'channel_notifications.mobileNotificationsTitle', - defaultMessage: 'Mobile Notifications', - }, - - MobileNotificationsSectionDesc: { - id: 'channel_notifications.mobileNotificationsDesc', - defaultMessage: 'Notification alerts are pushed to your mobile device when there is activity in Mattermost.', - }, - - MuteChannelDesc: { - id: 'channel_notifications.muteChannelDesc', - defaultMessage: 'Turns off notifications for this channel. You’ll still see badges if you’re mentioned.', - }, - - IgnoreMentionsDesc: { - id: 'channel_notifications.ignoreMentionsDesc', - defaultMessage: 'When enabled, @channel, @here and @all will not trigger mentions or mention notifications in this channel', - }, - - MuteChannelInputFieldTitle: { - id: 'channel_notifications.muteChannelTitle', - defaultMessage: 'Mute channel', - }, - - DesktopReplyThreadsInputFieldTitle: { - id: 'channel_notifications.checkbox.threadsReplyTitle', - defaultMessage: 'Notify me about replies to threads I\'m following', - }, - - MobileReplyThreadsInputFieldTitle: { - id: 'channel_notifications.checkbox.threadsReplyTitle', - defaultMessage: 'Notify me about replies to threads I\'m following', - }, - - sameMobileSettingsDesktopInputFieldTitle: { - id: 'channel_notifications.checkbox.sameMobileSettingsDesktop', - defaultMessage: 'Use the same notification settings as desktop', - }, - - IgnoreMentionsInputFieldTitle: { - id: 'channel_notifications.ignoreMentionsTitle', - defaultMessage: 'Ignore mentions for @channel, @here and @all', - }, - - AutoFollowThreadsTitle: { - id: 'channel_notifications.autoFollowThreadsTitle', - defaultMessage: 'Follow all threads in this channel', - }, - - AutoFollowThreadsDesc: { - id: 'channel_notifications.autoFollowThreadsDesc', - defaultMessage: 'When enabled, all new replies in this channel will be automatically followed and will appear in your Threads view.', - }, - - AutoFollowThreadsInputFieldTitle: { - id: 'channel_notifications.checkbox.autoFollowThreadsTitle', - defaultMessage: 'Automatically follow threads in this channel', - }, -}); - -const desktopNotificationInputFieldOptions = defineMessages({ - allNewMessages: { - id: 'channel_notifications.desktopNotificationAllLabel', - defaultMessage: 'All new messages', - }, - mentions: { - id: 'channel_notifications.desktopNotificationMentionLabel', - defaultMessage: 'Mentions, direct messages, and keywords only', - }, - nothing: { - id: 'channel_notifications.desktopNotificationNothingLabel', - defaultMessage: 'Nothing', - }, -}); - -const mobileNotificationInputFieldOptions = defineMessages({ - allNewMessages: { - id: 'channel_notifications.MobileNotificationAllLabel', - defaultMessage: 'All new messages', - }, - mentions: { - id: 'channel_notifications.MobileNotificationMentionLabel', - defaultMessage: 'Mentions, direct messages, and keywords only', - }, - nothing: { - id: 'channel_notifications.MobileNotificationNothingLabel', - defaultMessage: 'Nothing', - }, -}); - const MuteChannelInputFieldData: FieldsetCheckbox = { - title: translations.MuteChannelInputFieldTitle, name: 'mute channel', dataTestId: 'muteChannel', }; const DesktopReplyThreadsInputFieldData: FieldsetCheckbox = { - title: translations.DesktopReplyThreadsInputFieldTitle, name: 'desktop reply threads', dataTestId: 'desktopReplyThreads', }; const MobileReplyThreadsInputFieldData: FieldsetCheckbox = { - title: translations.MobileReplyThreadsInputFieldTitle, name: 'mobile reply threads', dataTestId: 'mobileReplyThreads', }; -const sameMobileSettingsDesktopInputFieldData: FieldsetCheckbox = { - title: translations.sameMobileSettingsDesktopInputFieldTitle, +export const sameMobileSettingsDesktopInputFieldData: FieldsetCheckbox = { name: 'same mobile settings as Desktop', dataTestId: 'sameMobileSettingsDesktop', }; -const IgnoreMentionsInputFieldData: FieldsetCheckbox = { - title: translations.IgnoreMentionsInputFieldTitle, +export const IgnoreMentionsInputFieldData: FieldsetCheckbox = { name: 'ignore mentions', dataTestId: 'ignoreMentions', }; -const AutoFollowThreadsInputFieldData: FieldsetCheckbox = { - title: translations.AutoFollowThreadsInputFieldTitle, +export const AutoFollowThreadsInputFieldData: FieldsetCheckbox = { name: 'auto follow threads', dataTestId: 'autoFollowThreads', }; -const desktopNotificationInputFieldData = (defaultOption: string): FieldsetRadio => { +export const desktopNotificationInputFieldData = (defaultOption: string): FieldsetRadio => { return { options: [ { dataTestId: `desktopNotification-${NotificationLevels.ALL}`, - title: desktopNotificationInputFieldOptions.allNewMessages, + title: ( + <FormattedMessage + id='channel_notifications.desktopNotificationAllLabel' + defaultMessage='All new messages' + /> + ), name: `desktopNotification-${NotificationLevels.ALL}`, key: `desktopNotification-${NotificationLevels.ALL}`, value: NotificationLevels.ALL, @@ -182,7 +66,12 @@ const desktopNotificationInputFieldData = (defaultOption: string): FieldsetRadio }, { dataTestId: `desktopNotification-${NotificationLevels.MENTION}`, - title: desktopNotificationInputFieldOptions.mentions, + title: ( + <FormattedMessage + id='channel_notifications.desktopNotificationMentionLabel' + defaultMessage='Mentions, direct messages, and keywords only' + /> + ), name: `desktopNotification-${NotificationLevels.MENTION}`, key: `desktopNotification-${NotificationLevels.MENTION}`, value: NotificationLevels.MENTION, @@ -194,7 +83,12 @@ const desktopNotificationInputFieldData = (defaultOption: string): FieldsetRadio }, { dataTestId: `desktopNotification-${NotificationLevels.NONE}`, - title: desktopNotificationInputFieldOptions.nothing, + title: ( + <FormattedMessage + id='channel_notifications.desktopNotificationNothingLabel' + defaultMessage='Nothing' + /> + ), name: `desktopNotification-${NotificationLevels.NONE}`, key: `desktopNotification-${NotificationLevels.NONE}`, value: NotificationLevels.NONE, @@ -208,12 +102,17 @@ const desktopNotificationInputFieldData = (defaultOption: string): FieldsetRadio }; }; -const mobileNotificationInputFieldData = (defaultOption: string): FieldsetRadio => { +export const mobileNotificationInputFieldData = (defaultOption: string): FieldsetRadio => { return { options: [ { dataTestId: `MobileNotification-${NotificationLevels.ALL}`, - title: mobileNotificationInputFieldOptions.allNewMessages, + title: ( + <FormattedMessage + id='channel_notifications.MobileNotificationAllLabel' + defaultMessage='All new messages' + /> + ), name: `MobileNotification-${NotificationLevels.ALL}`, key: `MobileNotification-${NotificationLevels.ALL}`, value: NotificationLevels.ALL, @@ -225,7 +124,12 @@ const mobileNotificationInputFieldData = (defaultOption: string): FieldsetRadio }, { dataTestId: `MobileNotification-${NotificationLevels.MENTION}`, - title: mobileNotificationInputFieldOptions.mentions, + title: ( + <FormattedMessage + id='channel_notifications.MobileNotificationMentionLabel' + defaultMessage='Mentions, direct messages, and keywords only' + /> + ), name: `MobileNotification-${NotificationLevels.MENTION}`, key: `MobileNotification-${NotificationLevels.MENTION}`, value: NotificationLevels.MENTION, @@ -237,7 +141,12 @@ const mobileNotificationInputFieldData = (defaultOption: string): FieldsetRadio }, { dataTestId: `MobileNotification-${NotificationLevels.NONE}`, - title: mobileNotificationInputFieldOptions.nothing, + title: ( + <FormattedMessage + id='channel_notifications.MobileNotificationNothingLabel' + defaultMessage='Nothing' + /> + ), name: `MobileNotification-${NotificationLevels.NONE}`, key: `MobileNotification-${NotificationLevels.NONE}`, value: NotificationLevels.NONE, @@ -253,22 +162,11 @@ const mobileNotificationInputFieldData = (defaultOption: string): FieldsetRadio const utils = { desktopNotificationInputFieldData, - DesktopNotificationsSectionDesc: translations.DesktopNotificationsSectionDesc, - DesktopNotificationsSectionTitle: translations.DesktopNotificationsSectionTitle, - IgnoreMentionsDesc: translations.IgnoreMentionsDesc, IgnoreMentionsInputFieldData, mobileNotificationInputFieldData, - MobileNotificationsSectionDesc: translations.MobileNotificationsSectionDesc, - MobileNotificationsSectionTitle: translations.MobileNotificationsSectionTitle, - MuteAndIgnoreSectionTitle: translations.MuteAndIgnoreSectionTitle, - MuteChannelDesc: translations.MuteChannelDesc, MuteChannelInputFieldData, - NotifyMeTitle: translations.NotifyMeTitle, DesktopReplyThreadsInputFieldData, - ThreadsReplyTitle: translations.ThreadsReplyTitle, MobileReplyThreadsInputFieldData, - AutoFollowThreadsTitle: translations.AutoFollowThreadsTitle, - AutoFollowThreadsDesc: translations.AutoFollowThreadsDesc, AutoFollowThreadsInputFieldData, sameMobileSettingsDesktopInputFieldData, }; diff --git a/webapp/channels/src/components/file_limit_sticky_banner/index.tsx b/webapp/channels/src/components/file_limit_sticky_banner/index.tsx index 048dd762fd27..599b561e25b3 100644 --- a/webapp/channels/src/components/file_limit_sticky_banner/index.tsx +++ b/webapp/channels/src/components/file_limit_sticky_banner/index.tsx @@ -16,7 +16,6 @@ import useGetLimits from 'components/common/hooks/useGetLimits'; import useGetUsage from 'components/common/hooks/useGetUsage'; import useOpenPricingModal from 'components/common/hooks/useOpenPricingModal'; import NotifyAdminCTA from 'components/notify_admin_cta/notify_admin_cta'; -import Tooltip from 'components/tooltip'; import {CloudProducts, LicenseSkus, MattermostFeatures, Preferences} from 'utils/constants'; import {asGBString} from 'utils/limits'; @@ -147,19 +146,13 @@ function FileLimitStickyBanner() { /> ); - const tooltip = ( - <Tooltip id='file_limit_banner_snooze'> - {formatMessage({id: 'create_post.file_limit_sticky_banner.snooze_tooltip', defaultMessage: 'Snooze for {snoozeDays} days'}, {snoozeDays: snoozeCoolOffDays})} - </Tooltip> - ); - return ( <StyledDiv id='cloud_file_limit_banner'> <AlertBanner mode={'warning'} variant={'app'} onDismiss={snoozeBanner} - closeBtnTooltip={tooltip} + closeBtnTooltip={formatMessage({id: 'create_post.file_limit_sticky_banner.snooze_tooltip', defaultMessage: 'Snooze for {snoozeDays} days'}, {snoozeDays: snoozeCoolOffDays})} title={title} message={isAdmin ? adminMessage : nonAdminMessage} /> diff --git a/webapp/channels/src/components/team_settings/team_access_tab/allowed_domains_select.tsx b/webapp/channels/src/components/team_settings/team_access_tab/allowed_domains_select.tsx index 7468cef11d13..260f385d3c39 100644 --- a/webapp/channels/src/components/team_settings/team_access_tab/allowed_domains_select.tsx +++ b/webapp/channels/src/components/team_settings/team_access_tab/allowed_domains_select.tsx @@ -2,27 +2,12 @@ // See LICENSE.txt for license information. import React, {useCallback, useState} from 'react'; -import {defineMessages, useIntl} from 'react-intl'; +import {FormattedMessage, useIntl} from 'react-intl'; import SelectTextInput, {type SelectTextInputOption} from 'components/common/select_text_input/select_text_input'; import CheckboxSettingItem from 'components/widgets/modals/components/checkbox_setting_item'; import {type SaveChangesPanelState} from 'components/widgets/modals/components/save_changes_panel'; -const translations = defineMessages({ - AllowedDomainsTitle: { - id: 'general_tab.AllowedDomainsTitle', - defaultMessage: 'Users with a specific email domain', - }, - AllowedDomainsInfo: { - id: 'general_tab.AllowedDomainsInfo', - defaultMessage: 'When enabled, users can only join the team if their email matches a specific domain (e.g. "mattermost.org")', - }, - AllowedDomains: { - id: 'general_tab.allowedDomains', - defaultMessage: 'Allow only users with a specific email domain to join this team', - }, -}); - type Props = { allowedDomains: string[]; setAllowedDomains: (domains: string[]) => void; @@ -52,15 +37,28 @@ const AllowedDomainsSelect = ({allowedDomains, setAllowedDomains, setHasChanges, setSaveChangesPanelState('editing'); setAllowedDomains(allowedDomainsOptions?.map((domain) => domain.value) || []); }, [setAllowedDomains, setHasChanges, setSaveChangesPanelState]); + return ( <> <CheckboxSettingItem + inputFieldTitle={ + <FormattedMessage + id='general_tab.allowedDomains' + defaultMessage='Allow only users with a specific email domain to join this team' + /> + } data-testid='allowedDomainsCheckbox' className='access-allowed-domains-section' - title={translations.AllowedDomainsTitle} - description={translations.AllowedDomainsInfo} + title={formatMessage({ + id: 'general_tab.AllowedDomainsTitle', + defaultMessage: 'Users with a specific email domain', + })} + description={formatMessage({ + id: 'general_tab.AllowedDomainsInfo', + defaultMessage: 'When enabled, users can only join the team if their email matches a specific domain (e.g. "mattermost.org")', + })} descriptionAboveContent={true} - inputFieldData={{title: translations.AllowedDomains, name: 'name'}} + inputFieldData={{name: 'name'}} inputFieldValue={showAllowedDomains} handleChange={handleEnableAllowedDomains} /> diff --git a/webapp/channels/src/components/team_settings/team_access_tab/invite_section_input.tsx b/webapp/channels/src/components/team_settings/team_access_tab/invite_section_input.tsx index bc5ce3044d18..efc2ac0c2d52 100644 --- a/webapp/channels/src/components/team_settings/team_access_tab/invite_section_input.tsx +++ b/webapp/channels/src/components/team_settings/team_access_tab/invite_section_input.tsx @@ -24,14 +24,6 @@ const translations = defineMessages({ id: 'team_settings.openInviteDescription.error', defaultMessage: 'There was an error generating the invite code, please try again', }, - CodeTitle: { - id: 'general_tab.codeTitle', - defaultMessage: 'Invite Code', - }, - CodeLongDesc: { - id: 'general_tab.codeLongDesc', - defaultMessage: 'The Invite Code is part of the unique team invitation link which is sent to members you’re inviting to this team. Regenerating the code creates a new invitation link and invalidates the previous link.', - }, }); type Props = { @@ -91,8 +83,15 @@ const InviteSectionInput = ({regenerateTeamInviteId}: Props) => { return ( <BaseSettingItem className='access-invite-section' - title={translations.CodeTitle} - description={translations.CodeLongDesc} + title={formatMessage({ + id: 'general_tab.codeTitle', + defaultMessage: 'Invite Code', + })} + description={formatMessage({ + id: 'general_tab.codeLongDesc', + defaultMessage: 'The Invite Code is part of the unique team invitation link which is sent to members you’re inviting to this team. Regenerating the code creates a new invitation link and invalidates the previous link.', + + })} content={inviteSectionInput} error={inviteIdError} descriptionAboveContent={true} diff --git a/webapp/channels/src/components/team_settings/team_access_tab/open_invite.tsx b/webapp/channels/src/components/team_settings/team_access_tab/open_invite.tsx index 8e76920b57f4..2915dd6ea7aa 100644 --- a/webapp/channels/src/components/team_settings/team_access_tab/open_invite.tsx +++ b/webapp/channels/src/components/team_settings/team_access_tab/open_invite.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react'; -import {defineMessages, useIntl} from 'react-intl'; +import {FormattedMessage, useIntl} from 'react-intl'; import ExternalLink from 'components/external_link'; import BaseSettingItem from 'components/widgets/modals/components/base_setting_item'; @@ -14,21 +14,6 @@ type Props = { setAllowOpenInvite: (value: boolean) => void; }; -const translations = defineMessages({ - OpenInviteText: { - id: 'general_tab.openInviteText', - defaultMessage: 'Users on this server', - }, - OpenInviteDesc: { - id: 'general_tab.openInviteDesc', - defaultMessage: 'When enabled, a link to this team will be included on the landing page allowing anyone with an account to join this team. Changing this setting will create a new invitation link and invalidate the previous link.', - }, - OpenInviteTitle: { - id: 'general_tab.openInviteTitle', - defaultMessage: 'Allow only users with a specific email domain to join this team', - }, -}); - const OpenInvite = ({isGroupConstrained, allowOpenInvite, setAllowOpenInvite}: Props) => { const {formatMessage} = useIntl(); if (isGroupConstrained) { @@ -52,8 +37,14 @@ const OpenInvite = ({isGroupConstrained, allowOpenInvite, setAllowOpenInvite}: P return ( <BaseSettingItem className='access-invite-domains-section' - title={translations.OpenInviteText} - description={translations.OpenInviteDesc} + title={formatMessage({ + id: 'general_tab.openInviteText', + defaultMessage: 'Users on this server', + })} + description={formatMessage({ + id: 'general_tab.openInviteDesc', + defaultMessage: 'When enabled, a link to this team will be included on the landing page allowing anyone with an account to join this team. Changing this setting will create a new invitation link and invalidate the previous link.', + })} descriptionAboveContent={true} content={groupConstrainedContent} /> @@ -63,11 +54,23 @@ const OpenInvite = ({isGroupConstrained, allowOpenInvite, setAllowOpenInvite}: P return ( <CheckboxSettingItem className='access-invite-domains-section' - inputFieldData={{title: translations.OpenInviteTitle, name: 'name'}} + inputFieldTitle={ + <FormattedMessage + id='general_tab.openInviteTitle' + defaultMessage='Allow only users with a specific email domain to join this team' + /> + } + inputFieldData={{name: 'name'}} inputFieldValue={allowOpenInvite} handleChange={setAllowOpenInvite} - title={translations.OpenInviteText} - description={translations.OpenInviteDesc} + title={formatMessage({ + id: 'general_tab.openInviteText', + defaultMessage: 'Users on this server', + })} + description={formatMessage({ + id: 'general_tab.openInviteDesc', + defaultMessage: 'When enabled, a link to this team will be included on the landing page allowing anyone with an account to join this team. Changing this setting will create a new invitation link and invalidate the previous link.', + })} descriptionAboveContent={true} /> ); diff --git a/webapp/channels/src/components/team_settings/team_info_tab/team_description_section.tsx b/webapp/channels/src/components/team_settings/team_info_tab/team_description_section.tsx index cc3891c2258d..61a52a5114b4 100644 --- a/webapp/channels/src/components/team_settings/team_info_tab/team_description_section.tsx +++ b/webapp/channels/src/components/team_settings/team_info_tab/team_description_section.tsx @@ -3,7 +3,7 @@ import React, {useCallback} from 'react'; import type {ChangeEvent} from 'react'; -import {defineMessages, useIntl} from 'react-intl'; +import {useIntl} from 'react-intl'; import type {Team} from '@mattermost/types/teams'; @@ -12,13 +12,6 @@ import BaseSettingItem, {type BaseSettingItemProps} from 'components/widgets/mod import Constants from 'utils/constants'; -const translations = defineMessages({ - TeamDescriptionInfo: { - id: 'general_tab.teamDescriptionInfo', - defaultMessage: 'Team description provides additional information to help users select the right team. Maximum of 50 characters.', - }, -}); - type Props = { handleDescriptionChanges: (name: string) => void; description: Team['description']; @@ -47,7 +40,10 @@ const TeamDescriptionSection = ({handleDescriptionChanges, clientError, descript return ( <BaseSettingItem - description={translations.TeamDescriptionInfo} + description={formatMessage({ + id: 'general_tab.teamDescriptionInfo', + defaultMessage: 'Team description provides additional information to help users select the right team. Maximum of 50 characters.', + })} content={descriptionSectionInput} className='description-setting-item' error={clientError} diff --git a/webapp/channels/src/components/team_settings/team_info_tab/team_name_section.tsx b/webapp/channels/src/components/team_settings/team_info_tab/team_name_section.tsx index 660444f17330..ac0b293f71df 100644 --- a/webapp/channels/src/components/team_settings/team_info_tab/team_name_section.tsx +++ b/webapp/channels/src/components/team_settings/team_info_tab/team_name_section.tsx @@ -3,7 +3,7 @@ import React, {useCallback} from 'react'; import type {ChangeEvent} from 'react'; -import {defineMessages, useIntl} from 'react-intl'; +import {useIntl} from 'react-intl'; import type {Team} from '@mattermost/types/teams'; @@ -12,17 +12,6 @@ import BaseSettingItem, {type BaseSettingItemProps} from 'components/widgets/mod import Constants from 'utils/constants'; -const translations = defineMessages({ - TeamInfo: { - id: 'general_tab.teamInfo', - defaultMessage: 'Team info', - }, - TeamNameInfo: { - id: 'general_tab.teamNameInfo', - defaultMessage: 'This name will appear on your sign-in screen and at the top of the left sidebar.', - }, -}); - type Props = { handleNameChanges: (name: string) => void; name: Team['display_name']; @@ -48,8 +37,14 @@ const TeamNameSection = ({clientError, handleNameChanges, name}: Props) => { return ( <BaseSettingItem - title={translations.TeamInfo} - description={translations.TeamNameInfo} + title={formatMessage({ + id: 'general_tab.teamInfo', + defaultMessage: 'Team info', + })} + description={formatMessage({ + id: 'general_tab.teamNameInfo', + defaultMessage: 'This name will appear on your sign-in screen and at the top of the left sidebar.', + })} content={nameSectionInput} error={clientError} /> diff --git a/webapp/channels/src/components/team_settings/team_info_tab/team_picture_section.tsx b/webapp/channels/src/components/team_settings/team_info_tab/team_picture_section.tsx index dcf1c94ee808..ce672b4e8729 100644 --- a/webapp/channels/src/components/team_settings/team_info_tab/team_picture_section.tsx +++ b/webapp/channels/src/components/team_settings/team_info_tab/team_picture_section.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {type ChangeEvent, useRef, useState, useEffect, useCallback} from 'react'; -import {defineMessages, useIntl} from 'react-intl'; +import {useIntl} from 'react-intl'; import {TrashCanOutlineIcon} from '@mattermost/compass-icons/components'; import type {Team} from '@mattermost/types/teams'; @@ -14,19 +14,8 @@ import type {BaseSettingItemProps} from 'components/widgets/modals/components/ba import Constants from 'utils/constants'; import * as FileUtils from 'utils/file_utils'; import {imageURLForTeam} from 'utils/utils'; -import './team_picture_section.scss'; -const translations = defineMessages({ - Title: { - id: 'setting_picture.title', - defaultMessage: 'Team Icon', - }, - Profile: { - id: 'setting_picture.help.profile', - defaultMessage: 'Upload a picture in BMP, JPG, JPEG, or PNG format. Maximum file size: {max}', - values: {max: '50MB'}, - }, -}); +import './team_picture_section.scss'; type Props = { team: Team; @@ -168,8 +157,19 @@ const TeamPictureSection = ({team, file, teamName, disabled, onFileChange, onRem return ( <BaseSettingItem - title={translations.Title} - description={teamImageSource ? undefined : translations.Profile} + title={formatMessage({ + id: 'setting_picture.title', + defaultMessage: 'Team Icon', + })} + description={teamImageSource ? undefined : formatMessage( + { + id: 'setting_picture.help.profile', + defaultMessage: 'Upload a picture in BMP, JPG, JPEG, or PNG format. Maximum file size: {max}', + }, + { + max: '50MB', + }, + )} content={teamPictureSection} className='picture-setting-item' error={clientError} diff --git a/webapp/channels/src/components/widgets/modals/components/base_setting_item.scss b/webapp/channels/src/components/widgets/modals/components/base_setting_item.scss index 03fdfcf4d670..b00b72d51828 100644 --- a/webapp/channels/src/components/widgets/modals/components/base_setting_item.scss +++ b/webapp/channels/src/components/widgets/modals/components/base_setting_item.scss @@ -9,11 +9,11 @@ padding: 0; margin: 0 0 8px; color: var(--center-channel-color); - font-family: 'Metropolis', sans-serif; - font-size: 16px; + font-family: "Open Sans", sans-serif; + font-size: 14px; font-style: normal; font-weight: 600; - line-height: 24px; + line-height: 20px; } &__description { @@ -82,6 +82,7 @@ width: fit-content; flex-direction: row; align-items: center; + margin-bottom: 0; cursor: pointer; font-size: 14px; font-weight: 400; diff --git a/webapp/channels/src/components/widgets/modals/components/base_setting_item.tsx b/webapp/channels/src/components/widgets/modals/components/base_setting_item.tsx index ce4db74265ed..1cb5b5bdc70f 100644 --- a/webapp/channels/src/components/widgets/modals/components/base_setting_item.tsx +++ b/webapp/channels/src/components/widgets/modals/components/base_setting_item.tsx @@ -16,8 +16,8 @@ type ExtendedMessageDescriptor = MessageDescriptor & { }; export type BaseSettingItemProps = { - title?: ExtendedMessageDescriptor; - description?: ExtendedMessageDescriptor; + title?: string; + description?: string; error?: ExtendedMessageDescriptor; }; @@ -29,21 +29,22 @@ type Props = BaseSettingItemProps & { function BaseSettingItem({title, description, content, className, error, descriptionAboveContent = false}: Props): JSX.Element { const {formatMessage} = useIntl(); - const Title = title && ( + + const titleComponent = title && ( <h4 data-testid='mm-modal-generic-section-item__title' className='mm-modal-generic-section-item__title' > - {formatMessage({id: title.id, defaultMessage: title.defaultMessage}, title.values)} + {title} </h4> ); - const Description = description && ( + const descriptionComponent = description && ( <p data-testid='mm-modal-generic-section-item__description' className='mm-modal-generic-section-item__description' > - {formatMessage({id: description.id, defaultMessage: description.defaultMessage}, description.values)} + {description} </p> ); @@ -57,19 +58,17 @@ function BaseSettingItem({title, description, content, className, error, descrip </div> ); - const getClassName = classNames('mm-modal-generic-section-item', className); - return ( - <div className={getClassName}> - {Title} - {descriptionAboveContent ? Description : undefined} + <div className={classNames('mm-modal-generic-section-item', className)}> + {titleComponent} + {descriptionAboveContent ? descriptionComponent : undefined} <div data-testid='mm-modal-generic-section-item__content' className='mm-modal-generic-section-item__content' > {content} </div> - {descriptionAboveContent ? undefined : Description} + {descriptionAboveContent ? undefined : descriptionComponent} {Error} </div> ); diff --git a/webapp/channels/src/components/widgets/modals/components/checkbox_setting_item.tsx b/webapp/channels/src/components/widgets/modals/components/checkbox_setting_item.tsx index aef4002aaa39..15838c7f7f51 100644 --- a/webapp/channels/src/components/widgets/modals/components/checkbox_setting_item.tsx +++ b/webapp/channels/src/components/widgets/modals/components/checkbox_setting_item.tsx @@ -1,35 +1,40 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import type {ReactNode} from 'react'; import React from 'react'; -import {FormattedMessage} from 'react-intl'; -import type {MessageDescriptor} from 'react-intl'; import type {BaseSettingItemProps} from './base_setting_item'; import BaseSettingItem from './base_setting_item'; export type FieldsetCheckbox = { dataTestId?: string; - title: MessageDescriptor; name: string; } type Props = BaseSettingItemProps & { inputFieldData: FieldsetCheckbox; inputFieldValue: boolean; + + /** + * The title of the checkbox input field, pass in FormattedMessage component for styling compatibility + */ + inputFieldTitle: ReactNode; handleChange: (e: boolean) => void; className?: string; descriptionAboveContent?: boolean; } -function CheckboxSettingItem({ + +export default function CheckboxSettingItem({ title, description, inputFieldData, inputFieldValue, + inputFieldTitle, handleChange, className, descriptionAboveContent = false, -}: Props): JSX.Element { +}: Props) { const content = ( <fieldset key={inputFieldData.name} @@ -44,14 +49,11 @@ function CheckboxSettingItem({ checked={inputFieldValue} onChange={(e) => handleChange(e.target.checked)} /> - <FormattedMessage - id={inputFieldData.title.id} - defaultMessage={inputFieldData.title.defaultMessage} - /> + {inputFieldTitle} </label> - <br/> </fieldset> ); + return ( <BaseSettingItem content={content} @@ -62,5 +64,3 @@ function CheckboxSettingItem({ /> ); } - -export default CheckboxSettingItem; diff --git a/webapp/channels/src/components/widgets/modals/components/modal_header.scss b/webapp/channels/src/components/widgets/modals/components/modal_header.scss index 93822646069f..8304a0506310 100644 --- a/webapp/channels/src/components/widgets/modals/components/modal_header.scss +++ b/webapp/channels/src/components/widgets/modals/components/modal_header.scss @@ -15,6 +15,7 @@ font-style: normal; font-weight: 600; line-height: 28px; + white-space: nowrap; } &__vertical-divider { @@ -42,28 +43,6 @@ flex: 1 1 auto; align-items: center; justify-content: flex-end; - color: rgba(var(--center-channel-color-rgb), 0.56); - gap: 24px; - } - - &__close-btn { - display: flex; - overflow: hidden; - width: 40px; - height: 40px; - align-items: center; - justify-content: center; - border: unset; - border-radius: 4px; - margin-left: 8px; - background: transparent; - color: rgba(var(--center-channel-color-rgb), 0.56); - - &:hover, - &.active { - background: rgba(var(--center-channel-color-rgb), 0.08); - color: rgba(var(--center-channel-color-rgb), 0.72); - } } @media screen and (max-width: 768px) { diff --git a/webapp/channels/src/components/widgets/modals/components/modal_header.tsx b/webapp/channels/src/components/widgets/modals/components/modal_header.tsx index 38ef72413037..f04a2778b168 100644 --- a/webapp/channels/src/components/widgets/modals/components/modal_header.tsx +++ b/webapp/channels/src/components/widgets/modals/components/modal_header.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import {CloseIcon} from '@mattermost/compass-icons/components'; import './modal_header.scss'; type Props = { @@ -29,11 +28,8 @@ function ModalHeader({id, title, subtitle, handleClose}: Props) { className='mm-modal-header__ctr' onClick={handleClose} > - <button className='style--none mm-modal-header__close-btn'> - <CloseIcon - size={24} - color={'currentcolor'} - /> + <button className='btn btn-icon'> + <i className='icon icon-close'/> </button> </div> </header> diff --git a/webapp/channels/src/components/widgets/modals/components/modal_section.scss b/webapp/channels/src/components/widgets/modals/components/modal_section.scss index e8147bc95acc..2c5a5a42662b 100644 --- a/webapp/channels/src/components/widgets/modals/components/modal_section.scss +++ b/webapp/channels/src/components/widgets/modals/components/modal_section.scss @@ -2,46 +2,41 @@ display: flex; flex-direction: column; - &__info-ctr { + .modalSectionHeader { display: flex; flex-direction: column; - margin-bottom: 8px; gap: 8px; - } - - &__title { - display: flex; - align-items: center; - padding: 0; - margin: 0; - color: var(--center-channel-color); - font-family: 'Metropolis', sans-serif; - font-size: 16px; - font-style: normal; - font-weight: 600; - line-height: 24px; - } + margin-block-end: 24px; - &__row { - display: flex; - align-items: center; - gap: 8px; - } + .modalSectionTitle { + display: flex; + align-items: center; + padding: 0; + margin: 0; + color: var(--center-channel-color); + font-family: "Metropolis", sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 600; + gap: 8px; + line-height: 24px; + } - &__description { - display: flex; - align-items: center; - padding: 0; - margin: 0; - color: rgba(var(--center-channel-color-rgb), 0.64); - font-family: 'Open Sans', sans-serif; - font-size: 12px; - font-style: normal; - font-weight: 400; - line-height: 16px; + .modalSectionDescription { + display: flex; + align-items: center; + padding: 0; + margin: 0; + color: rgba(var(--center-channel-color-rgb), 0.64); + font-family: "Open Sans", sans-serif; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; + } } - &__content { + .modalSectionContent { display: flex; flex-direction: column; gap: 24px; diff --git a/webapp/channels/src/components/widgets/modals/components/modal_section.tsx b/webapp/channels/src/components/widgets/modals/components/modal_section.tsx index 016d8c869160..1f26b7a08cc7 100644 --- a/webapp/channels/src/components/widgets/modals/components/modal_section.tsx +++ b/webapp/channels/src/components/widgets/modals/components/modal_section.tsx @@ -2,14 +2,13 @@ // See LICENSE.txt for license information. import React from 'react'; -import type {MessageDescriptor} from 'react-intl'; -import {useIntl} from 'react-intl'; +import type {ReactNode} from 'react'; import './modal_section.scss'; type Props = { - title?: MessageDescriptor; - description?: MessageDescriptor; + title?: ReactNode; + description?: ReactNode; content: JSX.Element; titleSuffix?: JSX.Element; }; @@ -19,46 +18,29 @@ function ModalSection({ description, content, titleSuffix, -}: Props): JSX.Element { - const {formatMessage} = useIntl(); - const titleContent = title ? ( - <h4 className='mm-modal-generic-section__title'> - {formatMessage({id: title.id, defaultMessage: title.defaultMessage})} +}: Props) { + const titleComponent = title && ( + <h4 className='modalSectionTitle'> + {title} + {titleSuffix} </h4> - ) : undefined; + ); - const descriptionContent = description && ( - <p className='mm-modal-generic-section__description'> - {formatMessage({id: description.id, defaultMessage: description.defaultMessage})} + const descriptionComponent = description && ( + <p className='modalSectionDescription'> + {description} </p> ); - function titleRow() { - if (titleSuffix) { - return (<div className='mm-modal-generic-section__row'> - {titleContent} - {titleSuffix} - </div>); - } - return titleContent; - } - - const titleDescriptionSection = () => { - if (title || description) { - return ( - <div className='mm-modal-generic-section__title-description-ctr'> - {titleRow()} - {descriptionContent} - </div> - ); - } - return null; - }; - return ( <section className='mm-modal-generic-section'> - {titleDescriptionSection()} - <div className='mm-modal-generic-section__content'> + {(title || description) && ( + <div className='modalSectionHeader'> + {titleComponent} + {descriptionComponent} + </div> + )} + <div className='modalSectionContent'> {content} </div> </section> diff --git a/webapp/channels/src/components/widgets/modals/components/radio_setting_item.tsx b/webapp/channels/src/components/widgets/modals/components/radio_setting_item.tsx index b7cc551bc9b6..7671a8891b26 100644 --- a/webapp/channels/src/components/widgets/modals/components/radio_setting_item.tsx +++ b/webapp/channels/src/components/widgets/modals/components/radio_setting_item.tsx @@ -1,9 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import type {ReactNode} from 'react'; import React from 'react'; -import type {MessageDescriptor} from 'react-intl'; -import {FormattedMessage} from 'react-intl'; import type {BaseSettingItemProps} from './base_setting_item'; import BaseSettingItem from './base_setting_item'; @@ -11,7 +10,7 @@ import BaseSettingItem from './base_setting_item'; export type FieldsetRadio = { options: Array<{ dataTestId?: string; - title: MessageDescriptor; + title: ReactNode; name: string; key: string; value: string; @@ -20,13 +19,16 @@ export type FieldsetRadio = { } type Props = BaseSettingItemProps & { + className?: string; inputFieldData: FieldsetRadio; inputFieldValue: string; handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void; } + function RadioSettingItem({ title, description, + className, inputFieldData, inputFieldValue, handleChange, @@ -46,10 +48,7 @@ function RadioSettingItem({ value={option.value} onChange={handleChange} /> - <FormattedMessage - id={option.title.id} - defaultMessage={option.title.defaultMessage} - /> + {option.title} {option.suffix} </label> ); @@ -62,6 +61,7 @@ function RadioSettingItem({ ); return ( <BaseSettingItem + className={className} content={content} title={title} description={description}