- fix issue with firebase-hooks

- implement custom useAuthState
This commit is contained in:
Amruth Pillai
2020-07-06 19:53:47 +05:30
parent 862ff7cdc1
commit 4e064dba96
11 changed files with 465 additions and 157 deletions

View File

@ -1,11 +1,11 @@
import cx from "classnames";
import React, { useContext } from "react";
import { MdPerson, MdSync } from "react-icons/md";
import { MdPerson, MdSync, MdSyncDisabled } from "react-icons/md";
import DatabaseContext from "../../../contexts/DatabaseContext";
import styles from "./RightNavbar.module.css";
const RightNavbar = () => {
const { isUpdating } = useContext(DatabaseContext);
const { isOffline, isUpdating } = useContext(DatabaseContext);
return (
<div className={styles.container}>
@ -16,7 +16,13 @@ const RightNavbar = () => {
/>
</div>
<MdSync size="24px" className={cx("mt-auto", { spin: isUpdating })} />
<div className="text-4xl mt-auto">
{isOffline ? (
<MdSyncDisabled className="text-red-600" />
) : (
<MdSync className={cx({ spin: isUpdating })} />
)}
</div>
</div>
);
};

View File

@ -1,23 +1,34 @@
import firebase from "gatsby-plugin-firebase";
import { debounce } from "lodash";
import React, { createContext, useContext, useState } from "react";
import React, { createContext, useContext, useEffect, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import UserContext from "./UserContext";
const defaultState = {
isOffline: false,
isUpdating: false,
getResume: async () => {},
getResumes: async () => {},
createResume: () => {},
updateResume: async () => {},
debouncedUpdate: async () => {},
deleteResume: () => {},
};
const DatabaseContext = createContext(defaultState);
const DatabaseProvider = ({ children }) => {
const [isOffline, setOffline] = useState(false);
const [isUpdating, setUpdating] = useState(false);
const { user } = useContext(UserContext);
useEffect(() => {
const connectedRef = firebase.database().ref(".info/connected");
connectedRef.on("value", (snapshot) => {
snapshot.val() === true ? setOffline(false) : setOffline(true);
});
}, []);
const getResume = async (id) => {
const snapshot = await firebase
.database()
@ -30,11 +41,25 @@ const DatabaseProvider = ({ children }) => {
const id = uuidv4();
const createdAt = firebase.database.ServerValue.TIMESTAMP;
let firstName = "",
lastName = "",
photograph = "";
if (!user.isAnonymous) {
[firstName, lastName] = user.displayName.split(" ");
photograph = user.photoURL;
}
firebase
.database()
.ref(`users/${user.uid}/resumes/${id}`)
.set({
id,
profile: {
firstName,
lastName,
photograph,
},
...resume,
createdAt,
updatedAt: createdAt,
@ -66,10 +91,12 @@ const DatabaseProvider = ({ children }) => {
return (
<DatabaseContext.Provider
value={{
isOffline,
isUpdating,
getResume,
createResume,
updateResume: debouncedUpdate,
updateResume,
debouncedUpdate,
deleteResume,
}}
>

View File

@ -5,7 +5,7 @@ import DatabaseContext from "./DatabaseContext";
const ResumeContext = createContext({});
const ResumeProvider = ({ children }) => {
const { updateResume } = useContext(DatabaseContext);
const { debouncedUpdate } = useContext(DatabaseContext);
const [state, dispatch] = useReducer((state, { type, payload }) => {
let newState;
@ -13,7 +13,7 @@ const ResumeProvider = ({ children }) => {
switch (type) {
case "on_input":
newState = set({ ...state }, payload.path, payload.value);
updateResume(newState);
debouncedUpdate(newState);
return newState;
case "set_data":
return payload;

View File

@ -1,14 +1,15 @@
import firebase from "gatsby-plugin-firebase";
import { pick } from "lodash";
import React, { createContext, useEffect, useState } from "react";
import { useAuthState } from "react-firebase-hooks/auth";
import { toast } from "react-toastify";
import useAuthState from "../hooks/useAuthState";
const defaultUser = {
uid: null,
displayName: null,
email: null,
photoURL: null,
isAnonymous: false,
};
const defaultState = {
@ -20,7 +21,7 @@ const defaultState = {
const UserContext = createContext(defaultState);
const UserProvider = ({ children }) => {
const [firebaseUser, loading] = useAuthState(firebase.auth());
const [firebaseUser, loading] = useAuthState(firebase);
const [user, setUser] = useState(null);
useEffect(() => {

54
src/hooks/useAuthState.js Normal file
View File

@ -0,0 +1,54 @@
import { useEffect, useReducer, useState } from "react";
export default function useAuthState(firebase) {
const [auth, setAuth] = useState(undefined);
const [state, dispatch] = useReducer(
(state, action) => {
switch (action.type) {
case "auth_state_changed":
return {
...state,
user: action.user,
loading: false,
};
case "error":
return {
...state,
error: action.error,
loading: false,
};
default:
return state;
}
},
{
user: undefined,
loading: true,
error: undefined,
}
);
useEffect(() => {
setAuth(firebase.auth());
}, [firebase]);
useEffect(() => {
if (auth === undefined) return;
const unsubscribe = auth.onAuthStateChanged(
(user) => {
dispatch({ type: "auth_state_changed", user });
},
(error) => {
dispatch({ type: "error", error });
}
);
return () => {
unsubscribe();
};
}, [auth]);
return [state.user, state.loading, state.error];
}

View File

@ -38,8 +38,15 @@ const CreateResumeModal = () => {
name: "",
},
validationSchema: CreateResumeSchema,
onSubmit: (data) => {
isEditMode ? updateResume(data) : createResume(data);
onSubmit: (newData) => {
if (isEditMode) {
if (data !== newData) {
updateResume(newData);
}
} else {
createResume(newData);
}
modalRef.current.handleClose();
},
});

View File

@ -1,15 +1,28 @@
import firebase from "gatsby-plugin-firebase";
import React from "react";
import { useListVals } from "react-firebase-hooks/database";
import React, { useEffect, useState } from "react";
import CreateResume from "../../components/dashboard/CreateResume";
import ResumePreview from "../../components/dashboard/ResumePreview";
import TopNavbar from "../../components/dashboard/TopNavbar";
import LoadingScreen from "../../components/router/LoadingScreen";
const Dashboard = ({ user }) => {
const [resumes, loading] = useListVals(
firebase.database().ref(`users/${user.uid}/resumes`)
);
const [resumes, setResumes] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
firebase
.database()
.ref(`users/${user.uid}/resumes`)
.on("value", (snapshot) => {
if (snapshot.val()) {
const resumes = [];
const data = snapshot.val();
Object.keys(data).forEach((key) => resumes.push(data[key]));
setResumes(resumes);
setLoading(false);
}
});
}, [user]);
if (loading) {
return <LoadingScreen message="Connecting to database..." />;