Skip to content

Commit d485779

Browse files
mikefrancisarmand1m
authored andcommitted
Added loading state and expose with prop (#47)
* Added loading state * Installed prettier and ran * refactor: improves prettier; sets up lint script; changes logic a bit
1 parent 924870f commit d485779

File tree

8 files changed

+213
-131
lines changed

8 files changed

+213
-131
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ yarn-error.log*
2222

2323
.rpt*
2424
coverage
25+
26+
yarn.lock

.prettierrc.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"semi": true,
3+
"singleQuote": true,
4+
"trailingComma": "all"
5+
}

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ node_js:
99
install:
1010
- npm install --build-from-source
1111
script:
12+
- npm run lint
1213
- npm test
1314
- codecov -f coverage/*.json
1415
after_success:

package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,34 @@
1717
"test:watch": "react-scripts-ts test --env=jsdom",
1818
"build": "rollup -c",
1919
"start": "rollup -c -w",
20+
"lint": "prettier --check 'src/**/*.{ts,tsx}'",
21+
"lint:fix": "prettier --write 'src/**/*.{ts,tsx}'",
2022
"prepare": "npm run build",
2123
"predeploy-example": "cd example && npm install && npm run build",
2224
"deploy-example": "gh-pages -d example/build",
2325
"travis-deploy-once": "travis-deploy-once"
2426
},
2527
"peerDependencies": {
28+
"firebase": "^7.0.0",
2629
"prop-types": "^15.5.4",
2730
"react": "^15.0.0 || ^16.0.0",
28-
"react-dom": "^15.0.0 || ^16.0.0",
29-
"firebase": "^7.0.0"
31+
"react-dom": "^15.0.0 || ^16.0.0"
3032
},
3133
"devDependencies": {
34+
"@babel/core": "^7.0.0",
35+
"@babel/runtime": "^7.0.0",
3236
"@types/enzyme": "^3.1.14",
3337
"@types/enzyme-adapter-react-16": "^1.0.3",
3438
"@types/firebase": "^3.2.1",
3539
"@types/jest": "^24.0.6",
3640
"@types/react": "^16.3.13",
3741
"@types/react-dom": "^16.0.5",
38-
"@babel/core": "^7.0.0",
39-
"@babel/runtime": "^7.0.0",
4042
"codecov": "^3.2.0",
4143
"cross-env": "^6.0.0",
4244
"enzyme": "^3.6.0",
4345
"enzyme-adapter-react-16": "^1.5.0",
4446
"gh-pages": "^2.0.1",
47+
"prettier": "^1.19.1",
4548
"react": "^16.4.1",
4649
"react-dom": "^16.4.1",
4750
"react-scripts-ts": "^3.1.0",
@@ -54,8 +57,8 @@
5457
"rollup-plugin-typescript2": "^0.24.0",
5558
"rollup-plugin-url": "^2.2.0",
5659
"semantic-release": "^15.13.3",
57-
"typescript": "^3.3.3333",
58-
"travis-deploy-once": "^5.0.11"
60+
"travis-deploy-once": "^5.0.11",
61+
"typescript": "^3.3.3333"
5962
},
6063
"files": [
6164
"dist"

src/getErrorMessageForProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ const providerToTypeMapper = {
44
googleProvider: 'firebase.auth.GoogleAuthProvider',
55
facebookProvider: 'firebase.auth.FacebookAuthProvider',
66
twitterProvider: 'firebase.auth.TwitterAuthProvider',
7-
githubProvider: 'firebase.auth.GithubAuthProvider'
7+
githubProvider: 'firebase.auth.GithubAuthProvider',
88
};
99

1010
const providerToFirebaseDocs = {
1111
googleProvider: 'https://firebase.google.com/docs/auth/web/google-signin',
1212
facebookProvider: 'https://firebase.google.com/docs/auth/web/facebook-signin',
1313
twitterProvider: 'https://firebase.google.com/docs/auth/web/twitter-signin',
14-
githubProvider: 'https://firebase.google.com/docs/auth/web/github-auth'
14+
githubProvider: 'https://firebase.google.com/docs/auth/web/github-auth',
1515
};
1616

1717
const getErrorMessageForProvider = (provider: PossibleProviders) =>

src/index.tsx

Lines changed: 115 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@ export type WrappedComponentProps = {
1010
signInWithFacebook: () => void;
1111
signInWithGithub: () => void;
1212
signInWithTwitter: () => void;
13-
signInWithPhoneNumber: (phoneNumber: string, applicationVerifier: firebase.auth.ApplicationVerifier) => Promise<any>;
13+
signInWithPhoneNumber: (
14+
phoneNumber: string,
15+
applicationVerifier: firebase.auth.ApplicationVerifier,
16+
) => Promise<any>;
1417
signInAnonymously: () => void;
1518
signOut: () => void;
1619
setError: (error: any) => void;
1720
user?: firebase.User;
1821
error?: firebase.FirebaseError;
22+
loading: boolean;
1923
};
2024

2125
export type PossibleProviders =
22-
'googleProvider'
26+
| 'googleProvider'
2327
| 'facebookProvider'
2428
| 'twitterProvider'
2529
| 'githubProvider';
@@ -28,7 +32,7 @@ export type ProvidersMapper = {
2832
googleProvider?: firebase.auth.GithubAuthProvider_Instance;
2933
facebookProvider?: firebase.auth.FacebookAuthProvider_Instance;
3034
twitterProvider?: firebase.auth.TwitterAuthProvider_Instance;
31-
githubProvider?: firebase.auth.GithubAuthProvider_Instance;
35+
githubProvider?: firebase.auth.GithubAuthProvider_Instance;
3236
};
3337

3438
export type HocParameters = {
@@ -37,108 +41,129 @@ export type HocParameters = {
3741
};
3842

3943
export type FirebaseAuthProviderState = {
40-
user?: firebase.User,
41-
error?: string,
44+
loading: boolean;
45+
user?: firebase.User;
46+
error?: string;
4247
};
4348

4449
const withFirebaseAuth = ({
4550
firebaseAppAuth,
4651
providers = {},
47-
}: HocParameters) =>
48-
(WrappedComponent: React.SFC<WrappedComponentProps>) =>
49-
class FirebaseAuthProvider extends React.PureComponent<{}, FirebaseAuthProviderState> {
50-
static displayName = `withFirebaseAuth(${WrappedComponent.displayName || WrappedComponent.name})`;
51-
52-
state = {
53-
user: undefined,
54-
error: undefined,
55-
};
52+
}: HocParameters) => (WrappedComponent: React.SFC<WrappedComponentProps>) =>
53+
class FirebaseAuthProvider extends React.PureComponent<
54+
{},
55+
FirebaseAuthProviderState
56+
> {
57+
static displayName = `withFirebaseAuth(${WrappedComponent.displayName ||
58+
WrappedComponent.name})`;
59+
60+
state = {
61+
loading: false,
62+
user: undefined,
63+
error: undefined,
64+
};
65+
66+
unsubscribeAuthStateListener: firebase.Unsubscribe;
67+
68+
componentDidMount() {
69+
this.toggleLoading();
70+
71+
this.unsubscribeAuthStateListener = firebaseAppAuth.onAuthStateChanged(
72+
(user: firebase.User) => this.setState({ user }),
73+
(error: firebase.auth.Error) => this.setError(error.message),
74+
() => this.toggleLoading(),
75+
);
76+
}
5677

57-
unsubscribeAuthStateListener: firebase.Unsubscribe;
78+
componentWillUnmount() {
79+
this.unsubscribeAuthStateListener();
80+
}
5881

59-
componentDidMount() {
60-
this.unsubscribeAuthStateListener =
61-
firebaseAppAuth.onAuthStateChanged((user: firebase.User) =>
62-
this.setState({ user })
63-
);
64-
}
82+
setError = (error: any) => this.setState({ error });
83+
84+
toggleLoading = () =>
85+
this.setState(currState => ({ loading: !currState.loading }));
6586

66-
componentWillUnmount() {
67-
this.unsubscribeAuthStateListener();
87+
async tryTo<T>(operation: () => Promise<T>) {
88+
try {
89+
const result = await operation();
90+
this.toggleLoading();
91+
return result;
92+
} catch (error) {
93+
this.setError(error.message);
94+
this.toggleLoading();
95+
return error as Error;
6896
}
97+
}
6998

70-
setError = (error: any) => this.setState({ error });
99+
tryToSignInWithProvider = (provider: PossibleProviders) =>
100+
this.tryTo<firebase.auth.UserCredential>(() => {
101+
const providerInstance = providers[provider];
71102

72-
async tryTo <T> (operation: () => Promise<T>): Promise<T> {
73-
try {
74-
return operation();
75-
} catch(error) {
76-
this.setError(error.message);
77-
return error;
103+
if (!providerInstance) {
104+
throw new Error(getErrorMessageForProvider(provider));
78105
}
79-
};
80-
81-
tryToSignInWithProvider = (provider: PossibleProviders): Promise<firebase.auth.UserCredential> =>
82-
this.tryTo<firebase.auth.UserCredential>(() => {
83-
const providerInstance = providers[provider];
84-
85-
if (!providerInstance) {
86-
throw new Error(getErrorMessageForProvider(provider));
87-
}
88-
89-
return firebaseAppAuth.signInWithPopup(providerInstance);
90-
});
91106

92-
signOut = () =>
93-
this.tryTo<void>(() => firebaseAppAuth.signOut());
94-
95-
signInAnonymously = () =>
96-
this.tryTo<firebase.auth.UserCredential>(() => firebaseAppAuth.signInAnonymously());
97-
98-
signInWithGithub = () =>
99-
this.tryToSignInWithProvider('githubProvider');
100-
101-
signInWithTwitter = () =>
102-
this.tryToSignInWithProvider('twitterProvider');
103-
104-
signInWithGoogle = () =>
105-
this.tryToSignInWithProvider('googleProvider');
106-
107-
signInWithFacebook = () =>
108-
this.tryToSignInWithProvider('facebookProvider');
109-
110-
signInWithEmailAndPassword = (email: string, password: string) =>
111-
this.tryTo<firebase.auth.UserCredential>(() => firebaseAppAuth.signInWithEmailAndPassword(email, password));
112-
113-
signInWithPhoneNumber = (phoneNumber: string, applicationVerifier: firebase.auth.ApplicationVerifier) =>
114-
this.tryTo<firebase.auth.ConfirmationResult>(() => firebaseAppAuth.signInWithPhoneNumber(phoneNumber, applicationVerifier))
115-
116-
createUserWithEmailAndPassword = (email: string, password: string) =>
117-
this.tryTo<firebase.auth.UserCredential>(() => firebaseAppAuth.createUserWithEmailAndPassword(email, password));
118-
119-
sharedHandlers = {
120-
signInWithEmailAndPassword: this.signInWithEmailAndPassword,
121-
createUserWithEmailAndPassword: this.createUserWithEmailAndPassword,
122-
signInWithGithub: this.signInWithGithub,
123-
signInWithTwitter: this.signInWithTwitter,
124-
signInWithGoogle: this.signInWithGoogle,
125-
signInWithFacebook: this.signInWithFacebook,
126-
signInWithPhoneNumber: this.signInWithPhoneNumber,
127-
setError: this.setError,
128-
signInAnonymously: this.signInAnonymously,
129-
signOut: this.signOut,
107+
return firebaseAppAuth.signInWithPopup(providerInstance);
108+
});
109+
110+
signOut = () => this.tryTo<void>(() => firebaseAppAuth.signOut());
111+
112+
signInAnonymously = () =>
113+
this.tryTo<firebase.auth.UserCredential>(() =>
114+
firebaseAppAuth.signInAnonymously(),
115+
);
116+
117+
signInWithGithub = () => this.tryToSignInWithProvider('githubProvider');
118+
119+
signInWithTwitter = () => this.tryToSignInWithProvider('twitterProvider');
120+
121+
signInWithGoogle = () => this.tryToSignInWithProvider('googleProvider');
122+
123+
signInWithFacebook = () => this.tryToSignInWithProvider('facebookProvider');
124+
125+
signInWithEmailAndPassword = (email: string, password: string) =>
126+
this.tryTo<firebase.auth.UserCredential>(() =>
127+
firebaseAppAuth.signInWithEmailAndPassword(email, password),
128+
);
129+
130+
signInWithPhoneNumber = (
131+
phoneNumber: string,
132+
applicationVerifier: firebase.auth.ApplicationVerifier,
133+
) =>
134+
this.tryTo<firebase.auth.ConfirmationResult>(() =>
135+
firebaseAppAuth.signInWithPhoneNumber(phoneNumber, applicationVerifier),
136+
);
137+
138+
createUserWithEmailAndPassword = (email: string, password: string) =>
139+
this.tryTo<firebase.auth.UserCredential>(() =>
140+
firebaseAppAuth.createUserWithEmailAndPassword(email, password),
141+
);
142+
143+
sharedHandlers = {
144+
signInWithEmailAndPassword: this.signInWithEmailAndPassword,
145+
createUserWithEmailAndPassword: this.createUserWithEmailAndPassword,
146+
signInWithGithub: this.signInWithGithub,
147+
signInWithTwitter: this.signInWithTwitter,
148+
signInWithGoogle: this.signInWithGoogle,
149+
signInWithFacebook: this.signInWithFacebook,
150+
signInWithPhoneNumber: this.signInWithPhoneNumber,
151+
setError: this.setError,
152+
signInAnonymously: this.signInAnonymously,
153+
signOut: this.signOut,
154+
};
155+
156+
render() {
157+
const props = {
158+
...this.props,
159+
...this.sharedHandlers,
160+
loading: this.state.loading,
161+
user: this.state.user,
162+
error: this.state.error,
130163
};
131164

132-
render() {
133-
const props = {
134-
...this.props,
135-
...this.sharedHandlers,
136-
user: this.state.user,
137-
error: this.state.error,
138-
};
139-
140-
return <WrappedComponent {...props} />;
141-
}
165+
return <WrappedComponent {...props} />;
142166
}
167+
};
143168

144169
export default withFirebaseAuth;

0 commit comments

Comments
 (0)