diff --git a/src/components/AvatarTooltip/AvatarTooltip.tsx b/src/components/AvatarTooltip/AvatarTooltip.tsx deleted file mode 100644 index 8b4420c..0000000 --- a/src/components/AvatarTooltip/AvatarTooltip.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { FC } from 'react'; - -import { isEmail } from '../../utils/url'; -import Tooltip from '../../muiComponents/Tooltip'; -import Avatar from '../../muiComponents/Avatar'; - -export interface AvatarDeveloper { - name: string; - packageName: string; - version: string; - avatar: string; - email: string; -} - -const AvatarTooltip: FC = ({ name, packageName, version, avatar, email }) => { - const avatarComponent = ; - function renderLinkForMail( - email: string, - avatarComponent: JSX.Element, - packageName: string, - version: string - ): JSX.Element { - if (!email || isEmail(email) === false) { - return avatarComponent; - } - - return ( - - {avatarComponent} - - ); - } - - return {renderLinkForMail(email, avatarComponent, packageName, version)}; -}; - -export { AvatarTooltip }; diff --git a/src/components/AvatarTooltip/index.ts b/src/components/AvatarTooltip/index.ts deleted file mode 100644 index 746d62c..0000000 --- a/src/components/AvatarTooltip/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { AvatarTooltip } from './AvatarTooltip'; - -export { AvatarTooltip }; -export default AvatarTooltip; diff --git a/src/components/DetailSidebar/DetailSidebar.tsx b/src/components/DetailSidebar/DetailSidebar.tsx index 379a896..e51de6a 100644 --- a/src/components/DetailSidebar/DetailSidebar.tsx +++ b/src/components/DetailSidebar/DetailSidebar.tsx @@ -2,7 +2,7 @@ import React, { ReactElement } from 'react'; import ActionBar from '../ActionBar'; import Author from '../Author'; -import Developers from '../Developers'; +import Developers, { DeveloperType } from '../Developers'; import Dist from '../Dist/Dist'; import Engine from '../Engines/Engines'; import Install from '../Install'; @@ -28,8 +28,6 @@ const renderLatestDescription = (description, version, isLatest = true): JSX.Ele }; const renderCopyCLI = (): JSX.Element => ; -const renderMaintainers = (): JSX.Element => ; -const renderContributors = (): JSX.Element => ; const renderRepository = (): JSX.Element => ; const renderAuthor = (): JSX.Element => ; const renderEngine = (): JSX.Element => ; @@ -63,8 +61,8 @@ function renderSideBar(packageName, packageVersion, packageMeta): ReactElement + diff --git a/src/components/Developers/Developers.test.tsx b/src/components/Developers/Developers.test.tsx index 2f3fb7c..8913ebc 100644 --- a/src/components/Developers/Developers.test.tsx +++ b/src/components/Developers/Developers.test.tsx @@ -3,8 +3,7 @@ import React from 'react'; import { mount } from '../../utils/test-enzyme'; import { DetailContextProvider } from '../../pages/Version'; -import Developers, { DevelopersType } from './Developers'; -import { Fab } from './styles'; +import Developers, { DeveloperType, Fab } from './Developers'; describe('test Developers', () => { const packageMeta = { @@ -35,14 +34,13 @@ describe('test Developers', () => { }; test('should render the component with no items', () => { - const type: DevelopersType = 'maintainers'; const packageMeta = { latest: {}, }; const wrapper = mount( // @ts-ignore - + ); @@ -50,11 +48,10 @@ describe('test Developers', () => { }); test('should render the component for maintainers with items', () => { - const type: DevelopersType = 'maintainers'; const wrapper = mount( // @ts-ignore - + ); @@ -62,11 +59,10 @@ describe('test Developers', () => { }); test('should render the component for contributors with items', () => { - const type: DevelopersType = 'contributors'; const wrapper = mount( // @ts-ignore - + ); @@ -74,7 +70,6 @@ describe('test Developers', () => { }); test('should test onClick the component avatar', () => { - const type: DevelopersType = 'contributors'; const packageMeta = { latest: { packageName: 'foo', @@ -95,7 +90,7 @@ describe('test Developers', () => { const wrapper = mount( // @ts-ignore - + ); diff --git a/src/components/Developers/Developers.tsx b/src/components/Developers/Developers.tsx index ca4f96c..3e69462 100644 --- a/src/components/Developers/Developers.tsx +++ b/src/components/Developers/Developers.tsx @@ -1,60 +1,89 @@ -import React, { FC, Fragment } from 'react'; +import React, { useState, useCallback, useContext, useEffect, useMemo } from 'react'; import Add from '@material-ui/icons/Add'; +import styled from '@emotion/styled'; import { DetailContext } from '../../pages/Version'; -import { AvatarTooltip } from '../AvatarTooltip'; +import Tooltip from '../../muiComponents/Tooltip'; +import Avatar from '../../muiComponents/Avatar'; +import Box from '../../muiComponents/Box'; +import Text from '../../muiComponents/Text'; +import FloatingActionButton from '../../muiComponents/FloatingActionButton'; +import { Theme } from '../../design-tokens/theme'; -import { Details, StyledText, Content, Fab } from './styles'; +import getUniqueDeveloperValues from './get-unique-developer-values'; -export type DevelopersType = 'contributors' | 'maintainers'; +export const Fab = styled(FloatingActionButton)<{ theme?: Theme }>(props => ({ + backgroundColor: props.theme && props.theme.palette.primary.main, + color: props.theme && props.theme.palette.white, +})); + +export enum DeveloperType { + CONTRIBUTORS = 'contributors', + MAINTAINERS = 'maintainers', +} interface Props { - type: DevelopersType; + type: DeveloperType; visibleMax?: number; } +export const StyledText = styled(Text)<{ theme?: Theme }>(({ theme }) => ({ + fontWeight: theme && theme.fontWeight.bold, + marginBottom: '10px', + textTransform: 'capitalize', +})); + +const StyledBox = styled(Box)({ + '> *': { + margin: 5, + }, +}); + export const VISIBLE_MAX = 6; -const Developers: FC = ({ type, visibleMax }) => { - const [visibleDevs, setVisibleDevs] = React.useState(visibleMax || VISIBLE_MAX); - const { packageMeta } = React.useContext(DetailContext); +const Developers: React.FC = ({ type, visibleMax = VISIBLE_MAX }) => { + const detailContext = useContext(DetailContext); - const handleLoadMore = (): void => { - setVisibleDevs(visibleDevs + VISIBLE_MAX); - }; - - const renderDeveloperDetails = ({ name, avatar, email }, packageMeta): JSX.Element => { - const { name: packageName, version } = packageMeta.latest; - - return ; - }; - - const renderDevelopers = (developers, packageMeta): JSX.Element => { - const listVisibleDevelopers = developers.slice(0, visibleDevs); - - return ( - - {type} - - {listVisibleDevelopers.map(developer => ( -
{renderDeveloperDetails(developer, packageMeta)}
- ))} - {visibleDevs < developers.length && ( - - - - )} -
-
- ); - }; - - const developerList = packageMeta && packageMeta.latest[type]; - if (!developerList || developerList.length === 0) { - return null; + if (!detailContext) { + throw Error("The app's detail Context was not correct used"); } - return renderDevelopers(developerList, packageMeta); + const developers = useMemo(() => getUniqueDeveloperValues(detailContext.packageMeta?.latest[type]), [ + detailContext.packageMeta, + type, + ]); + + const [visibleDevelopersMax, setVisibleDevelopersMax] = useState(visibleMax); + const [visibleDevelopers, setVisibleDevelopers] = useState(developers); + + useEffect(() => { + if (!developers) return; + setVisibleDevelopers(developers.slice(0, visibleDevelopersMax)); + }, [developers, visibleDevelopersMax]); + + const handleSetVisibleDevelopersMax = useCallback(() => { + setVisibleDevelopersMax(visibleDevelopersMax + VISIBLE_MAX); + }, [visibleDevelopersMax]); + + if (!visibleDevelopers || !developers) return null; + + return ( + <> + {type} + + {visibleDevelopers.map(visibleDeveloper => ( + + + + ))} + {visibleDevelopersMax < developers.length && ( + + + + )} + + + ); }; export default Developers; diff --git a/src/components/Developers/__snapshots__/Developers.test.tsx.snap b/src/components/Developers/__snapshots__/Developers.test.tsx.snap index e820c96..94e907d 100644 --- a/src/components/Developers/__snapshots__/Developers.test.tsx.snap +++ b/src/components/Developers/__snapshots__/Developers.test.tsx.snap @@ -7,35 +7,10 @@ exports[`test Developers should render the component for contributors with items text-transform: capitalize; } -.emotion-12 { - margin: 10px 0 10px 0; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap; -} - -.emotion-12 > * { +.emotion-8 > * { margin: 5px; } -.emotion-8 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - @@ -97,336 +72,354 @@ exports[`test Developers should render the component for contributors with items - -
+ -
- - - - - - - - -
- - - - - - - -
-
-
-
-
- -
- -
- - } - className="MuiTooltip-popper" - id={null} - open={false} - placement="bottom" - popperOptions={ - Object { - "modifiers": Object { - "arrow": Object { - "element": null, - "enabled": false, - }, - }, - } - } - transition={true} - /> -
-
-
-
-
-
-
- - - - - + + + + +
+ + + + + + + } + className="MuiTooltip-popper" + id={null} + open={false} + placement="bottom" + popperOptions={ Object { - "arrow": "MuiTooltip-arrow", - "popper": "MuiTooltip-popper", - "popperArrow": "MuiTooltip-popperArrow", - "popperInteractive": "MuiTooltip-popperInteractive", - "tooltip": "MuiTooltip-tooltip", - "tooltipArrow": "MuiTooltip-tooltipArrow", - "tooltipPlacementBottom": "MuiTooltip-tooltipPlacementBottom", - "tooltipPlacementLeft": "MuiTooltip-tooltipPlacementLeft", - "tooltipPlacementRight": "MuiTooltip-tooltipPlacementRight", - "tooltipPlacementTop": "MuiTooltip-tooltipPlacementTop", - "touch": "MuiTooltip-touch", + "modifiers": Object { + "arrow": Object { + "element": null, + "enabled": false, + }, + }, } } + transition={true} + /> + + + + + + + - - - -
- - - - - - - -
-
-
-
-
- -
- -
- - } - className="MuiTooltip-popper" - id={null} - open={false} - placement="bottom" - popperOptions={ - Object { - "modifiers": Object { - "arrow": Object { - "element": null, - "enabled": false, - }, + + + + + + +
+ + + + + + } + className="MuiTooltip-popper" + id={null} + open={false} + placement="bottom" + popperOptions={ + Object { + "modifiers": Object { + "arrow": Object { + "element": null, + "enabled": false, }, - } + }, } - transition={true} - /> -
-
-
-
- - - - + } + transition={true} + /> + + + + + + +
`; @@ -437,35 +430,10 @@ exports[`test Developers should render the component for maintainers with items text-transform: capitalize; } -.emotion-12 { - margin: 10px 0 10px 0; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap; -} - -.emotion-12 > * { +.emotion-8 > * { margin: 5px; } -.emotion-8 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - @@ -527,336 +495,354 @@ exports[`test Developers should render the component for maintainers with items - -
+ -
- - - - - - - - -
- - - - - - - -
-
-
-
-
- -
- -
- - } - className="MuiTooltip-popper" - id={null} - open={false} - placement="bottom" - popperOptions={ - Object { - "modifiers": Object { - "arrow": Object { - "element": null, - "enabled": false, - }, - }, - } - } - transition={true} - /> -
-
-
-
-
-
-
- - - - - + + + + +
+ + + + + + + } + className="MuiTooltip-popper" + id={null} + open={false} + placement="bottom" + popperOptions={ Object { - "arrow": "MuiTooltip-arrow", - "popper": "MuiTooltip-popper", - "popperArrow": "MuiTooltip-popperArrow", - "popperInteractive": "MuiTooltip-popperInteractive", - "tooltip": "MuiTooltip-tooltip", - "tooltipArrow": "MuiTooltip-tooltipArrow", - "tooltipPlacementBottom": "MuiTooltip-tooltipPlacementBottom", - "tooltipPlacementLeft": "MuiTooltip-tooltipPlacementLeft", - "tooltipPlacementRight": "MuiTooltip-tooltipPlacementRight", - "tooltipPlacementTop": "MuiTooltip-tooltipPlacementTop", - "touch": "MuiTooltip-touch", + "modifiers": Object { + "arrow": Object { + "element": null, + "enabled": false, + }, + }, } } + transition={true} + /> + + + + + + + - - - -
- - - - - - - -
-
-
-
-
- -
- -
- - } - className="MuiTooltip-popper" - id={null} - open={false} - placement="bottom" - popperOptions={ - Object { - "modifiers": Object { - "arrow": Object { - "element": null, - "enabled": false, - }, + + + + + + +
+ + + + + + } + className="MuiTooltip-popper" + id={null} + open={false} + placement="bottom" + popperOptions={ + Object { + "modifiers": Object { + "arrow": Object { + "element": null, + "enabled": false, }, - } + }, } - transition={true} - /> -
-
-
- - - - -
+ } + transition={true} + /> + + + + + + +
`; diff --git a/src/components/Developers/get-unique-developer-values.ts b/src/components/Developers/get-unique-developer-values.ts new file mode 100644 index 0000000..8c963bf --- /dev/null +++ b/src/components/Developers/get-unique-developer-values.ts @@ -0,0 +1,12 @@ +import { Developer } from '../../../types/packageMeta'; + +function getUniqueDeveloperValues(developers?: Array): undefined | Array { + if (!developers) return; + return developers.reduce( + (accumulator: Array, current: Developer) => + accumulator.some(developer => developer.email === current.email) ? accumulator : [...accumulator, current], + [] + ); +} + +export default getUniqueDeveloperValues; diff --git a/src/components/Developers/index.ts b/src/components/Developers/index.ts index fb3ef86..27846f2 100644 --- a/src/components/Developers/index.ts +++ b/src/components/Developers/index.ts @@ -1 +1 @@ -export { default } from './Developers'; +export { default, DeveloperType } from './Developers'; diff --git a/types/packageMeta.ts b/types/packageMeta.ts index 0030e8f..4d250c1 100644 --- a/types/packageMeta.ts +++ b/types/packageMeta.ts @@ -24,9 +24,16 @@ export interface PackageMetaInterface { type?: string; url?: string; }; + maintainers?: Array; + contributors?: Array; }; _uplinks: {}; } +export interface Developer { + name: string; + email: string; + avatar: string; +} interface LicenseInterface { type: string;