forked from sombochea/verdaccio-ui
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
This commit is contained in:
committed by
Juan Picado @jotadeveloper
parent
28c982a7da
commit
f84fd79c5b
13
src/components/DetailContainer/DetailContainer.test.tsx
Normal file
13
src/components/DetailContainer/DetailContainer.test.tsx
Normal file
@@ -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(<DetailContainer />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
test.todo('should test click on tabs');
|
||||
});
|
||||
@@ -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<P> extends Component<P, DetailContainerState> {
|
||||
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<HTMLElement> {
|
||||
return (
|
||||
<DetailContextConsumer>
|
||||
{context => {
|
||||
return this.renderTabs(context as VersionPageConsumerProps);
|
||||
}}
|
||||
</DetailContextConsumer>
|
||||
);
|
||||
}
|
||||
|
||||
private handleChange = (event: React.ChangeEvent<{}>, tabPosition: number) => {
|
||||
event.preventDefault();
|
||||
this.setState({ tabPosition });
|
||||
};
|
||||
|
||||
private renderListTabs(tabPosition: number): React.ReactElement<HTMLElement> {
|
||||
return (
|
||||
<Tabs indicatorColor={'primary'} onChange={this.handleChange} textColor={'primary'} value={tabPosition} variant={'fullWidth'}>
|
||||
<Tab data-testid={'readme-tab'} id={'readme-tab'} label={README_LABEL} />
|
||||
<Tab data-testid={'dependencies-tab'} id={'dependencies-tab'} label={DEPS_LABEL} />
|
||||
<Tab data-testid={'versions-tab'} id={'versions-tab'} label={VERSION_LABEL} />
|
||||
<Tab data-testid={'uplinks-tab'} id={'uplinks-tab'} label={UPLINKS_LABEL} />
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
private renderTabs = ({ readMe }) => {
|
||||
const { tabPosition } = this.state;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Content>
|
||||
{this.renderListTabs(tabPosition)}
|
||||
<br />
|
||||
{tabPosition === 0 && this.renderReadme(readMe)}
|
||||
{tabPosition === 1 && <Dependencies />}
|
||||
{tabPosition === 2 && <Versions />}
|
||||
{tabPosition === 3 && <UpLinks />}
|
||||
</Content>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
private renderReadme = (readMe: string): ReactElement<HTMLElement> => {
|
||||
const encodedReadme = preventXSS(readMe);
|
||||
|
||||
return <Readme description={encodedReadme} />;
|
||||
};
|
||||
}
|
||||
return (
|
||||
<Box component="div" display="flex" flexDirection="column" padding={2}>
|
||||
<DetailContainerTabs onChangeTabPosition={handleChangeTabPosition} tabPosition={tabPosition} />
|
||||
<DetailContainerContent readDescription={readMe} tabPosition={tabPosition} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default DetailContainer;
|
||||
|
||||
30
src/components/DetailContainer/DetailContainerContent.tsx
Normal file
30
src/components/DetailContainer/DetailContainerContent.tsx
Normal file
@@ -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<Props> = ({ tabPosition, readDescription }) => {
|
||||
switch (tabPosition) {
|
||||
case TabPosition.README:
|
||||
return <DetailContainerContentReadme description={readDescription} />;
|
||||
case TabPosition.UPLINKS:
|
||||
return <UpLinks />;
|
||||
case TabPosition.VERSIONS:
|
||||
return <Versions />;
|
||||
case TabPosition.DEPENDENCIES:
|
||||
return <Dependencies />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default DetailContainerContent;
|
||||
@@ -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<Props> = ({ description }) => {
|
||||
if (!description) return null;
|
||||
const encodedReadme = preventXSS(description);
|
||||
return <Readme description={encodedReadme} />;
|
||||
};
|
||||
|
||||
export default DetailContainerContentReadme;
|
||||
37
src/components/DetailContainer/DetailContainerTabs.tsx
Normal file
37
src/components/DetailContainer/DetailContainerTabs.tsx
Normal file
@@ -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<Props> = ({ tabPosition, onChangeTabPosition }) => {
|
||||
const [tabPositionIndex, setTabPositionIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const tabIndex = getTabIndex(tabPosition);
|
||||
setTabPositionIndex(tabIndex);
|
||||
}, [tabPosition]);
|
||||
|
||||
return (
|
||||
<Tabs indicatorColor={'primary'} onChange={onChangeTabPosition} textColor={'primary'} value={tabPositionIndex} variant={'fullWidth'}>
|
||||
<Tab data-testid={'readme-tab'} id={'readme-tab'} label={TabPosition.README} />
|
||||
<Tab data-testid={'dependencies-tab'} id={'dependencies-tab'} label={TabPosition.DEPENDENCIES} />
|
||||
<Tab data-testid={'versions-tab'} id={'versions-tab'} label={TabPosition.VERSIONS} />
|
||||
<Tab data-testid={'uplinks-tab'} id={'uplinks-tab'} label={TabPosition.UPLINKS} />
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
export default DetailContainerTabs;
|
||||
@@ -0,0 +1,98 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DetailContainer renders correctly 1`] = `
|
||||
<div
|
||||
class="MuiBox-root MuiBox-root-2"
|
||||
>
|
||||
<div
|
||||
class="MuiTabs-root css-1qm1lh emotion-0"
|
||||
>
|
||||
<div
|
||||
class="MuiTabs-scroller MuiTabs-fixed"
|
||||
style="overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
class="MuiTabs-flexContainer"
|
||||
role="tablist"
|
||||
>
|
||||
<button
|
||||
aria-selected="true"
|
||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary Mui-selected MuiTab-fullWidth"
|
||||
data-testid="readme-tab"
|
||||
id="readme-tab"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
>
|
||||
Readme
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
aria-selected="false"
|
||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth"
|
||||
data-testid="dependencies-tab"
|
||||
id="dependencies-tab"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
>
|
||||
Dependencies
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
aria-selected="false"
|
||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth"
|
||||
data-testid="versions-tab"
|
||||
id="versions-tab"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
>
|
||||
Versions
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
aria-selected="false"
|
||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth"
|
||||
data-testid="uplinks-tab"
|
||||
id="uplinks-tab"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
>
|
||||
Uplinks
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<span
|
||||
class="PrivateTabIndicator-root-27 PrivateTabIndicator-colorPrimary-28 MuiTabs-indicator"
|
||||
style="left: 0px; width: 0px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,7 +0,0 @@
|
||||
import styled from 'react-emotion';
|
||||
|
||||
export const Content = styled('div')({
|
||||
'&&': {
|
||||
padding: '15px',
|
||||
},
|
||||
});
|
||||
6
src/components/DetailContainer/tabs.ts
Normal file
6
src/components/DetailContainer/tabs.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export enum TabPosition {
|
||||
README = 'Readme',
|
||||
DEPENDENCIES = 'Dependencies',
|
||||
VERSIONS = 'Versions',
|
||||
UPLINKS = 'Uplinks',
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface Props {
|
||||
children: ReactNode;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
Reference in New Issue
Block a user