Monday, 11 November 2019

Passing user permission from child to parent component with ReactJS

I am currently trying to past data from a function to a parent component and then to a child component.

I have a function called FetchUserPermissions which queries a mock database and returns a list of user permissions. I need to pass that list of permissions to the parenting root component App and then to a component which restricts the users ability to view different elements in the UI.

What I exactly struggling to do is, to pass my response from the fetch request, to the parenting component and then to the other children.

My login and user permissions are not the first page a user sees when he accesses the application. Therefore I can't pass them from the top of the component tree.

Here is my FetchUserPermissions function that I use to get the user permissions:

function FetchUserPermissions() {
  const userRole = localStorage.getItem("role");
  const accessToken = localStorage.getItem("accesstoken");
  const requestOptions = {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      accesstoken: accessToken,
      role: userRole
    }
  };
  if (userRole !== null) {
    fetch(
      process.env.REACT_APP_API_URL + "/authenticated/get-roles",
      requestOptions
    ).then(response => response.json());
    //set the response as a state.
    // So that state can be passed as props to the CAN component.
  } else {
    console.log("not loggedin === no user permissions.");
  }
}

export default FetchUserPermissions;

This is the Can component, which aims to restrict user views and abilities in the UI, based on the user role.

const check = (rules, role, action, data) => {
  const permissions = rules[role];

  if (!permissions) {
    // role is not present in the rules
    return false;
  }

  const staticPermissions = permissions.static;
  if (staticPermissions && staticPermissions.includes(action)) {
    // static rule not provided for action
    return true;
  }

  const dynamicPermissions = permissions.dynamic;

  if (dynamicPermissions) {
    const permissionCondition = dynamicPermissions[action];
    if (!permissionCondition) {
      // dynamic rule not provided for action
      return false;
    }

    return permissionCondition(data);
  }
  return false;
};

const Can = props =>
  check(rules, props.role, props.perform, props.data)
    ? props.yes()
    : props.no();

Can.defaultProps = {
  yes: () => null,
  no: () => null
};

export default Can;

I thought that maybe I could export the FetchUserPermissions component as a Context and pass the data that way but I couldn't figure out how to do it.

One thing I don't wanna do for sure is to call out the fetch request, each time the user uses the Can component, because that will put too much strain on the database.

Here is how the Can component will be used in different pages:

  <div className="home">
    <h1>Mock Admin Page...</h1>
    <h3>{mockDataFetched}</h3>
    <Can
      role={userRole}
      perform="dashboard-page:visit"
      yes={() => (
        <div>
          <h1>Admin Dashboard</h1>
        </div>
      )}
      no={() => (
        <div>
          <h1>Non Admin Dashboard</h1>
        </div>
      )}
    />
  </div>
);

If there is anything unclear about my question, I'll happily provide additional information. Thank you in advance.

------ EDIT -------

Here's my APP component, it contains only a Switch and Router Elements:

function App() {
  return (
    <div>
      {/* Where the main router is innitiated. */}
      <BrowserRouter>
        <div className="container">
          <Header />
          <Switch>
            <Route exact path="/" component={Home} />
            {/* custom dummy page. to be removed.*/}
            <Route exact path="/page-one" component={CustomPage} />
            <Route exact path="/login" component={LoginPage} />
            <PrivateRoute exact path="/admin-board" component={AdminPage} />
          </Switch>
        </div>
      </BrowserRouter>
    </div>
  );
}

export default App;

-------------- 2nd EDIT-------------------------------------------------------

After applying all the suggested changes, I keep getting:

./src/views/routes/Can.js
  Line 2:  'usePermissions' is not defined  no-undef

Search for the keywords to learn more about each error.


from Passing user permission from child to parent component with ReactJS

No comments:

Post a Comment