Search code examples
reactjsfirebasereact-reduxgoogle-cloud-firestorereact-redux-firebase

Include nested collections to firebase.profile


I'm currently working on a React / Redux / Firebase application.

In my Firebase Cloud Firestore I store user data, dynamically created after creating an Auth user.

In my index.js I use useFirestoreForProfile: true to get the corresponding user data to show up in firebase.profile

index.js

const store = createStore(rootReducer,
    compose(
        applyMiddleware(
            thunk.withExtraArgument({
                getFirebase, // Firebase
                getFirestore // Cloud Database
            })
        ),
        reduxFirestore(fbInit),
        reactReduxFirebase(fbInit, {
            useFirestoreForProfile: true, // Sync user data to firebase.profile
            userProfile: 'users', // Tell Redux Firebase where our users are stored
            attachAuthIsReady: true // Enable firebase initializing before DOM rendering
        })
    )
);

My authentication action:

/store/actions/authActions.js

export const signIn = (credentials) => {
    return (dispatch, getState, {getFirebase}) => {
        const firebase = getFirebase();

        firebase.auth().signInWithEmailAndPassword(
            credentials.email,
            credentials.password
        ).then(() => {
            dispatch({
                type: 'LOGIN_SUCCESS'
            })
        }).catch((err) => {
            dispatch({
                type: 'LOGIN_ERROR',
                err
            })
        });
    }
}

The part of successful login in my authentication reducer:

/store/reducers/authReducer.js

  case 'LOGIN_SUCCESS':
      console.log('Login success');
      return {
         ...state,
         authError: null,
         authErrorDetails: null
      };

The way I map the state to the component props:

/components/pages/Dashboard/index.jsx

const mapStateToProps = (state) => {
    console.log(state);
    return {
        records: state.firestore.ordered.records,
        tabs: state.firestore.ordered.tabs,
        auth: state.firebase.auth,
        profile: state.firebase.profile
    }
}

The current profile data looks like this:

Profile data

Within the user document where those fields are set, I've created an additional collection.

The path would look as: users -> (document id) -> tabs -> (document id) -> fields

Database structure

Is there any way to include the tabs collections in firebase.profile


The final object should look something like the one I just created manually for displaying purposes:

Desired structure

Is there a way of achieving this? I really hope it's only a param missing or something.


Solution

  • I have solved the problem by creating an array within the user fields.

    export const createTab = (tab) => {
        return (dispatch, getState, { getFirebase, getFirestore }) => {
            // Make aync call to DB
    
            // Get userId (to know where to store the new tab)
            const userId = getState().firebase.auth.uid;
            // Get user tabSlots to decide how many tabs the user may have
            const userTabSlots = getState().firebase.profile.tabSlots;
            // Get current tabs (to not overwrite)
            const currentTabs = getState().firebase.profile.tabs;
    
            // Check if already exists
            let exists = currentTabs.map((ctab, i) => {
                if(ctab.title === tab.title){
                    dispatch({ type: 'CREATE_TAB_ERROR_DUPLICATE', err: "Duplicate" });
                    return true;
                } else {
                    return false;
                }
            });
    
            // Check if the user can make new tabs dependent on the tier
            let canCreate = true;
            if(currentTabs.length === userTabSlots){
                dispatch({ type: 'CREATE_TAB_ERROR_LIMIT', err: "Tab limit reached" });
                canCreate = false;
            }
    
            // If it does not already exists and user can create new tabs
            if(!exists.includes(true) && canCreate){
                const firestore = getFirestore();
                firestore.collection('users').doc(userId).update({
                    tabs: [
                        ...currentTabs,
                        {...tab, createdAt: new Date()} 
                    ]
                }).then(() => {
                    dispatch({ type: 'CREATE_TAB', tab });
                }).catch((err) => {
                    dispatch({ type: 'CREATE_TAB_ERROR', err });
                })
            }
        }
    }