Skip to content

Commit

Permalink
Merge pull request conventional-changelog#115 from verdaccio/hooks-fi…
Browse files Browse the repository at this point in the history
…rst-step

hooks first step
  • Loading branch information
juanpicado authored Aug 15, 2019
2 parents 542212a + 3d7b230 commit d81b610
Show file tree
Hide file tree
Showing 13 changed files with 3,019 additions and 58 deletions.
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"prettier",
"verdaccio",
"jsx-a11y",
"codeceptjs"
"codeceptjs",
"react-hooks"
],
"settings": {
"react": {
Expand Down Expand Up @@ -107,6 +108,8 @@
2,
"always"
],
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"verdaccio/jsx-no-style": ["warn"],
"verdaccio/jsx-spread": ["warn"],
"jest/expect-expect": 0,
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@material-ui/core": "3.9.3",
"@material-ui/icons": "3.0.2",
"@octokit/rest": "16.28.7",
"@testing-library/react": "9.1.0",
"@types/enzyme": "3.10.3",
"@types/lodash": "4.14.136",
"@types/material-ui": "0.21.6",
Expand Down Expand Up @@ -45,6 +46,7 @@
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-prettier": "3.1.0",
"eslint-plugin-react": "7.14.3",
"eslint-plugin-react-hooks": "1.7.0",
"eslint-plugin-verdaccio": "2.0.0",
"file-loader": "4.2.0",
"friendly-errors-webpack-plugin": "1.7.0",
Expand Down
66 changes: 65 additions & 1 deletion partials/storage/jquery/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4579,6 +4579,70 @@
"tarball": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz"
},
"maintainers": [
{
"name": "dmethvin",
"email": "dave.methvin@gmail.com"
},
{
"name": "mgol",
"email": "m.goleb@gmail.com"
},
{
"name": "scott.gonzalez",
"email": "scott.gonzalez@gmail.com"
},
{
"name": "timmywil",
"email": "4timmywil@gmail.com"
},
{
"name": "dmethvin",
"email": "dave.methvin@gmail.com"
},
{
"name": "mgol",
"email": "m.goleb@gmail.com"
},
{
"name": "scott.gonzalez",
"email": "scott.gonzalez@gmail.com"
},
{
"name": "timmywil",
"email": "4timmywil@gmail.com"
},
{
"name": "dmethvin",
"email": "dave.methvin@gmail.com"
},
{
"name": "mgol",
"email": "m.goleb@gmail.com"
},
{
"name": "scott.gonzalez",
"email": "scott.gonzalez@gmail.com"
},
{
"name": "timmywil",
"email": "4timmywil@gmail.com"
},
{
"name": "dmethvin",
"email": "dave.methvin@gmail.com"
},
{
"name": "mgol",
"email": "m.goleb@gmail.com"
},
{
"name": "scott.gonzalez",
"email": "scott.gonzalez@gmail.com"
},
{
"name": "timmywil",
"email": "4timmywil@gmail.com"
},
{
"name": "dmethvin",
"email": "dave.methvin@gmail.com"
Expand Down Expand Up @@ -4916,4 +4980,4 @@
},
"_rev": "60-fed4915c27b9c1e6",
"readme": "# jQuery\n\n> jQuery is a fast, small, and feature-rich JavaScript library.\n\nFor information on how to get started and how to use jQuery, please see [jQuery's documentation](http://api.jquery.com/).\nFor source files and issues, please visit the [jQuery repo](https://github.com/jquery/jquery).\n\nIf upgrading, please see the [blog post for 3.3.1](https://blog.jquery.com/2017/03/20/jquery-3.3.1-now-available/). This includes notable differences from the previous version and a more readable changelog.\n\n## Including jQuery\n\nBelow are some of the most common ways to include jQuery.\n\n### Browser\n\n#### Script tag\n\n```html\n<script src=\"https://code.jquery.com/jquery-3.3.1.min.js\"></script>\n```\n\n#### Babel\n\n[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively.\n\n```js\nimport $ from \"jquery\";\n```\n\n#### Browserify/Webpack\n\nThere are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project's documention. In the script, including jQuery will usually look like this...\n\n```js\nvar $ = require(\"jquery\");\n```\n\n#### AMD (Asynchronous Module Definition)\n\nAMD is a module format built for the browser. For more information, we recommend [require.js' documentation](http://requirejs.org/docs/whyamd.html).\n\n```js\ndefine([\"jquery\"], function($) {\n\n});\n```\n\n### Node\n\nTo include jQuery in [Node](nodejs.org), first install with npm.\n\n```sh\nnpm install jquery\n```\n\nFor jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes.\n\n```js\nrequire(\"jsdom\").env(\"\", function(err, window) {\n\tif (err) {\n\t\tconsole.error(err);\n\t\treturn;\n\t}\n\n\tvar $ = require(\"jquery\")(window);\n});\n```"
}
}
32 changes: 32 additions & 0 deletions src/components/AvatarTooltip/AvatarTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { FC } from 'react';

