From f84fd79c5b37f27f226acadaca4c3c81eb2e4fb8 Mon Sep 17 00:00:00 2001 From: Priscila Oliveira Date: Thu, 3 Oct 2019 18:17:04 +0200 Subject: [PATCH] fix: detailContainer Component - Replaced class by func. comp (#130) * refactor: coverted class comp. into func.comp * refactor: added forward ref comp. * fix: fixed external link color * fix: fixed typo * refactor: applied feedbacks --- src/components/ActionBar/ActionBar.tsx | 2 +- src/components/AutoComplete/styles.tsx | 3 +- .../AvatarTooltip/AvatarTooltip.tsx | 3 +- .../CopyToClipBoard/CopyToClipBoard.tsx | 2 +- src/components/CopyToClipBoard/styles.ts | 2 +- src/components/Dependencies/Dependencies.tsx | 4 - .../DetailContainer/DetailContainer.test.tsx | 13 + .../DetailContainer/DetailContainer.tsx | 96 +-- .../DetailContainerContent.tsx | 30 + .../DetailContainerContentReadme.tsx | 17 + .../DetailContainer/DetailContainerTabs.tsx | 37 + .../DetailContainer.test.tsx.snap | 98 +++ src/components/DetailContainer/styles.ts | 7 - src/components/DetailContainer/tabs.ts | 6 + src/components/DetailContainer/types.ts | 7 - .../__snapshots__/Developers.test.tsx.snap | 732 ++++++++++++------ src/components/Header/Header.tsx | 27 +- .../Header/__snapshots__/Header.test.tsx.snap | 4 +- src/components/Header/styles.ts | 10 +- src/components/Package/Package.tsx | 2 +- src/components/Package/styles.ts | 2 +- src/components/TextField/TextField.tsx | 14 - src/muiComponents/IconButton/IconButton.tsx | 12 + src/muiComponents/IconButton/index.ts | 1 + .../TextField/TextField.test.tsx | 0 src/muiComponents/TextField/TextField.tsx | 22 + .../__snapshots__/TextField.test.tsx.snap | 0 .../TextField/index.ts | 0 src/muiComponents/Tooltip/Tooltip.tsx | 13 + src/muiComponents/Tooltip/index.ts | 1 + 30 files changed, 824 insertions(+), 343 deletions(-) create mode 100644 src/components/DetailContainer/DetailContainer.test.tsx create mode 100644 src/components/DetailContainer/DetailContainerContent.tsx create mode 100644 src/components/DetailContainer/DetailContainerContentReadme.tsx create mode 100644 src/components/DetailContainer/DetailContainerTabs.tsx create mode 100644 src/components/DetailContainer/__snapshots__/DetailContainer.test.tsx.snap delete mode 100644 src/components/DetailContainer/styles.ts create mode 100644 src/components/DetailContainer/tabs.ts delete mode 100644 src/components/DetailContainer/types.ts delete mode 100644 src/components/TextField/TextField.tsx create mode 100644 src/muiComponents/IconButton/IconButton.tsx create mode 100644 src/muiComponents/IconButton/index.ts rename src/{components => muiComponents}/TextField/TextField.test.tsx (100%) create mode 100644 src/muiComponents/TextField/TextField.tsx rename src/{components => muiComponents}/TextField/__snapshots__/TextField.test.tsx.snap (100%) rename src/{components => muiComponents}/TextField/index.ts (100%) create mode 100644 src/muiComponents/Tooltip/Tooltip.tsx create mode 100644 src/muiComponents/Tooltip/index.ts diff --git a/src/components/ActionBar/ActionBar.tsx b/src/components/ActionBar/ActionBar.tsx index ea02107..bee45ec 100644 --- a/src/components/ActionBar/ActionBar.tsx +++ b/src/components/ActionBar/ActionBar.tsx @@ -4,12 +4,12 @@ import BugReportIcon from '@material-ui/icons/BugReport'; import DownloadIcon from '@material-ui/icons/CloudDownload'; import HomeIcon from '@material-ui/icons/Home'; import List from '@material-ui/core/List'; -import Tooltip from '@material-ui/core/Tooltip'; import { DetailContextConsumer, VersionPageConsumerProps } from '../../pages/Version'; import { Fab, ActionListItem } from './styles'; import { isURL, extractFileName, downloadFile } from '../../utils/url'; import api from '../../utils/api'; +import Tooltip from '../../muiComponents/Tooltip'; export interface Action { icon: string; diff --git a/src/components/AutoComplete/styles.tsx b/src/components/AutoComplete/styles.tsx index 9c296f4..a46dc47 100644 --- a/src/components/AutoComplete/styles.tsx +++ b/src/components/AutoComplete/styles.tsx @@ -2,7 +2,7 @@ import React from 'react'; import styled, { css } from 'react-emotion'; import Paper from '@material-ui/core/Paper'; -import TextField from '../TextField'; +import TextField from '../../muiComponents/TextField'; export interface InputFieldProps { color: string; @@ -17,6 +17,7 @@ export const Wrapper = styled('div')({ }, }); +/* eslint-disable verdaccio/jsx-spread */ export const InputField: React.FC = ({ color, ...others }) => ( { } class Dependencies extends Component { - public state = { - tabPosition: 0, - }; - public render(): ReactElement { return ( diff --git a/src/components/DetailContainer/DetailContainer.test.tsx b/src/components/DetailContainer/DetailContainer.test.tsx new file mode 100644 index 0000000..29784c7 --- /dev/null +++ b/src/components/DetailContainer/DetailContainer.test.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +import { render } from '@testing-library/react'; + +import DetailContainer from './DetailContainer'; + +describe('DetailContainer', () => { + test('renders correctly', () => { + const { container } = render(); + expect(container.firstChild).toMatchSnapshot(); + }); + test.todo('should test click on tabs'); +}); diff --git a/src/components/DetailContainer/DetailContainer.tsx b/src/components/DetailContainer/DetailContainer.tsx index 61f3a6d..89ea18f 100644 --- a/src/components/DetailContainer/DetailContainer.tsx +++ b/src/components/DetailContainer/DetailContainer.tsx @@ -1,77 +1,33 @@ -import React, { Component, ReactElement, Fragment } from 'react'; +import React, { useCallback, useState, ChangeEvent, useContext } from 'react'; +import Box from '@material-ui/core/Box'; -import { DetailContextConsumer, VersionPageConsumerProps } from '../../pages/Version'; -import Readme from '../Readme'; -import Versions from '../Versions'; -import { preventXSS } from '../../utils/sec-utils'; -import Tabs from '@material-ui/core/Tabs'; -import Tab from '@material-ui/core/Tab'; -import { Content } from './styles'; -import Dependencies from '../Dependencies'; -import UpLinks from '../UpLinks'; +import { DetailContext } from '../../pages/Version'; -interface DetailContainerState { - tabPosition: number; -} +import DetailContainerTabs from './DetailContainerTabs'; +import DetailContainerContent from './DetailContainerContent'; +import { TabPosition } from './tabs'; -export const README_LABEL = 'Readme'; -export const DEPS_LABEL = 'Dependencies'; -export const VERSION_LABEL = 'Versions'; -export const UPLINKS_LABEL = 'Uplinks'; +const DetailContainer: React.FC = () => { + const [tabPosition, setTabPosition] = useState(TabPosition.README); + const detailContext = useContext(DetailContext); + const { readMe } = detailContext; -class DetailContainer

extends Component { - public state = { - tabPosition: 0, - }; + const handleChangeTabPosition = useCallback( + (event: ChangeEvent<{}>) => { + event.preventDefault(); + const eventTarget = event.target as HTMLSpanElement; + const chosentab = eventTarget.innerText as TabPosition; + setTabPosition(TabPosition[chosentab]); + }, + [setTabPosition] + ); - public render(): ReactElement { - return ( - - {context => { - return this.renderTabs(context as VersionPageConsumerProps); - }} - - ); - } - - private handleChange = (event: React.ChangeEvent<{}>, tabPosition: number) => { - event.preventDefault(); - this.setState({ tabPosition }); - }; - - private renderListTabs(tabPosition: number): React.ReactElement { - return ( - - - - - - - ); - } - - private renderTabs = ({ readMe }) => { - const { tabPosition } = this.state; - - return ( - - - {this.renderListTabs(tabPosition)} -
- {tabPosition === 0 && this.renderReadme(readMe)} - {tabPosition === 1 && } - {tabPosition === 2 && } - {tabPosition === 3 && } -
-
- ); - }; - - private renderReadme = (readMe: string): ReactElement => { - const encodedReadme = preventXSS(readMe); - - return ; - }; -} + return ( + + + + + ); +}; export default DetailContainer; diff --git a/src/components/DetailContainer/DetailContainerContent.tsx b/src/components/DetailContainer/DetailContainerContent.tsx new file mode 100644 index 0000000..94ffee4 --- /dev/null +++ b/src/components/DetailContainer/DetailContainerContent.tsx @@ -0,0 +1,30 @@ +import React from 'react'; + +import Dependencies from '../Dependencies'; +import UpLinks from '../UpLinks'; +import Versions from '../Versions'; + +import DetailContainerContentReadme from './DetailContainerContentReadme'; +import { TabPosition } from './tabs'; + +interface Props { + tabPosition: TabPosition; + readDescription?: string; +} + +const DetailContainerContent: React.FC = ({ tabPosition, readDescription }) => { + switch (tabPosition) { + case TabPosition.README: + return ; + case TabPosition.UPLINKS: + return ; + case TabPosition.VERSIONS: + return ; + case TabPosition.DEPENDENCIES: + return ; + default: + return null; + } +}; + +export default DetailContainerContent; diff --git a/src/components/DetailContainer/DetailContainerContentReadme.tsx b/src/components/DetailContainer/DetailContainerContentReadme.tsx new file mode 100644 index 0000000..66fbab8 --- /dev/null +++ b/src/components/DetailContainer/DetailContainerContentReadme.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +import { preventXSS } from '../../utils/sec-utils'; + +import Readme from '../Readme'; + +interface Props { + description?: string; +} + +const DetailContainerContentReadme: React.FC = ({ description }) => { + if (!description) return null; + const encodedReadme = preventXSS(description); + return ; +}; + +export default DetailContainerContentReadme; diff --git a/src/components/DetailContainer/DetailContainerTabs.tsx b/src/components/DetailContainer/DetailContainerTabs.tsx new file mode 100644 index 0000000..031ba67 --- /dev/null +++ b/src/components/DetailContainer/DetailContainerTabs.tsx @@ -0,0 +1,37 @@ +import React, { ChangeEvent, useState, useEffect } from 'react'; +import { default as MuiTabs } from '@material-ui/core/Tabs'; +import Tab from '@material-ui/core/Tab'; +import styled from 'react-emotion'; + +import { TabPosition } from './tabs'; + +interface Props { + tabPosition: TabPosition; + onChangeTabPosition: (event: ChangeEvent<{}>) => void; +} + +const Tabs = styled(MuiTabs)({ + marginBottom: 16, +}); + +const getTabIndex = (tabPosition: TabPosition): number => Object.keys(TabPosition).findIndex(position => position === String(tabPosition).toUpperCase()); + +const DetailContainerTabs: React.FC = ({ tabPosition, onChangeTabPosition }) => { + const [tabPositionIndex, setTabPositionIndex] = useState(0); + + useEffect(() => { + const tabIndex = getTabIndex(tabPosition); + setTabPositionIndex(tabIndex); + }, [tabPosition]); + + return ( + + + + + + + ); +}; + +export default DetailContainerTabs; diff --git a/src/components/DetailContainer/__snapshots__/DetailContainer.test.tsx.snap b/src/components/DetailContainer/__snapshots__/DetailContainer.test.tsx.snap new file mode 100644 index 0000000..6ac4a04 --- /dev/null +++ b/src/components/DetailContainer/__snapshots__/DetailContainer.test.tsx.snap @@ -0,0 +1,98 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DetailContainer renders correctly 1`] = ` +

