├── .prettierrc ├── src ├── lib │ ├── index.js │ ├── index.d.ts │ ├── ReactWhatsapp.js │ └── ReactWhatsapp.spec.js └── dev │ ├── index.js │ ├── index.html │ ├── App.js │ └── index.css ├── .github └── workflows │ ├── npmpublish.yml │ └── nodejs.yml ├── LICENSE ├── .gitignore ├── package.json └── README.md /.prettierrc: -------------------------------------------------------------------------------- 1 | { "singleQuote": true } 2 | -------------------------------------------------------------------------------- /src/lib/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ReactWhatsapp'; 2 | -------------------------------------------------------------------------------- /src/dev/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import './index.css'; 5 | 6 | ReactDOM.render(, document.getElementById('root')); 7 | -------------------------------------------------------------------------------- /src/dev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | React Whatsapp 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /src/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | type Values = T[keyof T]; 4 | 5 | type ObtainHTMLProps> = 6 | T extends React.DetailedHTMLProps ? Props : never; 7 | 8 | type ReactWhatsappProps = Values<{ 9 | [Tag in keyof JSX.IntrinsicElements]: { 10 | element: Tag; 11 | number: string; 12 | message?: string; 13 | } & ObtainHTMLProps; 14 | }>; 15 | 16 | export default class ReactWhatsapp extends React.Component {} 17 | -------------------------------------------------------------------------------- /.github/workflows/npmpublish.yml: -------------------------------------------------------------------------------- 1 | name: Node.js Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | npm-publish: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: 12 15 | registry-url: https://registry.npmjs.org/ 16 | - name: Install dependencies 17 | run: yarn install --frozen-lockfile 18 | - name: Build 19 | run: yarn build 20 | - name: Npm publish 21 | run: npm publish --access public 22 | env: 23 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 24 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build_test: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | node-version: [10, 12, 14] 11 | os: [ubuntu-latest, windows-latest, macOS-latest] 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Use Node.js ${{ matrix.node-version }} 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: ${{ matrix.node-version }} 18 | - name: Install dependencies 19 | run: yarn install --frozen-lockfile 20 | - name: Tests and coverage 21 | run: yarn coverage 22 | - name: Build 23 | run: yarn build 24 | -------------------------------------------------------------------------------- /src/dev/App.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import ReactWhatsapp from '../lib'; 3 | 4 | const App = () => { 5 | const [number, setNumber] = useState(''); 6 | const [message, setMessage] = useState(''); 7 | 8 | return ( 9 |
10 |

React Whatsapp

