- Read Tutorial
- Watch Guide Video
So what we need to do is we need to, well we don't really need to do in the initial layout on these sign in pages because we're already well actually we do because we're hard coding it in right now. So what we need to do is, we need to go into, first I want to close my node modules I don't know why those are open.
And then what I'm going to do is I'm going to go into bootstrap.js
and you'll see that we need it to be the same for all of these, but then on these routes let's go check what we need okay, well we'll do that after. Okay so in sign in and sign up we need to set those.
So we're going into signin.js
, we already have access to our actions, so what we want to do is just say onComponentDidMount now change the header here so this.props.updateHeader
. All right so it takes in the title, subtitle, and hideBar. We don't want to hide the bar, so we'll just leave it. But we're going to come back, so hideBar might be set to true.
So what we want to do is say title and we'll say put something there. So don't put something there and then hideBar is false.
signin.js
componentDidMount() { this.props.updateHeader(title: '', subtitle: '', hideBar: false); }
Okay, now we need to provide data here. All right, why is it doing that? Oh this isn't Swift that's why.
signin.js
componentDidMount() { this.props.updateHeader('', '', false); }
We need to provide some data in here OK but we don't have any data. So what we need to do is go into layout.js
and we just need to take this title data out. All right go back to layout and take this subtitle and let's just close this header off now so it has nothing and well set that now in signin.js.
layout.js
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Header, HeaderBar } from './header'; class Layout extends Component { render() { return ( <div className='layout-grid'> <Header/> <HeaderBar/> {this.props.children} </div> ) } } function mapStateToProps(state) { return state; } Layout = connect(mapStateToProps)(Layout); export default Layout;
And we'll set that in signin.js. Now let's go see what happens, and let's uncomment this so you can see what's going on here,
signin.js
import React, { Component } from 'react'; import { connect } from 'react-redux'; import * as actions from '../../actions'; import SigninForm from './signinForm'; class Signin extends Component { componentDidMount() { // this.props.updateHeader('Welcome to HOA Manager!', 'Please login to continue', false); } onSubmit = (fields) => { this.props.signIn(fields, () => { this.props.history.push('/dashboard'); }) } render() { return ( <div className='sign-in'> <SigninForm onSubmit={(event) => this.onSubmit(event)}/> </div> ) } } export default connect(null, actions)(Signin);
And you'll see we don't have a header now, but we do have the bar.
So what we need to do is uncomment this and we haven't even set in the case for the bar yet, so it's going to show in all cases for a second. Okay, now let's see what happens when we reload the page, okay so it still displays as none. Now the reason this is happening is because in our layout.js we're not yet really providing these to the header right.
The header still takes these in we just haven't provided them. So we also need to hide the bar if there is a status that's sent false, so will say hideBar and then we'll say, what we'll have to do is say return and then we'll have to use a ternary expression.
So will say in a javascript object, hide, here's what we'll do, we'll say hideBar question mark then do this. So we want to say return, lets just return an empty div or nothing. But then if hideBar is set to false we will return this.
header.js
export function HeaderBar({hideBar}) { {hideBar ? '' : <div className='bar'></div>} }
So that's how that works. Let's go map these over now because it's still not going to be really doing anything. Okay, we're actually getting an error already, it says nothing was returned from render.
So what we need to do is say, let's see, okay what we're going to have to do is wrap this with a div, except for that kind of creates a problem. So what we'll do is, let's see, I'm going to comment that and say if hideBar, I don't want to import that.
So if hideBar then we'll return it, or we wont return it, so we'll say if not hideBar, we do need to return something here, so we'll just say return div thats empty, else return the div with bar in it, okay so that should work great.
header.js
export function HeaderBar({hideBar}) { if(hideBar) { return <div></div> } else { <div className='bar'></div> } }
Let's go ahead and try it out now. Right it says header bar nothing was returned from render,
and that's because we're not returning this div, okay thats our HeaderBar at this point.
header.js
export function HeaderBar({hideBar}) { if(hideBar) { return <div></div> } else { return <div className='bar'></div> } }
And you'll see that everything's working the way it should. But now what we need to do is actually provide these props see hideBar, title, and subtitle we're not providing these yet. So let's go into our layout.js
and get them from our state and then provide them.
If you go in here and you say Redux DevTools to the left, you'll see that we should at least I'm going to close the Redux DevTools because it seems to be acting weird and reopen them. Right and nothing's working still, you don't see the headers right.
So what we need to do is hook up the header by going into reducers index.js
and importing it, let's say import header from ./headerReducer and then down here we just need to put in header and that should work.
index.js
import { combineReducers } from 'redux'; import { reducer as form } from 'redux-form'; import auth from './authReducer'; import newsletters from './newsletterReducer'; import requests from './requestsReducer'; import headeer from './headerReducer'; const rootReducer = combineReducers({ form, auth, newsletters, requests, header }); export default rootReducer;
Let's go check it out now and see if its in Redux DevTools and we get an error, it says key is not defined in headerReducer. Okay so let's go into headerReducer.js
and let's get rid of wherever it's saying key, okay so key needs to be action.payload or I mean action.type
and now it should work.
headerReducer.js
export default function(state = INITIAL_STATE, action) { switch (action.type) { case UPDATE_HEADER: const { title, subtitle, hideBar } = action.payload; return { ...state, title, subtitle, hideBar } // return { // ...state, // ...action.payload // } default: return state; } }
Okay cool, everything's working. Let's go check it in Redux DevTools, you'll see we now have access to header. You'll see that header has a title, subtitle, and a hideBar.
And those are all set except for we don't really have access to them up here in our nav bar, like they are not displaying right. And that's because in layout.js
we're not passing them in as props and in these components we don't have mapStateToProps, and we don't want to do that in here because we just want these to be simple functional components.
So let's go back and let's provide them into here okay, so we've got title, subtitle, and then we can past into here hideBar and then set this to this.props or better yet take them all out in the render functions. So we say const title, subtitle, and hideBar.
layout.js
const { title, subtitle, hideBar } = this.props;
Now we don't have access to these yet, so what we need to do, is we need to go into mapStateToProps and we just need to say const header is equal to state.header and then we just need to return in an object ...header and that will take them all out and put them into our props.
layout.js
function mapStateToProps(state) { const header = state.header; return { ...header } }
Now what we need to do is go into the browser, or first we need to put these in here. So we need to say title, subtitle and then go down to hideBar and say hideBar.
layout.js
import { Header, HeaderBar } from './header'; class Layout extends Component { render() { const { title, subtitle, hideBar } = this.props; return ( <div className='layout-grid'> <Header title={title} subtitle={subtitle} /> <HeaderBar hideBar={hideBar}/> {this.props.children} </div> ) } }
All right, that should work. Let's go into Chrome and you'll see it's working.
But when we go to not a member, it's still working because it's set. But if we were to reload the page right now and stay on sign up it wouldn't work, it would be gone.
and that's because we're only setting this in the one signin.js file. So what we need to do, is we need to copy this componentDidMount and we need to set it everywhere else okay. We need to go into sign up, and we need to paste it in here and we're going to be good to go.
signup.js
componentDidMount() { this.props.updateHeader('Welcome to HOA Manager!', 'Please login to continue', false); }
Now you'll see when we reload the page on sign up it appears.
That's great except for when we go to login, it's now still the same right, it didn't even work, we're back to where we started.
So for now we set it up in a way that we can really easily modify it. If we had done this at the very beginning of the application, this whole process would have been really quick. We would have started like four videos ago or however many it's taken to do this.
All right, so what we need to do is we need to go into our, we need to go into the rest of our components and set them, the rest of our routes at least, and so we have about five more. So we're never really going to reload on the edit page and the detail page.
So what we'll do, is we'll just set it on the dashboard. So let's go to the dashboard.js
and let's put this in, so let's pasted it in, so it's componentDidMount, and then this.props.updateHeader, and then we need a change it to what we see in the design, which is "Welcome, Jordan! HOA Management".
Okay, so let's say Welcome, and then pass in the user name and then we'll say HOA Management and that we want to hide the bar, right? I'll get rid of that ${} for now. Now there's one problem with this, and it's that we don't have access to our actions, so it's going to crash.
So what we need to do in this file is say import connect from react-redux
and then we need to say import * as actions from ../actions
okay so these two imports.
dashboard.js
import React, { Component } from "react"; import { connect } from 'react-redux'; import * as actions from '../action'; import TabNav from './tabnav'; import NewsletterGrid from "./newsletter/newsletterGrid"; import RequestsGrid from "./requests/requestsGrid"; class Dashboard extends Component { componentDidMount() { this.props.updateHeader(`Welcome`, 'HOA Management', true); }
What we need to do now is go down here and just say export default connect(null, actions)(Dashboard);
. Okay so I just imported actions and connect and used them down here. Now we have access to our redux actions and we can pass these in, so let's go check that out now.
Let's log in you'll see it changes and says Welcome HOA Management, and it hides the bar.
Now it's kind of leaving a lot of space, so let's go see what we can do about that because now that bar is gone. Let's go into our layout.js
and what we're going to have to do is basically let's move this hideBar component, let's just get rid of this prop and put it out here okay.
So we'll say this.props.hideBar
and then if it is we will return empty string, and then if it's not we will return HeaderBar. Now this probably isn't going to fix it because if the row is still there, it will still be there. So let's try it out, login and you'll see it's still there.
So this is part of our grid row okay, so inspect, open up layout grid and you'll see we have header and header contains the subtitle still.
Oh not the header but the dashboard. Okay, there's no div but there's that empty row that you can see.
Okay, so what we need to do is say min-max on the header, and let's go try it out okay. So let's go in to layout.scss or where ever we put it. I guess it's in base.scss
and in .layout-grid
what we need to do is change this bar to go from 4em to min-max and we'll say 0 to 4rem.
base.scss
.layout-grid { width: 100vw; height: 100vh; display: grid; grid-template-rows: [page-s header-s] 13.6rem [header-e bar-s] minmax(0, 4rem) [bar-e content-s] 1fr [content-e page-e]; grid-template-columns: [page-s] 14rem [content-s] 1fr [content-e] 14rem [page-e] }
Let's go in and you'll see it moves it up and now it's not there.
The header is there with it's row gap and everything, but you'll see that the header is not there or the subheader, the little bar, at least I don't think it is. Let's change this to 0rem instead of 4rem and see how 0 reacts. Okay, so that pulls it up, so this is what we want to see, let's change it back to 4rem.
All right, so we can either do this all in JavaScript or we could do something like we could, this is interesting because, all right, because I wonder if auto would fix that. Okay, it looks like it hasn't changed which is good, let's come back and you'll see it's there again, log back in and it pulls up. Hey sweet, I'm pretty sure that fixed it let's just check here one more time, yeah that fixed it.
base.scss
.layout-grid { width: 100vw; height: 100vh; display: grid; grid-template-rows: [page-s header-s] 13.6rem [header-e bar-s] auto [bar-e content-s] 1fr [content-e page-e]; grid-template-columns: [page-s] 14rem [content-s] 1fr [content-e] 14rem [page-e] }
Now we should be good there, so let's go back, you'll see that it's there, let's go in here and you'll see it's gone. All right sweet, that fixes that. Now we just need to get in the user name, so we just have one more thing to do before we're done with this video. Okay, let's go into dashboard.js
and let's get the user okay we've got to get the user name, which we can get pretty easily.
Let's scroll down here, and let's implement a function from mapStateToProps and we'll pass in state and then we'll just say return and we'll say state.auth.user, I believe it is. Let's go check in in our DevTools where it is, so state.auth.user.fullName cool, that should be good.
Let's go ahead and go back to the code and let's say state.auth.user.fullName and then we'll give this a prop name of name. Okay, now what we need to do is pass it in to our connect so mapStateToProps.
dashboard.js
function mapStateToProps(state) { return { name: state.auth.user.fullName } } export default connect(mapStateToProps, actions)(Dashboard);
And then we'll scroll up and we will say in brackets here with a dollar sign in front of it we'll say this.props.name, okay, and that will work.
dashboard.js
componentDidMount() { this.props.updateHeader('Welcome ${this.props.name}', 'HOA Management', true); }
Login in and you'll see it says welcome undefined what a great name. All right, so let's go down and see why it's not working. We have it here, oh its probably because we named this wrong, okay this should work lowercase n.
dashboard.js
function mapStateToProps(state) { return { name: state.auth.user.fullname } } export default connect(mapStateToProps, actions)(Dashboard);
Log back in, and you'll see it says Welcome Max Nelson HOA Management.
Awesome! So that works great, and we have all over functionality in here. The app is nearly complete, there's one more thing we have to implement and it's called, what is called, permissions. You'll see that we have access to everything, we want to be able to create users that only have access to certain things, okay.
So let's go ahead and filter what a user can do based on this authentication user admin property,
you see it's set to false, so want we'll have to do is create an account with one set to true and play around with that, and play around on a few accounts. It should be really quick, all it really is, is if statements, it's just if statements throughout the app.
So let's go ahead and or you can call it artificial intelligence, anyway, what we can do is commit our code.
Terminal
git status git add . git commit -m "set header values throughout application" git push origin master
Okay I'll see in the next video!