diff --git a/package-lock.json b/package-lock.json index bbf910c..99521af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8625,6 +8625,29 @@ "minimist": "^1.2.0" } }, + "jsonp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz", + "integrity": "sha1-pltPoPEL2nGaBUQep7lMVfPhW64=", + "requires": { + "debug": "^2.1.3" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "jsonwebtoken": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", @@ -11756,6 +11779,17 @@ "tiny-warning": "^1.0.0" } }, + "react-share": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/react-share/-/react-share-3.0.1.tgz", + "integrity": "sha512-xo4zjYP78h6zrBN5rlC06bb877js7216KFeZELAZP6sYxVoqmU27ChrfnpKUCL9H8F5PwYXh6DLNdAp+0E17GA==", + "requires": { + "babel-runtime": "^6.26.0", + "classnames": "^2.2.5", + "jsonp": "^0.2.1", + "prop-types": "^15.5.8" + } + }, "react-skeleton-loader": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/react-skeleton-loader/-/react-skeleton-loader-1.0.4.tgz", diff --git a/package.json b/package.json index 6166762..ff43a2e 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "react-pusher": "^0.2.0", "react-redux": "^7.1.1", "react-router-dom": "^5.0.1", + "react-share": "^3.0.1", "react-skeleton-loader": "^1.0.4", "react-spinners": "^0.6.1", "react-tag-input": "^6.4.1", diff --git a/src/components/Icon/index.js b/src/components/Icon/index.js index 21a2e17..73f3534 100644 --- a/src/components/Icon/index.js +++ b/src/components/Icon/index.js @@ -26,6 +26,7 @@ import { faAngleLeft as angleLeft, faAngleUp as angleTop, faAngleDown as angleBottom, + faEllipsisH as options, } from '@fortawesome/free-solid-svg-icons'; const icons = { @@ -46,6 +47,7 @@ const icons = { angleLeft, angleTop, angleBottom, + options, }; const Icon = (props) => { const { name, handleClick } = props; diff --git a/src/e2e/Articles/ShareArticle.js b/src/e2e/Articles/ShareArticle.js new file mode 100644 index 0000000..b260c9d --- /dev/null +++ b/src/e2e/Articles/ShareArticle.js @@ -0,0 +1,33 @@ +module.exports = { + '@tag': ['articles'], + 'User should be able to share articles': (browser) => { + browser + .url('http://localhost:9090/articles/multi-byte-invoice-payment') + .pause(3000) + .assert.visible('div[class="read-article"]') + .pause(500) + .assert.visible('[class="option-icon dropdown"]') + .pause(1000) + .assert.visible('[data-icon="ellipsis-h"]') + .pause(200) + .moveToElement('[data-icon="ellipsis-h"]', 1, 1) + .pause(1000) + .moveToElement('[aria-label="email"]', 1, 1) + .pause(2000) + .moveToElement('[aria-label="twitter"]', 1, 1) + .pause(2000) + .moveToElement('[aria-label="facebook"]', 1, 1) + .pause(2000) + .moveToElement('[aria-label="email"]', 1, 1) + .pause(2000) + .moveToElement('[aria-label="twitter"]', 1, 1) + .pause(1000) + .assert.visible('[aria-label="twitter"]') + .assert.visible('[aria-label="facebook"]') + .assert.visible('[aria-label="email"]') + .pause(1000) + .click('[aria-label="twitter"]') + .pause(5000) + .end(); + }, +}; diff --git a/src/views/Articles/ReadArticle/ReadArticle.js b/src/views/Articles/ReadArticle/ReadArticle.js index 2d04036..5be6ed6 100644 --- a/src/views/Articles/ReadArticle/ReadArticle.js +++ b/src/views/Articles/ReadArticle/ReadArticle.js @@ -1,6 +1,8 @@ +/* eslint-disable jsx-a11y/interactive-supports-focus */ /* eslint-disable react/no-unused-prop-types */ /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ /* eslint-disable jsx-a11y/anchor-is-valid */ +/* eslint-disable jsx-a11y/interactive-supports-focus */ import React, { Component } from 'react'; import jwtDecode from 'jwt-decode'; import PropTypes from 'prop-types'; @@ -9,6 +11,14 @@ import ReactHtmlParser from 'react-html-parser'; import { withRouter, Link } from 'react-router-dom'; import swal from '@sweetalert/with-react'; import Loader from 'react-loader-spinner'; +import { + FacebookShareButton, + FacebookIcon, + TwitterShareButton, + TwitterIcon, + EmailShareButton, + EmailIcon, +} from 'react-share'; import { readArticle, deleteAnArticle } from '@Actions/Articles'; import { getArticlesWithTagFromDb } from '@Actions/tagAction'; import { getProfile } from '@Actions/profileAction'; @@ -20,6 +30,7 @@ import { unFollowUser } from '@Actions/unfollowActions'; import { convertToHtml, isEmpty } from '@Utils/'; import './ReadArticle.scss'; +const appUrl = 'https://ah-commando-react.herokuapp.com'; export class ReadArticle extends Component { state = { errors: {}, @@ -139,6 +150,10 @@ export class ReadArticle extends Component { }); } + handleClick = name => { + document.querySelector(`[aria-label="${name}"]`).click(); + } + handleTagClick = async (tag) => { const { getArticlesTag, history } = this.props; await getArticlesTag(tag, history); @@ -166,6 +181,9 @@ export class ReadArticle extends Component { return history.push(`/profiles/${username}`); }; + handleClick = name => { + document.querySelector(`[aria-label="${name}"]`).click(); + } render = () => { const { @@ -183,6 +201,7 @@ export class ReadArticle extends Component { dislikesCount, comment, id: articleId, + slug, }, history, auth: { isAuthenticated }, @@ -312,6 +331,43 @@ export class ReadArticle extends Component { )} +

{' '}

+
+ +
+ this.handleClick('twitter')} + > + + + +

share on twitter

+
+ this.handleClick('facebook')} + > + + + +

share on facebook

+
+ this.handleClick('email')} + > + + + +

share by email

+
+
+
diff --git a/src/views/Articles/ReadArticle/ReadArticle.scss b/src/views/Articles/ReadArticle/ReadArticle.scss index ab32128..6acc492 100644 --- a/src/views/Articles/ReadArticle/ReadArticle.scss +++ b/src/views/Articles/ReadArticle/ReadArticle.scss @@ -4,7 +4,7 @@ display: flex; flex-direction: column; align-items: center; - margin-bottom: 30px; + margin-bottom: 100px; main { width: 100%; @@ -164,6 +164,7 @@ .comment-delete { display: flex; justify-content: flex-end; + align-items: space-around; flex: 10; .delete-icon { @@ -180,6 +181,17 @@ cursor: pointer; } } + + .option-icon { + padding: 0; + font-size: 25px ; + cursor: pointer; + height: auto !important; + transition: ease-in-out .3s; + &:hover{ + // transform: scale(1.2); + } + } } .comment-icon { background: none; @@ -200,6 +212,30 @@ justify-content: center; align-items: center; } + .dropdown-content { + display: none; + position: absolute; + background-color: #fff; + min-width: 160px; + padding: 5px; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + z-index: 1; + } + + .dropdown:hover .dropdown-content { + display: block; + span { + display: flex; + align-items: center; + margin-bottom: 2px; + font-size: 14px; + transition: ease-in-out .3s; + &:hover { + transform: scale(1.02); + background-color: #f0f0f0d0; + } + } + } } .liTag :hover {