11 |
12 | setNumber(e.target.value)} 17 | /> 18 | setMessage(e.target.value)} 23 | /> 24 | 25 | Open Whatsapp 26 | 27 |
28 |
29 | ); 30 | }; 31 | 32 | export default App; 33 | -------------------------------------------------------------------------------- /src/lib/ReactWhatsapp.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const URL = 'https://wa.me'; 5 | 6 | const ReactWhatsapp = ({ number, message, element, onClick, ...props }) => { 7 | const Element = element; 8 | 9 | number = number.replace(/[^\w\s]/gi, '').replace(/ /g, ''); 10 | 11 | let url = `${URL}/${number}`; 12 | 13 | if (message) { 14 | url += `?text=${encodeURI(message)}`; 15 | } 16 | 17 | return ( 18 | { 20 | window.open(url); 21 | 22 | if (onClick) { 23 | onClick(e); 24 | } 25 | }} 26 | {...props} 27 | /> 28 | ); 29 | }; 30 | 31 | ReactWhatsapp.propTypes = { 32 | number: PropTypes.string.isRequired, 33 | message: PropTypes.string, 34 | element: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), 35 | }; 36 | 37 | ReactWhatsapp.defaultProps = { 38 | element: 'button', 39 | }; 40 | 41 | export default ReactWhatsapp; 42 | -------------------------------------------------------------------------------- /src/dev/index.css: -------------------------------------------------------------------------------- 1 | body, 2 | #root { 3 | margin: 0; 4 | padding: 0; 5 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 6 | } 7 | 8 | html, 9 | body, 10 | #root { 11 | width: 100%; 12 | height: 100%; 13 | } 14 | 15 | .content { 16 | background-color: #1ebea5; 17 | width: 100%; 18 | height: 100%; 19 | display: flex; 20 | align-items: center; 21 | justify-content: center; 22 | flex-direction: column; 23 | } 24 | 25 | .title { 26 | color: white; 27 | margin-bottom: 10px; 28 | margin-top: 0px; 29 | font-size: 40pt; 30 | } 31 | 32 | .library { 33 | width: 600px; 34 | max-width: 100%; 35 | height: 300px; 36 | display: flex; 37 | flex-direction: column; 38 | align-items: center; 39 | justify-content: center; 40 | border-radius: 2px; 41 | padding: 16px; 42 | } 43 | 44 | input, 45 | button { 46 | width: 100%; 47 | font-family: inherit; 48 | font-size: 16pt; 49 | padding: 0.4em; 50 | margin: 0 0 20px 0; 51 | box-sizing: border-box; 52 | border: 1px solid #ccc; 53 | border-radius: 4px; 54 | } 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 N.A.D.A. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /bower_componets 6 | /.pnp 7 | .pnp.js 8 | 9 | # TypeScript v1 declaration files 10 | typings/ 11 | 12 | # TypeScript cache 13 | *.tsbuildinfo 14 | 15 | # Optional npm cache directory 16 | .npm 17 | 18 | # Optional eslint cache 19 | .eslintcache 20 | 21 | # Optional REPL history 22 | .node_repl_history 23 | 24 | # Output of 'npm pack' 25 | *.tgz 26 | 27 | # Yarn Integrity file 28 | .yarn-integrity 29 | 30 | # testing 31 | /coverage 32 | 33 | # production 34 | /dist 35 | 36 | # next.js build output 37 | .next 38 | 39 | # dotenv environment variables file 40 | .env 41 | .env.test 42 | 43 | # misc 44 | .DS_* 45 | **/*.backup.* 46 | **/*.back.* 47 | .env.local 48 | .env.development.local 49 | .env.test.local 50 | .env.production.local 51 | 52 | # Logs 53 | logs 54 | *.log 55 | npm-debug.log* 56 | yarn-debug.log* 57 | yarn-error.log* 58 | lerna-debug.log* 59 | 60 | # Runtime data 61 | pids 62 | *.pid 63 | *.seed 64 | *.pid.lock 65 | 66 | # DynamoDB Local files 67 | .dynamodb/ 68 | 69 | # FuseBox cache 70 | .fusebox/ 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # Other 76 | .idea/ 77 | *.sublime* 78 | psd 79 | thumb 80 | sketch 81 | Thumbs.db -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-whatsapp", 3 | "description": "React component for whatsapp click to chat", 4 | "version": "0.3.0", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "homepage": "https://react-whatsapp.netlify.com/", 9 | "author": "André Lins (https://andrelmlins.github.io/)", 10 | "license": "MIT", 11 | "files": [ 12 | "dist" 13 | ], 14 | "scripts": { 15 | "start": "react-dependency-scripts start", 16 | "build": "react-dependency-scripts build", 17 | "build:app": "react-dependency-scripts build-app", 18 | "test": "react-dependency-scripts test", 19 | "coverage": "react-dependency-scripts test --coverage" 20 | }, 21 | "devDependencies": { 22 | "@testing-library/react": "^11.2.5", 23 | "prop-types": "^15.7.2", 24 | "react": "^17.0.1", 25 | "react-dependency-scripts": "^1.0.6", 26 | "react-dom": "^17.0.1" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "git+https://github.com/andrelmlins/react-whatsapp.git" 31 | }, 32 | "keywords": [ 33 | "react", 34 | "whatsapp", 35 | "click-to-chat" 36 | ], 37 | "bugs": { 38 | "url": "https://github.com/andrelmlins/react-whatsapp/issues" 39 | }, 40 | "browserslist": { 41 | "production": [ 42 | ">0.2%", 43 | "not dead", 44 | "not op_mini all" 45 | ], 46 | "development": [ 47 | "last 1 chrome version", 48 | "last 1 firefox version", 49 | "last 1 safari version" 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/lib/ReactWhatsapp.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | render, 4 | cleanup, 5 | getByLabelText, 6 | fireEvent 7 | } from '@testing-library/react'; 8 | 9 | import ReactWhatsapp from './index'; 10 | 11 | afterEach(cleanup); 12 | 13 | describe('ReactWhatsapp Component', () => { 14 | it('Should render the component', () => { 15 | const { container } = createComponent({ 16 | number: '+1-202-555-0107', 17 | message: 'MESSAGE' 18 | }); 19 | expect(container).toBeDefined(); 20 | }); 21 | 22 | it('Should render the component without message', () => { 23 | const { container } = createComponent({ number: '+1-202-555-0107' }); 24 | expect(container).toBeDefined(); 25 | }); 26 | 27 | it('Call button with onClick', () => { 28 | const onClick = jest.fn(); 29 | window.open = jest.fn(); 30 | 31 | const { getByLabelText } = createComponent({ 32 | number: '+1-202-555-0107', 33 | onClick, 34 | 'aria-label': 'Click' 35 | }); 36 | 37 | fireEvent.click(getByLabelText('Click')); 38 | 39 | expect(onClick).toHaveBeenCalledTimes(1); 40 | expect(window.open).toHaveBeenCalledTimes(1); 41 | }); 42 | 43 | it('Call button without onClick', () => { 44 | window.open = jest.fn(); 45 | 46 | const { getByLabelText } = createComponent({ 47 | number: '+1-202-555-0107', 48 | 'aria-label': 'Click' 49 | }); 50 | 51 | fireEvent.click(getByLabelText('Click')); 52 | 53 | expect(window.open).toHaveBeenCalledTimes(1); 54 | }); 55 | }); 56 | 57 | function createComponent(props = {}) { 58 | const defaultProps = { 59 | ...props 60 | }; 61 | 62 | return render(); 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Whatsapp 2 | 3 | [![npm version](https://badge.fury.io/js/react-whatsapp.svg)](https://www.npmjs.com/package/react-whatsapp) • [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/andrelmlins/react-whatsapp/blob/master/LICENSE) • [[![Node.js CI](https://github.com/andrelmlins/react-whatsapp/actions/workflows/nodejs.yml/badge.svg)](https://github.com/andrelmlins/react-whatsapp/actions/workflows/nodejs.yml) • [![Netlify Status](https://api.netlify.com/api/v1/badges/aedabb99-7094-4894-8063-7dad39afc83d/deploy-status)](https://app.netlify.com/sites/react-whatsapp/deploys) 4 | 5 | React component for whatsapp click to chat 6 | 7 | ## Installation 8 | 9 | ``` 10 | npm i react-whatsapp 11 | // OR 12 | yarn add react-whatsapp 13 | ``` 14 | 15 | ## Demo [Link](https://react-whatsapp.netlify.com/) 16 | 17 | Local demo: 18 | 19 | ``` 20 | git clone https://github.com/andrelmlins/react-whatsapp.git 21 | cd react-whatsapp 22 | npm install && npm run start 23 | ``` 24 | 25 | ## Examples 26 | 27 | ```jsx 28 | import React from 'react'; 29 | import { render } from 'react-dom'; 30 | import ReactWhatsapp from 'react-whatsapp'; 31 | 32 | const App = () => ( 33 | 34 | ); 35 | 36 | render(, document.getElementById('root')); 37 | ``` 38 | 39 | ## Properties 40 | 41 | | Prop | Default | Type | Description | 42 | | ------- | ------- | ------- | ----------------------------------------------------- | 43 | | number | -- | string | Phone number | 44 | | message | -- | string | Message for chat | 45 | | element | button | element | Either a string to use a HTML element or a component. | 46 | 47 | ## NPM Statistics 48 | 49 | Download stats for this NPM package 50 | 51 | [![NPM](https://nodei.co/npm/react-whatsapp.png)](https://nodei.co/npm/react-whatsapp/) 52 | 53 | ## License 54 | 55 | React Whatsapp is open source software [licensed as MIT](https://github.com/andrelmlins/react-whatsapp/blob/master/LICENSE). 56 | --------------------------------------------------------------------------------