Skip to content

Commit 332947f

Browse files
committed
Fix tests, add documentation and make screen name as optional parameter
1 parent 278c010 commit 332947f

File tree

2 files changed

+129
-85
lines changed

2 files changed

+129
-85
lines changed

README.md

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[![NPM](https://nodei.co/npm/react-twitter-auth.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/react-twitter-auth/)
22

3+
[![npm](https://img.shields.io/npm/dt/react-twitter-auth.svg)](https://img.shields.io/npm/dt/react-twitter-auth.svg)
34
[![Build Status](https://travis-ci.org/GenFirst/react-twitter-auth.svg?branch=master)](https://travis-ci.org/GenFirst/react-twitter-auth)
45
[![Code Climate](https://codeclimate.com/github/GenFirst/react-twitter-login/badges/gpa.svg)](https://codeclimate.com/github/GenFirst/react-twitter-login)
5-
[![Dependency Status](https://gemnasium.com/badges/github.com/GenFirst/react-twitter-auth.svg)](https://gemnasium.com/github.com/GenFirst/react-twitter-auth)
66
[![Coverage Status](https://coveralls.io/repos/github/GenFirst/react-twitter-auth/badge.svg?branch=master)](https://coveralls.io/github/GenFirst/react-twitter-auth?branch=master)
77
[![npm version](https://badge.fury.io/js/react-twitter-auth.svg)](https://badge.fury.io/js/react-twitter-auth)
88
![License](https://img.shields.io/badge/license-MIT-blue.svg)
@@ -18,44 +18,50 @@
1818
## Usage
1919

2020
```jsx harmony
21-
<TwitterLogin loginUrl="http://localhost:4000/api/v1/auth/twitter"
22-
onFailure={this.onFailed} onSuccess={this.onSuccess}
23-
requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"/>
21+
<TwitterLogin
22+
loginUrl="http://localhost:4000/api/v1/auth/twitter"
23+
onFailure={this.onFailed}
24+
onSuccess={this.onSuccess}
25+
requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"
26+
/>
2427
```
2528

2629
Custom content that overrides default content:
2730

2831
```jsx harmony
29-
<TwitterLogin loginUrl="http://localhost:4000/api/v1/auth/twitter"
30-
onFailure={this.onFailed}
31-
onSuccess={this.onSuccess}
32-
requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"
33-
showIcon={true}
34-
customHeaders={customHeader}>
35-
<b>Custom</b> Twitter <i>Login</i> content
32+
<TwitterLogin
33+
loginUrl="http://localhost:4000/api/v1/auth/twitter"
34+
onFailure={this.onFailed}
35+
onSuccess={this.onSuccess}
36+
requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"
37+
showIcon={true}
38+
customHeaders={customHeader}
39+
>
40+
<b>Custom</b> Twitter <i>Login</i> content
3641
</TwitterLogin>
3742
```
3843

3944
## Options
4045

41-
| params | value | default value | description |
42-
|:---------------:|:------:|:-------------------:|:-----------------------------------------------------------------------------:|
43-
| tag |string |button |tag that should be used to create element that will be used as loging element |
44-
| text |string |Sign in with Twitter |text that will be shown in component |
45-
| loginUrl |string | |URL that will be used to finish 3rd step of authentication process |
46-
| requestTokenUrl |string | |URL that will be used to get request token |
47-
| onFailure |function| |function that will be called if user cannot be authenticated |
48-
| onSuccess |function| |function that will be called if user is successfully authenticated |
49-
| disabled |boolean |false |disable component |
50-
| style |object | |style object |
51-
| className |string | |class name for component |
52-
| dialogWidth |number |600 |dialog width |
53-
| dialogHeight |number |400 |dialog height |
54-
| showIcon |bool |true |should default icon be visible |
55-
| credentials |string |same-origin |indicates whether the user agent should send cookies from the other domain in the case of cross-origin requests. Possible values: `omit`, `same-origin`, `include`|
56-
| customHeaders |object |{} |custom headers should be object with fields that needs to be sent to user server. Field name will be used as header key and field value as header value. Because of bug in fetch implementation all keys will be lowercase.|
57-
| children |node | |this props can be used in order to override default component content|
58-
| forceLogin |bool |false |force user to authenticate with Twitter username and password |
46+
| params | value | default value | description |
47+
| :-------------: | :------: | :------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
48+
| tag | string | button | tag that should be used to create element that will be used as loging element |
49+
| text | string | Sign in with Twitter | text that will be shown in component |
50+
| loginUrl | string | | URL that will be used to finish 3rd step of authentication process |
51+
| requestTokenUrl | string | | URL that will be used to get request token |
52+
| onFailure | function | | function that will be called if user cannot be authenticated |
53+
| onSuccess | function | | function that will be called if user is successfully authenticated |
54+
| disabled | boolean | false | disable component |
55+
| style | object | | style object |
56+
| className | string | | class name for component |
57+
| dialogWidth | number | 600 | dialog width |
58+
| dialogHeight | number | 400 | dialog height |
59+
| showIcon | bool | true | should default icon be visible |
60+
| credentials | string | same-origin | indicates whether the user agent should send cookies from the other domain in the case of cross-origin requests. Possible values: `omit`, `same-origin`, `include` |
61+
| customHeaders | object | {} | custom headers should be object with fields that needs to be sent to user server. Field name will be used as header key and field value as header value. Because of bug in fetch implementation all keys will be lowercase. |
62+
| children | node | | this props can be used in order to override default component content |
63+
| forceLogin | bool | false | force user to authenticate with Twitter username and password |
64+
| screenName | string | '' | prefills the username input box of the OAuth login screen with the given value |
5965

6066
# Examples
6167

src/index.js

Lines changed: 94 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import React, { Component } from 'react';
2-
import PropTypes from 'prop-types';
3-
import 'whatwg-fetch'
4-
import 'url-search-params-polyfill';
5-
import TwitterIcon from 'react-icons/lib/fa/twitter';
6-
1+
import React, { Component } from "react";
2+
import PropTypes from "prop-types";
3+
import "whatwg-fetch";
4+
import "url-search-params-polyfill";
5+
import TwitterIcon from "react-icons/lib/fa/twitter";
76

87
class TwitterLogin extends Component {
9-
108
constructor(props) {
119
super(props);
1210

@@ -20,42 +18,67 @@ class TwitterLogin extends Component {
2018

2119
getHeaders() {
2220
const headers = Object.assign({}, this.props.customHeaders);
23-
headers['Content-Type'] = 'application/json';
21+
headers["Content-Type"] = "application/json";
2422
return headers;
2523
}
2624

2725
getRequestToken() {
2826
var popup = this.openPopup();
2927

30-
return window.fetch(this.props.requestTokenUrl, {
31-
method: 'POST',
32-
credentials: this.props.credentials,
33-
headers: this.getHeaders()
34-
}).then(response => {
35-
return response.json();
36-
}).then(data => {
37-
popup.location = `https://api.twitter.com/oauth/authenticate?oauth_token=${data.oauth_token}&force_login=${this.props.forceLogin}&screen_name=${this.props.screenName}`;
38-
this.polling(popup);
39-
}).catch(error => {
40-
popup.close();
41-
return this.props.onFailure(error);
42-
});
28+
return window
29+
.fetch(this.props.requestTokenUrl, {
30+
method: "POST",
31+
credentials: this.props.credentials,
32+
headers: this.getHeaders()
33+
})
34+
.then(response => {
35+
return response.json();
36+
})
37+
.then(data => {
38+
let authenticationUrl = `https://api.twitter.com/oauth/authenticate?oauth_token=${
39+
data.oauth_token
40+
}&force_login=${this.props.forceLogin}`;
41+
42+
if (this.props.screenName) {
43+
authenticationUrl = `${authenticationUrl}&screen_name=${
44+
this.props.screenName
45+
}`;
46+
}
47+
48+
popup.location = authenticationUrl;
49+
this.polling(popup);
50+
})
51+
.catch(error => {
52+
popup.close();
53+
return this.props.onFailure(error);
54+
});
4355
}
4456

4557
openPopup() {
4658
const w = this.props.dialogWidth;
4759
const h = this.props.dialogHeight;
48-
const left = (screen.width/2)-(w/2);
49-
const top = (screen.height/2)-(h/2);
50-
51-
return window.open('', '', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width='+w+', height='+h+', top='+top+', left='+left);
60+
const left = screen.width / 2 - w / 2;
61+
const top = screen.height / 2 - h / 2;
62+
63+
return window.open(
64+
"",
65+
"",
66+
"toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=" +
67+
w +
68+
", height=" +
69+
h +
70+
", top=" +
71+
top +
72+
", left=" +
73+
left
74+
);
5275
}
5376

5477
polling(popup) {
5578
const polling = setInterval(() => {
5679
if (!popup || popup.closed || popup.closed === undefined) {
5780
clearInterval(polling);
58-
this.props.onFailure(new Error('Popup has been closed by user'));
81+
this.props.onFailure(new Error("Popup has been closed by user"));
5982
}
6083

6184
const closeDialog = () => {
@@ -64,26 +87,28 @@ class TwitterLogin extends Component {
6487
};
6588

6689
try {
67-
if (!popup.location.hostname.includes('api.twitter.com') &&
68-
!popup.location.hostname == '') {
90+
if (
91+
!popup.location.hostname.includes("api.twitter.com") &&
92+
!popup.location.hostname == ""
93+
) {
6994
if (popup.location.search) {
7095
const query = new URLSearchParams(popup.location.search);
7196

72-
const oauthToken = query.get('oauth_token');
73-
const oauthVerifier = query.get('oauth_verifier');
97+
const oauthToken = query.get("oauth_token");
98+
const oauthVerifier = query.get("oauth_verifier");
7499

75100
closeDialog();
76101
return this.getOauthToken(oauthVerifier, oauthToken);
77102
} else {
78103
closeDialog();
79-
return this.props.onFailure(new Error(
80-
'OAuth redirect has occurred but no query or hash parameters were found. ' +
81-
'They were either not set during the redirect, or were removed—typically by a ' +
82-
'routing library—before Twitter react component could read it.'
83-
));
104+
return this.props.onFailure(
105+
new Error(
106+
"OAuth redirect has occurred but no query or hash parameters were found. " +
107+
"They were either not set during the redirect, or were removed—typically by a " +
108+
"routing library—before Twitter react component could read it."
109+
)
110+
);
84111
}
85-
86-
87112
}
88113
} catch (error) {
89114
// Ignore DOMException: Blocked a frame with origin from accessing a cross-origin frame.
@@ -93,19 +118,29 @@ class TwitterLogin extends Component {
93118
}
94119

95120
getOauthToken(oAuthVerifier, oauthToken) {
96-
return window.fetch(`${this.props.loginUrl}?oauth_verifier=${oAuthVerifier}&oauth_token=${oauthToken}`, {
97-
method: 'POST',
98-
credentials: this.props.credentials,
99-
headers: this.getHeaders()
100-
}).then(response => {
101-
this.props.onSuccess(response);
102-
}).catch(error => {
103-
return this.props.onFailure(error);
104-
});
121+
return window
122+
.fetch(
123+
`${
124+
this.props.loginUrl
125+
}?oauth_verifier=${oAuthVerifier}&oauth_token=${oauthToken}`,
126+
{
127+
method: "POST",
128+
credentials: this.props.credentials,
129+
headers: this.getHeaders()
130+
}
131+
)
132+
.then(response => {
133+
this.props.onSuccess(response);
134+
})
135+
.catch(error => {
136+
return this.props.onFailure(error);
137+
});
105138
}
106139

107140
getDefaultButtonContent() {
108-
const defaultIcon = this.props.showIcon? <TwitterIcon color='#00aced' size={25}/> : null;
141+
const defaultIcon = this.props.showIcon ? (
142+
<TwitterIcon color="#00aced" size={25} />
143+
) : null;
109144

110145
return (
111146
<span>
@@ -116,12 +151,14 @@ class TwitterLogin extends Component {
116151

117152
render() {
118153
const twitterButton = React.createElement(
119-
this.props.tag, {
154+
this.props.tag,
155+
{
120156
onClick: this.onButtonClick,
121157
style: this.props.style,
122158
disabled: this.props.disabled,
123-
className: this.props.className,
124-
}, this.props.children ? this.props.children : this.getDefaultButtonContent()
159+
className: this.props.className
160+
},
161+
this.props.children ? this.props.children : this.getDefaultButtonContent()
125162
);
126163
return twitterButton;
127164
}
@@ -140,22 +177,23 @@ TwitterLogin.propTypes = {
140177
dialogWidth: PropTypes.number,
141178
dialogHeight: PropTypes.number,
142179
showIcon: PropTypes.bool,
143-
credentials: PropTypes.oneOf(['omit', 'same-origin', 'include']),
180+
credentials: PropTypes.oneOf(["omit", "same-origin", "include"]),
144181
customHeaders: PropTypes.object,
145182
forceLogin: PropTypes.bool,
146-
screenName: propTypes.string,
183+
screenName: PropTypes.string
147184
};
148185

149186
TwitterLogin.defaultProps = {
150-
tag: 'button',
151-
text: 'Sign in with Twitter',
187+
tag: "button",
188+
text: "Sign in with Twitter",
152189
disabled: false,
153190
dialogWidth: 600,
154191
dialogHeight: 400,
155192
showIcon: true,
156-
credentials: 'same-origin',
193+
credentials: "same-origin",
157194
customHeaders: {},
158-
forceLogin: false
195+
forceLogin: false,
196+
screenName: ""
159197
};
160198

161199
export default TwitterLogin;

0 commit comments

Comments
 (0)