+
+
+
+ + + + +
+ +
+
+
+`; diff --git a/src/components/DetailContainer/styles.ts b/src/components/DetailContainer/styles.ts deleted file mode 100644 index af9dc91..0000000 --- a/src/components/DetailContainer/styles.ts +++ /dev/null @@ -1,7 +0,0 @@ -import styled from 'react-emotion'; - -export const Content = styled('div')({ - '&&': { - padding: '15px', - }, -}); diff --git a/src/components/DetailContainer/tabs.ts b/src/components/DetailContainer/tabs.ts new file mode 100644 index 0000000..26470f8 --- /dev/null +++ b/src/components/DetailContainer/tabs.ts @@ -0,0 +1,6 @@ +export enum TabPosition { + README = 'Readme', + DEPENDENCIES = 'Dependencies', + VERSIONS = 'Versions', + UPLINKS = 'Uplinks', +} diff --git a/src/components/DetailContainer/types.ts b/src/components/DetailContainer/types.ts deleted file mode 100644 index b83774b..0000000 --- a/src/components/DetailContainer/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ReactNode } from 'react'; - -export interface Props { - children: ReactNode; - open: boolean; - onClose: () => void; -} diff --git a/src/components/Developers/__snapshots__/Developers.test.tsx.snap b/src/components/Developers/__snapshots__/Developers.test.tsx.snap index 009d228..6548d26 100644 --- a/src/components/Developers/__snapshots__/Developers.test.tsx.snap +++ b/src/components/Developers/__snapshots__/Developers.test.tsx.snap @@ -72,79 +72,150 @@ exports[`test Developers should render the component for contributors with items name="dmethvin" version="1.0.0" > - - - - - -
- - - -
- - } - className="MuiTooltip-popper" - id={null} - open={false} - placement="bottom" - transition={true} - /> - - + className="MuiFormControl-root MuiTextField-root" + title="dmethvin" + > + + + + +
+ +
+
+
+
+
+
+ + + + + @@ -159,79 +230,150 @@ exports[`test Developers should render the component for contributors with items name="mgol" version="1.0.0" > - - - - - -
- - - -
- - } - className="MuiTooltip-popper" - id={null} - open={false} - placement="bottom" - transition={true} - /> - - + className="MuiFormControl-root MuiTextField-root" + title="mgol" + > + + + + +
+ +
+
+
+
+
+
+ + + + + @@ -312,79 +454,150 @@ exports[`test Developers should render the component for maintainers with items name="dmethvin" version="1.0.0" > - - - - - -
- - - -
- - } - className="MuiTooltip-popper" - id={null} - open={false} - placement="bottom" - transition={true} - /> - - + className="MuiFormControl-root MuiTextField-root" + title="dmethvin" + > + + + + +
+ +
+
+
+
+
+
+ + + + + @@ -399,79 +612,150 @@ exports[`test Developers should render the component for maintainers with items name="mgol" version="1.0.0" > - - - - - -
- - - -
- - } - className="MuiTooltip-popper" - id={null} - open={false} - placement="bottom" - transition={true} - /> - - + className="MuiFormControl-root MuiTextField-root" + title="mgol" + > + + + + +
+ +
+
+
+
+
+
+ + + + + diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 4cbea88..0b35a7f 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -3,24 +3,35 @@ import { Link } from 'react-router-dom'; import { css } from 'emotion'; import Button from '@material-ui/core/Button'; -import IconButton from '@material-ui/core/IconButton'; import MenuItem from '@material-ui/core/MenuItem'; import Menu from '@material-ui/core/Menu'; import Info from '@material-ui/icons/Info'; import Help from '@material-ui/icons/Help'; -import Tooltip from '@material-ui/core/Tooltip'; import AccountCircle from '@material-ui/icons/AccountCircle'; import { default as IconSearch } from '@material-ui/icons/Search'; import { getRegistryURL } from '../../utils/url'; -import ExternalLink from '../Link'; import Logo from '../Logo'; import RegistryInfoDialog from '../RegistryInfoDialog/RegistryInfoDialog'; import Label from '../Label/Label'; import Search from '../Search/Search'; import RegistryInfoContent from '../RegistryInfoContent/RegistryInfoContent'; -import { Greetings, NavBar, InnerNavBar, MobileNavBar, InnerMobileNavBar, LeftSide, RightSide, IconSearchButton, SearchWrapper } from './styles'; +import IconButton from '../../muiComponents/IconButton'; +import Tooltip from '../../muiComponents/Tooltip'; + +import { + Greetings, + NavBar, + InnerNavBar, + MobileNavBar, + InnerMobileNavBar, + LeftSide, + RightSide, + IconSearchButton, + SearchWrapper, + StyledExternalLink, +} from './styles'; interface Props { logo?: string; @@ -174,9 +185,11 @@ class Header extends Component { case 'help': content = ( // @ts-ignore - - - + + + + + ); break; case 'info': diff --git a/src/components/Header/__snapshots__/Header.test.tsx.snap b/src/components/Header/__snapshots__/Header.test.tsx.snap index 7b03115..0c3371b 100644 --- a/src/components/Header/__snapshots__/Header.test.tsx.snap +++ b/src/components/Header/__snapshots__/Header.test.tsx.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`
component with logged in state should load the component in logged in state 1`] = `"
"`; +exports[`
component with logged in state should load the component in logged in state 1`] = `"
"`; -exports[`
component with logged out state should load the component in logged out state 1`] = `"
"`; +exports[`
component with logged out state should load the component in logged out state 1`] = `"
"`; diff --git a/src/components/Header/styles.ts b/src/components/Header/styles.ts index ad7d9c1..dcbc49a 100644 --- a/src/components/Header/styles.ts +++ b/src/components/Header/styles.ts @@ -1,11 +1,13 @@ import styled, { css } from 'react-emotion'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; import colors from '../../utils/styles/colors'; import mq from '../../utils/styles/media'; +import IconButton from '../../muiComponents/IconButton'; +import ExternalLink from '../Link'; + export const InnerNavBar = styled(Toolbar)({ '&&': { justifyContent: 'space-between', @@ -108,3 +110,9 @@ export const NavBar = styled(AppBar)` }}; } `; + +export const StyledExternalLink = styled(ExternalLink)({ + '&&': { + color: 'white', + }, +}); diff --git a/src/components/Package/Package.tsx b/src/components/Package/Package.tsx index 7ae007e..ebf07ba 100644 --- a/src/components/Package/Package.tsx +++ b/src/components/Package/Package.tsx @@ -4,12 +4,12 @@ import BugReport from '@material-ui/icons/BugReport'; import Grid from '@material-ui/core/Grid'; import HomeIcon from '@material-ui/icons/Home'; import ListItem from '@material-ui/core/ListItem'; -import Tooltip from '@material-ui/core/Tooltip'; import { PackageMetaInterface } from 'types/packageMeta'; import Tag from '../Tag'; import fileSizeSI from '../../utils/file-size'; import { formatDate, formatDateDistance } from '../../utils/package'; +import Tooltip from '../../muiComponents/Tooltip'; import { Author, Avatar, diff --git a/src/components/Package/styles.ts b/src/components/Package/styles.ts index 6bf16f7..ac3bdf6 100644 --- a/src/components/Package/styles.ts +++ b/src/components/Package/styles.ts @@ -4,7 +4,6 @@ import { Link } from 'react-router-dom'; import Grid from '@material-ui/core/Grid'; import List from '@material-ui/core/List'; import ListItemText from '@material-ui/core/ListItemText'; -import MuiIconButton from '@material-ui/core/IconButton'; import Photo from '@material-ui/core/Avatar'; import Typography from '@material-ui/core/Typography'; @@ -13,6 +12,7 @@ import Ico from '../Icon'; import Label from '../Label'; import colors from '../../utils/styles/colors'; import { fontWeight } from '../../utils/styles/sizes'; +import { default as MuiIconButton } from '../../muiComponents/IconButton'; export const OverviewItem = styled('span')` && { diff --git a/src/components/TextField/TextField.tsx b/src/components/TextField/TextField.tsx deleted file mode 100644 index 5e9875b..0000000 --- a/src/components/TextField/TextField.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { default as TextFieldMaterialUI, TextFieldProps } from '@material-ui/core/TextField'; -import React from 'react'; - -const TextField: React.FC = ({ InputProps, classes, ...other }) => ( - -); - -export default TextField; diff --git a/src/muiComponents/IconButton/IconButton.tsx b/src/muiComponents/IconButton/IconButton.tsx new file mode 100644 index 0000000..9b344d5 --- /dev/null +++ b/src/muiComponents/IconButton/IconButton.tsx @@ -0,0 +1,12 @@ +import React, { forwardRef } from 'react'; +import { default as MuiIconButton, IconButtonProps } from '@material-ui/core/IconButton'; + +type IconButtonRef = HTMLElementTagNameMap['button']; + +/* eslint-disable verdaccio/jsx-spread */ +// eslint-disable-next-line react/display-name +const IconButton = forwardRef(function IconButton(props, ref) { + return ; +}); + +export default IconButton; diff --git a/src/muiComponents/IconButton/index.ts b/src/muiComponents/IconButton/index.ts new file mode 100644 index 0000000..86c5e51 --- /dev/null +++ b/src/muiComponents/IconButton/index.ts @@ -0,0 +1 @@ +export { default } from './IconButton'; diff --git a/src/components/TextField/TextField.test.tsx b/src/muiComponents/TextField/TextField.test.tsx similarity index 100% rename from src/components/TextField/TextField.test.tsx rename to src/muiComponents/TextField/TextField.test.tsx diff --git a/src/muiComponents/TextField/TextField.tsx b/src/muiComponents/TextField/TextField.tsx new file mode 100644 index 0000000..c26edd5 --- /dev/null +++ b/src/muiComponents/TextField/TextField.tsx @@ -0,0 +1,22 @@ +import React, { forwardRef } from 'react'; +import { default as TextFieldMaterialUI, TextFieldProps } from '@material-ui/core/TextField'; + +// The default element type of MUI's TextField is 'div' +type TextFieldRef = HTMLElementTagNameMap['div']; + +/* eslint-disable verdaccio/jsx-spread */ +// eslint-disable-next-line react/display-name +const TextField = forwardRef(function ToolTip({ InputProps, classes, ...props }, ref) { + return ( + + ); +}); + +export default TextField; diff --git a/src/components/TextField/__snapshots__/TextField.test.tsx.snap b/src/muiComponents/TextField/__snapshots__/TextField.test.tsx.snap similarity index 100% rename from src/components/TextField/__snapshots__/TextField.test.tsx.snap rename to src/muiComponents/TextField/__snapshots__/TextField.test.tsx.snap diff --git a/src/components/TextField/index.ts b/src/muiComponents/TextField/index.ts similarity index 100% rename from src/components/TextField/index.ts rename to src/muiComponents/TextField/index.ts diff --git a/src/muiComponents/Tooltip/Tooltip.tsx b/src/muiComponents/Tooltip/Tooltip.tsx new file mode 100644 index 0000000..b0f6890 --- /dev/null +++ b/src/muiComponents/Tooltip/Tooltip.tsx @@ -0,0 +1,13 @@ +import React, { forwardRef } from 'react'; +import { default as MuiTooltip, TooltipProps } from '@material-ui/core/Tooltip'; + +// The default element type of MUI's Tooltip is 'div' and the change of this prop is not allowed +type TooltipRef = HTMLElementTagNameMap['div']; + +/* eslint-disable verdaccio/jsx-spread */ +// eslint-disable-next-line react/display-name +const Tooltip = forwardRef(function ToolTip(props, ref) { + return ; +}); + +export default Tooltip; diff --git a/src/muiComponents/Tooltip/index.ts b/src/muiComponents/Tooltip/index.ts new file mode 100644 index 0000000..cdc0fab --- /dev/null +++ b/src/muiComponents/Tooltip/index.ts @@ -0,0 +1 @@ +export { default } from './Tooltip';