From 70d34c49c8302b372f876abfe0a91a005840fe2a Mon Sep 17 00:00:00 2001 From: simeng-li Date: Thu, 26 May 2022 13:30:09 +0800 Subject: [PATCH] refactor(ui): social container refactor (#955) * refactor(ui): social container refactor social container refactor * refactor(ui): extract socialSignInIconList extract socialSignInIconList --- .../PrimarySocialSignIn/index.tsx | 15 ++++ .../SocialSignIn/SecondarySocialSignIn.tsx | 82 ------------------- .../index.test.tsx} | 2 +- .../SecondarySocialSignIn/index.tsx | 65 +++++++++++++++ .../index.module.scss} | 0 .../SocialSignInDropdown/index.test.tsx | 24 ++++++ .../index.tsx} | 46 +++++------ .../index.module.scss} | 0 .../SocialSignInIconList/index.tsx | 50 +++++++++++ .../index.module.scss} | 0 .../index.test.tsx} | 8 +- .../index.tsx} | 28 ++++--- .../index.tsx} | 4 +- packages/ui/src/pages/SignIn/index.test.tsx | 3 +- 14 files changed, 198 insertions(+), 129 deletions(-) create mode 100644 packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn/index.tsx delete mode 100644 packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.tsx rename packages/ui/src/containers/SocialSignIn/{SecondarySocialSignIn.test.tsx => SecondarySocialSignIn/index.test.tsx} (98%) create mode 100644 packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn/index.tsx rename packages/ui/src/containers/SocialSignIn/{SocialSignInDropdown.module.scss => SocialSignInDropdown/index.module.scss} (100%) create mode 100644 packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.test.tsx rename packages/ui/src/containers/SocialSignIn/{SocialSignInDropdown.tsx => SocialSignInDropdown/index.tsx} (85%) rename packages/ui/src/containers/SocialSignIn/{SecondarySocialSignIn.module.scss => SocialSignInIconList/index.module.scss} (100%) create mode 100644 packages/ui/src/containers/SocialSignIn/SocialSignInIconList/index.tsx rename packages/ui/src/containers/SocialSignIn/{PrimarySocialSignIn.module.scss => SocialSignInList/index.module.scss} (100%) rename packages/ui/src/containers/SocialSignIn/{PrimarySocialSignIn.test.tsx => SocialSignInList/index.test.tsx} (87%) rename packages/ui/src/containers/SocialSignIn/{PrimarySocialSignIn.tsx => SocialSignInList/index.tsx} (67%) rename packages/ui/src/containers/SocialSignIn/{SocialSignInPopUp.tsx => SocialSignInPopUp/index.tsx} (72%) diff --git a/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn/index.tsx b/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn/index.tsx new file mode 100644 index 000000000..72541e8b2 --- /dev/null +++ b/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn/index.tsx @@ -0,0 +1,15 @@ +import React from 'react'; + +import SocialSignInList from '../SocialSignInList'; + +export const defaultSize = 3; + +type Props = { + className?: string; +}; + +const PrimarySocialSignIn = ({ className }: Props) => { + return ; +}; + +export default PrimarySocialSignIn; diff --git a/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.tsx b/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.tsx deleted file mode 100644 index 97e133dec..000000000 --- a/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import classNames from 'classnames'; -import React, { useMemo, useState, useRef } from 'react'; - -import MoreSocialIcon from '@/assets/icons/more-social-icon.svg'; -import IconButton from '@/components/Button/IconButton'; -import SocialIconButton from '@/components/Button/SocialIconButton'; -import usePlatform from '@/hooks/use-platform'; -import useSocial from '@/hooks/use-social'; - -import * as styles from './SecondarySocialSignIn.module.scss'; -import SocialSignInDropdown from './SocialSignInDropdown'; -import SocialSignInPopUp from './SocialSignInPopUp'; - -export const defaultSize = 4; - -type Props = { - className?: string; -}; - -const SecondarySocialSignIn = ({ className }: Props) => { - const { socialConnectors, invokeSocialSignIn } = useSocial(); - const isOverSize = socialConnectors.length > defaultSize; - const [showModal, setShowModal] = useState(false); - const moreButtonRef = useRef(null); - const { isMobile } = usePlatform(); - - const displayConnectors = useMemo(() => { - if (isOverSize) { - return socialConnectors.slice(0, defaultSize - 1); - } - - return socialConnectors; - }, [socialConnectors, isOverSize]); - - return ( - <> -
- {displayConnectors.map((connector) => ( - { - void invokeSocialSignIn(connector.id); - }} - /> - ))} - {isOverSize && ( - { - setShowModal(true); - }} - > - - - )} -
- {isOverSize && isMobile && ( - { - setShowModal(false); - }} - /> - )} - {isOverSize && !isMobile && ( - { - setShowModal(false); - }} - /> - )} - - ); -}; - -export default SecondarySocialSignIn; diff --git a/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.test.tsx b/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn/index.test.tsx similarity index 98% rename from packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.test.tsx rename to packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn/index.test.tsx index 1fe3aa341..928162a5d 100644 --- a/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.test.tsx +++ b/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn/index.test.tsx @@ -8,7 +8,7 @@ import { socialConnectors, mockSignInExperienceSettings } from '@/__mocks__/logt import * as socialSignInApi from '@/apis/social'; import { generateState, storeState } from '@/hooks/utils'; -import SecondarySocialSignIn, { defaultSize } from './SecondarySocialSignIn'; +import SecondarySocialSignIn, { defaultSize } from '.'; describe('SecondarySocialSignIn', () => { const mockOrigin = 'https://logto.dev'; diff --git a/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn/index.tsx b/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn/index.tsx new file mode 100644 index 000000000..cac9f8bf7 --- /dev/null +++ b/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn/index.tsx @@ -0,0 +1,65 @@ +import React, { useMemo, useState, useRef } from 'react'; + +import usePlatform from '@/hooks/use-platform'; +import useSocial from '@/hooks/use-social'; + +import SocialSignInDropdown from '../SocialSignInDropdown'; +import SocialSignInIconList from '../SocialSignInIconList'; +import SocialSignInPopUp from '../SocialSignInPopUp'; + +export const defaultSize = 4; + +type Props = { + className?: string; +}; + +const SecondarySocialSignIn = ({ className }: Props) => { + const { socialConnectors } = useSocial(); + const [showModal, setShowModal] = useState(false); + const moreButtonRef = useRef(null); + const { isMobile } = usePlatform(); + + const isCollapsed = socialConnectors.length > defaultSize; + + const displayConnectors = useMemo(() => { + if (isCollapsed) { + return socialConnectors.slice(0, defaultSize - 1); + } + + return socialConnectors; + }, [socialConnectors, isCollapsed]); + + return ( + <> + { + setShowModal(true); + }} + /> + {isCollapsed && isMobile && ( + { + setShowModal(false); + }} + /> + )} + {isCollapsed && !isMobile && ( + { + setShowModal(false); + }} + /> + )} + + ); +}; + +export default SecondarySocialSignIn; diff --git a/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown.module.scss b/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.module.scss similarity index 100% rename from packages/ui/src/containers/SocialSignIn/SocialSignInDropdown.module.scss rename to packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.module.scss diff --git a/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.test.tsx b/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.test.tsx new file mode 100644 index 000000000..c32f3ff43 --- /dev/null +++ b/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.test.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; + +import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; +import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; +import { socialConnectors } from '@/__mocks__/logto'; + +import SocialSignInDropdown from '.'; + +describe('SocialSignInDropdown', () => { + it('render properly', () => { + const { queryByText } = renderWithPageContext( + + + + + + ); + + for (const { name } of socialConnectors) { + expect(queryByText(name.en)).not.toBeNull(); + } + }); +}); diff --git a/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown.tsx b/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.tsx similarity index 85% rename from packages/ui/src/containers/SocialSignIn/SocialSignInDropdown.tsx rename to packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.tsx index 339e32eb9..bd967a072 100644 --- a/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown.tsx +++ b/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.tsx @@ -1,12 +1,12 @@ import { Language } from '@logto/phrases'; -import React, { useMemo, useState, useCallback } from 'react'; +import React, { useState, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import Dropdown, { DropdownItem } from '@/components/Dropdown'; import useSocial from '@/hooks/use-social'; import { ConnectorData } from '@/types'; -import * as styles from './SocialSignInDropdown.module.scss'; +import * as styles from './index.module.scss'; type Props = { anchorRef?: React.RefObject; @@ -19,31 +19,8 @@ const SocialSignInDropdown = ({ isOpen, onClose, connectors, anchorRef }: Props) const { i18n: { language }, } = useTranslation(); - - const { invokeSocialSignIn } = useSocial(); - const [contentStyle, setContentStyle] = useState<{ top?: number; left?: number }>(); - - const items = useMemo( - () => - connectors.map(({ id, name, logo }) => { - const languageKey = Object.keys(name).find((key) => key === language) ?? 'en'; - const localName = name[languageKey as Language]; - - return ( - { - void invokeSocialSignIn(id, onClose); - }} - > - {id} - {localName} - - ); - }), - [connectors, language, invokeSocialSignIn, onClose] - ); + const { invokeSocialSignIn } = useSocial(); const adjustPosition = useCallback(() => { if (anchorRef?.current) { @@ -68,7 +45,22 @@ const SocialSignInDropdown = ({ isOpen, onClose, connectors, anchorRef }: Props) setContentStyle(undefined); }} > - {items} + {connectors.map(({ id, name, logo }) => { + const languageKey = Object.keys(name).find((key) => key === language) ?? 'en'; + const localName = name[languageKey as Language]; + + return ( + { + void invokeSocialSignIn(id, onClose); + }} + > + {id} + {localName} + + ); + })} ); }; diff --git a/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.module.scss b/packages/ui/src/containers/SocialSignIn/SocialSignInIconList/index.module.scss similarity index 100% rename from packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.module.scss rename to packages/ui/src/containers/SocialSignIn/SocialSignInIconList/index.module.scss diff --git a/packages/ui/src/containers/SocialSignIn/SocialSignInIconList/index.tsx b/packages/ui/src/containers/SocialSignIn/SocialSignInIconList/index.tsx new file mode 100644 index 000000000..51adb079c --- /dev/null +++ b/packages/ui/src/containers/SocialSignIn/SocialSignInIconList/index.tsx @@ -0,0 +1,50 @@ +import classNames from 'classnames'; +import React from 'react'; + +import MoreSocialIcon from '@/assets/icons/more-social-icon.svg'; +import IconButton from '@/components/Button/IconButton'; +import SocialIconButton from '@/components/Button/SocialIconButton'; +import useSocial from '@/hooks/use-social'; +import { ConnectorData } from '@/types'; + +import * as styles from './index.module.scss'; + +type Props = { + className?: string; + connectors?: ConnectorData[]; + hasMore?: boolean; + moreButtonRef: React.RefObject; + onMoreButtonClick?: () => void; +}; + +const SocialSignInIconList = ({ + className, + connectors = [], + hasMore = false, + moreButtonRef, + onMoreButtonClick, +}: Props) => { + const { invokeSocialSignIn } = useSocial(); + + return ( +
+ {connectors.map((connector) => ( + { + void invokeSocialSignIn(connector.id); + }} + /> + ))} + {hasMore && ( + + + + )} +
+ ); +}; + +export default SocialSignInIconList; diff --git a/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.module.scss b/packages/ui/src/containers/SocialSignIn/SocialSignInList/index.module.scss similarity index 100% rename from packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.module.scss rename to packages/ui/src/containers/SocialSignIn/SocialSignInList/index.module.scss diff --git a/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.test.tsx b/packages/ui/src/containers/SocialSignIn/SocialSignInList/index.test.tsx similarity index 87% rename from packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.test.tsx rename to packages/ui/src/containers/SocialSignIn/SocialSignInList/index.test.tsx index 246f33c31..ce7a0156c 100644 --- a/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.test.tsx +++ b/packages/ui/src/containers/SocialSignIn/SocialSignInList/index.test.tsx @@ -6,9 +6,9 @@ import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; import { socialConnectors, mockSignInExperienceSettings } from '@/__mocks__/logto'; -import PrimarySocialSignIn, { defaultSize } from './PrimarySocialSignIn'; +import SocialSignInList, { defaultSize } from '.'; -describe('SecondarySocialSignIn', () => { +describe('SocialSignInList', () => { it('less than three connectors', () => { const { container } = renderWithPageContext( { }} > - + ); @@ -29,7 +29,7 @@ describe('SecondarySocialSignIn', () => { const { container } = renderWithPageContext( - + ); diff --git a/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.tsx b/packages/ui/src/containers/SocialSignIn/SocialSignInList/index.tsx similarity index 67% rename from packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.tsx rename to packages/ui/src/containers/SocialSignIn/SocialSignInList/index.tsx index 07abbb00c..9098deb8c 100644 --- a/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.tsx +++ b/packages/ui/src/containers/SocialSignIn/SocialSignInList/index.tsx @@ -6,29 +6,33 @@ import IconButton from '@/components/Button/IconButton'; import SocialLinkButton from '@/components/Button/SocialLinkButton'; import useSocial from '@/hooks/use-social'; -import * as styles from './PrimarySocialSignIn.module.scss'; +import * as styles from './index.module.scss'; -export const defaultSize = 3; +export const defaultSize = 4; type Props = { className?: string; - isPopup?: boolean; + isCollapseEnabled?: boolean; onSocialSignInCallback?: () => void; }; -const PrimarySocialSignIn = ({ className, isPopup = false, onSocialSignInCallback }: Props) => { - const [showAll, setShowAll] = useState(false); +const SocialSignInList = ({ + className, + isCollapseEnabled = true, + onSocialSignInCallback, +}: Props) => { + const [expand, setExpand] = useState(false); const { invokeSocialSignIn, socialConnectors } = useSocial(); const isOverSize = socialConnectors.length > defaultSize; - const fullDisplay = isPopup || !isOverSize; + const displayAll = !isOverSize || !isCollapseEnabled; const displayConnectors = useMemo(() => { - if (fullDisplay || showAll) { + if (displayAll || expand) { return socialConnectors; } return socialConnectors.slice(0, defaultSize); - }, [fullDisplay, showAll, socialConnectors]); + }, [displayAll, expand, socialConnectors]); return (
@@ -42,11 +46,11 @@ const PrimarySocialSignIn = ({ className, isPopup = false, onSocialSignInCallbac }} /> ))} - {!fullDisplay && ( + {!displayAll && ( { - setShowAll(!showAll); + setExpand(!expand); }} > @@ -56,4 +60,4 @@ const PrimarySocialSignIn = ({ className, isPopup = false, onSocialSignInCallbac ); }; -export default PrimarySocialSignIn; +export default SocialSignInList; diff --git a/packages/ui/src/containers/SocialSignIn/SocialSignInPopUp.tsx b/packages/ui/src/containers/SocialSignIn/SocialSignInPopUp/index.tsx similarity index 72% rename from packages/ui/src/containers/SocialSignIn/SocialSignInPopUp.tsx rename to packages/ui/src/containers/SocialSignIn/SocialSignInPopUp/index.tsx index 842574652..e1cf7eb91 100644 --- a/packages/ui/src/containers/SocialSignIn/SocialSignInPopUp.tsx +++ b/packages/ui/src/containers/SocialSignIn/SocialSignInPopUp/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import Drawer from '@/components/Drawer'; -import PrimarySocialSignIn from './PrimarySocialSignIn'; +import SocialSignInList from '../SocialSignInList'; type Props = { isOpen?: boolean; @@ -12,7 +12,7 @@ type Props = { const SocialSignInPopUp = ({ isOpen = false, onClose, className }: Props) => ( - + ); diff --git a/packages/ui/src/pages/SignIn/index.test.tsx b/packages/ui/src/pages/SignIn/index.test.tsx index 70784188c..3b16f5b58 100644 --- a/packages/ui/src/pages/SignIn/index.test.tsx +++ b/packages/ui/src/pages/SignIn/index.test.tsx @@ -4,6 +4,7 @@ import { MemoryRouter } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; import { mockSignInExperienceSettings } from '@/__mocks__/logto'; +import { defaultSize } from '@/containers/SocialSignIn/SocialSignInList'; import SignIn from '@/pages/SignIn'; describe('', () => { @@ -56,6 +57,6 @@ describe('', () => { ); - expect(container.querySelectorAll('button')).toHaveLength(4); // Plus Expand Button + expect(container.querySelectorAll('button')).toHaveLength(defaultSize + 1); // Plus Expand Button }); });