import Avatar from '@material-ui/core/Avatar';
import Tooltip from '@material-ui/core/Tooltip';
import { isEmail } from '../../utils/url';

export interface AvatarDeveloper {
name: string;
packageName: string;
version: string;
avatar: string;
email: string;
}

const AvatarTooltip: FC<AvatarDeveloper> = ({ name, packageName, version, avatar, email }) => {
const avatarComponent = <Avatar aria-label={name} src={avatar} />;
function renderLinkForMail(email, avatarComponent, packageName, version): JSX.Element {
if (!email || isEmail(email) === false) {
return avatarComponent;
}

return (
<a href={`mailto:${email}?subject=${packageName}@${version}`} target={'_top'}>
{avatarComponent}
</a>
);
}

return <Tooltip title={name}>{renderLinkForMail(email, avatarComponent, packageName, version)}</Tooltip>;
};

export { AvatarTooltip };
4 changes: 4 additions & 0 deletions src/components/AvatarTooltip/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { AvatarTooltip } from './AvatarTooltip';

export { AvatarTooltip };
export default AvatarTooltip;
104 changes: 104 additions & 0 deletions src/components/Developers/Developers.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React from 'react';
import { mount } from 'enzyme';
import Developers, { DevelopersType } from './Developers';
import { Fab } from './styles';
import { DetailContextProvider } from '../../pages/version/Version';

describe('test Developers', () => {
const packageMeta = {
latest: {
packageName: 'foo',
version: '1.0.0',
maintainers: [
{
name: 'dmethvin',
email: 'dave.methvin@gmail.com',
},
{
name: 'mgol',
email: 'm.goleb@gmail.com',
},
],
contributors: [
{
name: 'dmethvin',
email: 'dave.methvin@gmail.com',
},
{
name: 'mgol',
email: 'm.goleb@gmail.com',
},
],
},
};

test('should render the component with no items', () => {
const type: DevelopersType = 'maintainers';
const packageMeta = {
latest: {},
};
const wrapper = mount(
// @ts-ignore
<DetailContextProvider value={{ packageMeta }}>
<Developers type={type} />
</DetailContextProvider>
);

expect(wrapper).toMatchSnapshot();
});

test('should render the component for maintainers with items', () => {
const type: DevelopersType = 'maintainers';
const wrapper = mount(
// @ts-ignore
<DetailContextProvider value={{ packageMeta }}>
<Developers type={type} />
</DetailContextProvider>
);

expect(wrapper).toMatchSnapshot();
});

test('should render the component for contributors with items', () => {
const type: DevelopersType = 'contributors';
const wrapper = mount(
// @ts-ignore
<DetailContextProvider value={{ packageMeta }}>
<Developers type={type} />
</DetailContextProvider>
);

expect(wrapper).toMatchSnapshot();
});

test('should test onClick the component avatar', () => {
const type: DevelopersType = 'contributors';
const packageMeta = {
latest: {
packageName: 'foo',
version: '1.0.0',
contributors: [
{
name: 'dmethvin',
email: 'dave.methvin@gmail.com',
},
{
name: 'dmethvin2',
email: 'dave2.methvin@gmail.com',
},
],
},
};

const wrapper = mount(
// @ts-ignore
<DetailContextProvider value={{ packageMeta }}>
<Developers type={type} visibleMax={1} />
</DetailContextProvider>
);

const item2 = wrapper.find(Fab);
// TODO: I am not sure here how to verify the method inside the component was called.
item2.simulate('click');
});
});
82 changes: 31 additions & 51 deletions src/components/Developers/Developers.tsx
Original file line number Diff line number Diff line change
@@ -1,79 +1,59 @@
import React, { Component } from 'react';

