From 2f43194ad6a27e24a44178c85e7f95b1f25da6a8 Mon Sep 17 00:00:00 2001 From: Kosta Date: Fri, 15 Mar 2024 17:23:34 +0100 Subject: [PATCH] SSO: Show modal on disconnection (#88552) Co-authored-by: Anthony Grullon --- client/components/survey-modal/README.md | 49 +++++++++ client/components/survey-modal/index.jsx | 109 ++++++++++++++++++ client/components/survey-modal/style.scss | 114 +++++++++++++++++++ client/my-sites/site-settings/sso.jsx | 128 ++++++++++++++-------- 4 files changed, 352 insertions(+), 48 deletions(-) create mode 100644 client/components/survey-modal/README.md create mode 100644 client/components/survey-modal/index.jsx create mode 100644 client/components/survey-modal/style.scss diff --git a/client/components/survey-modal/README.md b/client/components/survey-modal/README.md new file mode 100644 index 00000000000000..60da760ed1701f --- /dev/null +++ b/client/components/survey-modal/README.md @@ -0,0 +1,49 @@ +# SurveyModal + +Simple modal component that links to a survey. + +## Example Usage + +```js +import { useState } from 'react'; +import ReactDOM from 'react-dom'; + +import SurveyModal from 'calypso/components/survey-modal'; +import surveyImage from 'calypso/assets/images/illustrations/illustration-seller.svg'; + +function MyComponent() { + const [ isModalVisible, setIsModalVisible ] = useState( false ); + + return <> +
Content
+ { isModalVisible && + ReactDOM.createPortal( + , + document.body + ) }; + +} +``` + +## Props + +- `name` - (string) The name to use for cookie management. Recommended to use Kebap case. +- `className` - (string) Additional className for the modal. +- `url` - (string) The url to which the confirm button links to. +- `heading` - _optional_ (string) Heading of the modal +- `title` - _optional_ (string) Title text +- `surveyImage` - _optional_ (string) Image to display in the modal +- `description` - (string) Description text +- `dismissText` - (string) Text for the dismiss button +- `confirmText` - (string) Text for the confirm button diff --git a/client/components/survey-modal/index.jsx b/client/components/survey-modal/index.jsx new file mode 100644 index 00000000000000..5ed3b86aabe6e1 --- /dev/null +++ b/client/components/survey-modal/index.jsx @@ -0,0 +1,109 @@ +import { Gridicon } from '@automattic/components'; +import { Button } from '@wordpress/components'; +import { useState } from '@wordpress/element'; +import classNames from 'classnames'; +import cookie from 'cookie'; +import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; +import { getCurrentUserId } from 'calypso/state/current-user/selectors'; +import './style.scss'; + +const SurveyModal = ( { + name, + className, + url, + heading, + title, + surveyImage, + description, + dismissText, + confirmText, +} ) => { + const userId = useSelector( getCurrentUserId ); + const href = new URL( url ); + href.searchParams.set( 'user-id', userId ); + + const [ hideNotice, setHideNotice ] = useState( + 'dismissed' === cookie.parse( document.cookie )?.sso_survey + ); + + const setSurveyCookie = ( value, maxAge ) => { + document.cookie = cookie.serialize( name, value, { + path: '/', + maxAge, + } ); + }; + + const onClose = () => { + setSurveyCookie( 'dismissed', 365 * 24 * 60 * 60 ); // 1 year + setHideNotice( true ); + }; + + if ( hideNotice ) { + return null; + } + + return ( +
+ +
+ ) } + + { ! heading && ( + + ) } + + { surveyImage && ( +
+ { +
+ ) } + +
+ { title &&
{ title }
} +
{ description }
+
+ + +
+
+ + + ); +}; + +SurveyModal.propTypes = { + name: PropTypes.string.isRequired, + className: PropTypes.string, + url: PropTypes.string.isRequired, + heading: PropTypes.string, + title: PropTypes.string, + surveyImage: PropTypes.string, + description: PropTypes.string.isRequired, + dismissText: PropTypes.string.isRequired, + confirmText: PropTypes.string.isRequired, +}; + +export default SurveyModal; diff --git a/client/components/survey-modal/style.scss b/client/components/survey-modal/style.scss new file mode 100644 index 00000000000000..7ec22d44367bf5 --- /dev/null +++ b/client/components/survey-modal/style.scss @@ -0,0 +1,114 @@ +.modal-survey-notice { + position: fixed; + left: 0; + top: 0; + height: 100%; + width: 100%; + z-index: 1000; + + .modal-survey-notice__backdrop { + background: var(--studio-black); + opacity: 0.2; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + cursor: default; + } + + + .modal-survey-notice__popup { + position: absolute; + right: 25px; + bottom: 25px; + width: 416px; + max-width: calc(100% - 50px); + z-index: 2; + border-radius: 2px; + box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.04), 0 3px 8px 0 rgba(0, 0, 0, 0.12); + overflow: hidden; + + .modal-survey-notice__popup-head { + background: #0675c4; + border-bottom: 1px solid #f6f7f7; + height: 56px; + padding: 0 14px 0 16px; + display: flex; + align-items: center; + justify-content: space-between; + + .modal-survey-notice__popup-head-title { + color: var(--studio-white); + font-size: rem(14px); + font-weight: 500; + line-height: 20px; + letter-spacing: -0.15px; + } + + } + + .modal-survey-notice__popup-head-close svg { + fill: var(--studio-white); + } + + > .modal-survey-notice__popup-head-close { + position: absolute; + right: 0; + } + + .modal-survey-notice__popup-img { + background: #0675c4; + padding-bottom: 57.9%; + height: 0; + + img { + width: 100%; + display: block; + } + } + + .modal-survey-notice__popup-content { + padding: 1rem; + background: var(--studio-white); + + .modal-survey-notice__popup-content-title { + font-size: rem(16px); + font-weight: 500; + line-height: 24px; + letter-spacing: -0.32px; + padding-bottom: 8px; + } + + .modal-survey-notice__popup-content-description { + font-size: rem(14px); + line-height: 20px; + letter-spacing: -0.15px; + padding-bottom: 18px; + } + + .modal-survey-notice__popup-content-buttons { + display: flex; + justify-content: flex-end; + + .modal-survey-notice__popup-content-buttons-ok { + padding: 8px 14px; + background: var(--studio-blue-50); + color: var(--studio-white); + font-size: rem(14px); + line-height: 20px; + letter-spacing: -0.15px; + } + + .modal-survey-notice__popup-content-buttons-cancel { + padding: 8px 14px; + color: var(--studio-blue-50); + text-align: center; + font-size: rem(14px); + line-height: 20px; + letter-spacing: -0.15px; + } + } + } + } +} diff --git a/client/my-sites/site-settings/sso.jsx b/client/my-sites/site-settings/sso.jsx index 281c847b11a2c1..28cb4c3f401853 100644 --- a/client/my-sites/site-settings/sso.jsx +++ b/client/my-sites/site-settings/sso.jsx @@ -1,11 +1,15 @@ import { Card } from '@automattic/components'; +import { useLocale } from '@automattic/i18n-utils'; import { ToggleControl } from '@wordpress/components'; import { localize } from 'i18n-calypso'; import PropTypes from 'prop-types'; +import { useState } from 'react'; +import ReactDOM from 'react-dom'; import { connect } from 'react-redux'; import QueryJetpackConnection from 'calypso/components/data/query-jetpack-connection'; import FormFieldset from 'calypso/components/forms/form-fieldset'; import SupportInfo from 'calypso/components/support-info'; +import SurveyModal from 'calypso/components/survey-modal'; import JetpackModuleToggle from 'calypso/my-sites/site-settings/jetpack-module-toggle'; import isJetpackModuleActive from 'calypso/state/selectors/is-jetpack-module-active'; import isJetpackModuleUnavailableInDevelopmentMode from 'calypso/state/selectors/is-jetpack-module-unavailable-in-development-mode'; @@ -23,60 +27,88 @@ const Sso = ( { ssoModuleUnavailable, translate, } ) => { - return ( -
- - - - - + const localeSlug = useLocale(); + const [ isModalVisible, setIsModalVisible ] = useState( false ); - + return ( + <> +
+ -
- + + - { + if ( ! enabled ) { + setIsModalVisible( true ); + } + } } /> -
- - -
+ +
+ + + +
+
+
+
+ { localeSlug === 'en' && + isModalVisible && + ReactDOM.createPortal( + , + document.body + ) } + ); };