What Happened
I have been working on an esports news submission web application for the last 2 months now (with a hearty break during December, so maybe closer to a month). Recently, I completed the article submission component. I mounted this component through a submit article page on the site. After getting the functionality running I wanted to make it so only users could submit an article. And, rather than having them write out the article to only be denied, I thought "why not let them know upfront you have to be logged in to submit an article?"
I started working through this process. My initial idea was to run a current user query within the component to get access to the current user's id. If this didn't return any data then I would know that the user was not logged in. After writing this up I could not find a way to encapsulate the submission Mutation within a user Query. After trying a few different methods everyone returned errors. Taking a step back I saw a solution.
The Solution
Taking that step back I saw a solution on the Next.js page that is used to mount the article submission component. By utilizing the <User>
component, I could wrap the <Submit>
component within the <User>
component's returned data. For further clarity, here is the full <User>
component:
import { Query } from "react-apollo"; import gql from "graphql-tag"; import PropTypes from "prop-types"; const CURRENT_USER_QUERY = gql` query { me { id email name permissions } } `; const User = props => ( <Query {...props} query={CURRENT_USER_QUERY}> {payload => props.children(payload)} </Query> ); User.propTypes = { children: PropTypes.func.isRequired }; export default User; export { CURRENT_USER_QUERY };
So, if we take that payload
returned from the component we can pass this to the <Submit>
component via a prop. Taking this approach we can change our submit.js
page from
import React, { Component } from "react"; import Submit from "../components/Submit"; const submit = () => <Submit />; export default submit;
To something that will gather data from the <User>
component.
import React, { Component } from "react"; import { Query } from "react-apollo"; import Submit from "../components/Submit"; import User from "../components/User"; import Signin from "../components/Signin"; const submit = () => <User>{({ data }) => <Submit isLoggedIn={data} />}</User>; export default submit;
The payload here is then passed to <Submit>
within the isLoggedIn
prop. Taking that prop, we can use some if/else statements to either render the submission form or render a login page, depending on what the current user status is.
render() { if (this.props.isLoggedIn.me) { return ( Submission form code here ) } else { login form, message, or redirect here } }
So, if isLoggedIn.me
exists, then the user is logged in. The me
part of this comes from the CURRENT_USER_QUERY. The query returns id, email, name, permission
. We could use any one of these, including isLoggedIn.me.permission
to make sure they are part of a group authorized to access this, but within the web application, any logged-in user is allowed to submit an article.
The Conclusion
This strategy could be utilized for any level of authorization. If this was an admin form I could take the returned data and look for the permission part of the object (this is defined in the query from <User>
and stored in the database for each user). This particular time, I only look for any data at all. As long as that data exists, the user is logged in. This is another excellent lesson in always taking a step back in what we are doing. I spent longer on this then I should but it was because I tried so many different iterations of how I thought it was supposed to work, rather than taking a few minutes to review my thought process and take a different approach.
Thank you for reading. As always, feel free to leave any comments about the code, my thought process, what I could be doing better, or just saying hey.
Top comments (0)