import Avatar from '@material-ui/core/Avatar';
import React, { FC, Fragment } from 'react';
import Add from '@material-ui/icons/Add';
import Tooltip from '@material-ui/core/Tooltip';

import { DetailContextConsumer } from '../../pages/version/Version';
import { DetailContext } from '../../pages/version/Version';
import { AvatarTooltip } from '../AvatarTooltip';
import { Details, Heading, Content, Fab } from './styles';
import { isEmail } from '../../utils/url';

export type DevelopersType = 'contributors' | 'maintainers';

interface Props {
type: 'contributors' | 'maintainers';
}
interface State {
visibleDevs: number;
type: DevelopersType;
visibleMax?: number;
}

class Developers extends Component<Props, State> {
public state = {
visibleDevs: 6,
export const VISIBLE_MAX = 6;

const Developers: FC<Props> = ({ type, visibleMax }) => {
const [visibleDevs, setVisibleDevs] = React.useState<number>(visibleMax || VISIBLE_MAX);
const { packageMeta } = React.useContext(DetailContext);

const handleLoadMore = () => {
setVisibleDevs(visibleDevs + VISIBLE_MAX);
};

public render(): JSX.Element {
return (
<DetailContextConsumer>
{({ packageMeta }) => {
const { type } = this.props;
const developerType = packageMeta && packageMeta.latest[type];
if (!developerType || developerType.length === 0) return null;
return this.renderDevelopers(developerType, packageMeta);
}}
</DetailContextConsumer>
);
}
const renderDeveloperDetails = ({ name, avatar, email }, packageMeta) => {
const { name: packageName, version } = packageMeta.latest;

public handleLoadMore = () => {
this.setState(prev => ({ visibleDevs: prev.visibleDevs + 6 }));
return <AvatarTooltip avatar={avatar} email={email} name={name} packageName={packageName} version={version} />;
};

private renderDevelopers = (developers, packageMeta) => {
const { type } = this.props;
const { visibleDevs } = this.state;
const renderDevelopers = (developers, packageMeta) => {
const listVisibleDevelopers = developers.slice(0, visibleDevs);

return (
<>
<Fragment>
<Heading variant={'subheading'}>{type}</Heading>
<Content>
{developers.slice(0, visibleDevs).map(developer => (
<Details key={developer.email}>{this.renderDeveloperDetails(developer, packageMeta)}</Details>
{listVisibleDevelopers.map(developer => (
<Details key={developer.email}>{renderDeveloperDetails(developer, packageMeta)}</Details>
))}
{visibleDevs < developers.length && (
<Fab onClick={this.handleLoadMore} size="small">
<Fab onClick={handleLoadMore} size="small">
<Add />
</Fab>
)}
</Content>
</>
</Fragment>
);
};

private renderLinkForMail(email, avatarComponent, packageName, version): JSX.Element {
if (!email || isEmail(email) === false) {
return avatarComponent;
}
return (
<a href={`mailto:${email}?subject=${packageName}@${version}`} target={'_top'}>
{avatarComponent}
</a>
);
const developerList = packageMeta && packageMeta.latest[type];
if (!developerList || developerList.length === 0) {
return null;
}

private renderDeveloperDetails = ({ name, avatar, email }, packageMeta) => {
const { name: packageName, version } = packageMeta.latest;

const avatarComponent = <Avatar aria-label={name} src={avatar} />;
return <Tooltip title={name}>{this.renderLinkForMail(email, avatarComponent, packageName, version)}</Tooltip>;
};
}
return renderDevelopers(developerList, packageMeta);
};

export default Developers;
Loading

0 comments on commit d81b610

Please sign in to comment.