feat: redirect after login when applicable
This commit is contained in:
parent
04c12e4da9
commit
e2634dc490
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Switch, Route, useHistory } from 'react-router-dom';
|
||||
import { Switch, Route, useHistory, useLocation, Redirect } from 'react-router-dom';
|
||||
import * as H from 'history';
|
||||
|
||||
import Dashboard from 'Dashboard';
|
||||
@ -29,8 +29,27 @@ type ValidateTokenResponse = {
|
||||
userID: string;
|
||||
};
|
||||
|
||||
const AuthorizedRoutes = () => {
|
||||
const history = useHistory();
|
||||
const UserRequiredRoute: React.FC<any> = ({ children }) => {
|
||||
const { user } = useCurrentUser();
|
||||
const location = useLocation();
|
||||
if (user) {
|
||||
return children;
|
||||
}
|
||||
return (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: '/login',
|
||||
state: { redirect: location.pathname },
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
type RoutesProps = {
|
||||
history: H.History;
|
||||
};
|
||||
|
||||
const Routes: React.FC<RoutesProps> = () => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { setUser } = useCurrentUser();
|
||||
useEffect(() => {
|
||||
@ -38,7 +57,6 @@ const AuthorizedRoutes = () => {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
}).then(async x => {
|
||||
const { status } = x;
|
||||
const response: ValidateTokenResponse = await x.json();
|
||||
const { valid, userID } = response;
|
||||
if (valid) {
|
||||
@ -47,32 +65,28 @@ const AuthorizedRoutes = () => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
return loading ? null : (
|
||||
if (loading) return null;
|
||||
return (
|
||||
<Switch>
|
||||
<MainContent>
|
||||
<Route exact path="/" component={Dashboard} />
|
||||
<Route exact path="/projects" component={Projects} />
|
||||
<Route path="/projects/:projectID" component={Project} />
|
||||
<Route path="/teams/:teamID" component={Teams} />
|
||||
<Route path="/profile" component={Profile} />
|
||||
<Route path="/admin" component={Admin} />
|
||||
<Route path="/tasks" component={MyTasks} />
|
||||
</MainContent>
|
||||
<Route exact path="/login" component={Login} />
|
||||
<Route exact path="/register" component={Register} />
|
||||
<Route exact path="/confirm" component={Confirm} />
|
||||
<Switch>
|
||||
<MainContent>
|
||||
<Route path="/projects/:projectID" component={Project} />
|
||||
|
||||
<UserRequiredRoute>
|
||||
<Route exact path="/" component={Dashboard} />
|
||||
<Route exact path="/projects" component={Projects} />
|
||||
<Route path="/teams/:teamID" component={Teams} />
|
||||
<Route path="/profile" component={Profile} />
|
||||
<Route path="/admin" component={Admin} />
|
||||
<Route path="/tasks" component={MyTasks} />
|
||||
</UserRequiredRoute>
|
||||
</MainContent>
|
||||
</Switch>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
type RoutesProps = {
|
||||
history: H.History;
|
||||
};
|
||||
|
||||
const Routes: React.FC<RoutesProps> = () => (
|
||||
<Switch>
|
||||
<Route exact path="/login" component={Login} />
|
||||
<Route exact path="/register" component={Register} />
|
||||
<Route exact path="/confirm" component={Confirm} />
|
||||
<AuthorizedRoutes />
|
||||
</Switch>
|
||||
);
|
||||
|
||||
export default Routes;
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import TopNavbar, { MenuItem } from 'shared/components/TopNavbar';
|
||||
import LoggedOutNavbar from 'shared/components/TopNavbar/LoggedOut';
|
||||
import { ProfileMenu } from 'shared/components/DropdownMenu';
|
||||
import { useHistory } from 'react-router';
|
||||
import { useHistory, useRouteMatch } from 'react-router';
|
||||
import { useCurrentUser } from 'App/context';
|
||||
import { RoleCode, useTopNavbarQuery } from 'shared/generated/graphql';
|
||||
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||
@ -234,6 +234,7 @@ const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({
|
||||
onRemoveFromBoard,
|
||||
}) => {
|
||||
const { user } = useCurrentUser();
|
||||
const match = useRouteMatch();
|
||||
if (user) {
|
||||
return (
|
||||
<LoggedInNavbar
|
||||
@ -255,7 +256,7 @@ const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <LoggedOutNavbar name={name} menuType={menuType} />;
|
||||
return <LoggedOutNavbar match={match.url} name={name} menuType={menuType} />;
|
||||
};
|
||||
|
||||
export default GlobalTopNavbar;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect, useContext } from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
import { useHistory, useLocation } from 'react-router';
|
||||
import Login from 'shared/components/Login';
|
||||
import UserContext from 'App/context';
|
||||
import { Container, LoginWrapper } from './Styles';
|
||||
@ -7,6 +7,7 @@ import { Container, LoginWrapper } from './Styles';
|
||||
const Auth = () => {
|
||||
const [invalidLoginAttempt, setInvalidLoginAttempt] = useState(0);
|
||||
const history = useHistory();
|
||||
const location = useLocation<{ redirect: string } | undefined>();
|
||||
const { setUser } = useContext(UserContext);
|
||||
const login = (
|
||||
data: LoginFormData,
|
||||
@ -30,7 +31,11 @@ const Auth = () => {
|
||||
const response = await x.json();
|
||||
const { userID } = response;
|
||||
setUser(userID);
|
||||
history.push('/');
|
||||
if (location.state && location.state.redirect) {
|
||||
history.push(location.state.redirect);
|
||||
} else {
|
||||
history.push('/');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -12,9 +12,10 @@ export type MenuItem = {
|
||||
type NavBarProps = {
|
||||
menuType?: Array<MenuItem> | null;
|
||||
name: string | null;
|
||||
match: string;
|
||||
};
|
||||
|
||||
const NavBar: React.FC<NavBarProps> = ({ menuType, name }) => {
|
||||
const NavBar: React.FC<NavBarProps> = ({ menuType, name, match }) => {
|
||||
return (
|
||||
<S.NavbarWrapper>
|
||||
<S.NavbarHeader>
|
||||
@ -51,7 +52,12 @@ const NavBar: React.FC<NavBarProps> = ({ menuType, name }) => {
|
||||
<S.TaskcafeTitle>Taskcafé</S.TaskcafeTitle>
|
||||
</S.LogoContainer>
|
||||
<S.GlobalActions>
|
||||
<Link to="/login">
|
||||
<Link
|
||||
to={{
|
||||
pathname: '/login',
|
||||
state: { redirect: match },
|
||||
}}
|
||||
>
|
||||
<S.SignIn>Sign In</S.SignIn>
|
||||
</Link>
|
||||
</S.GlobalActions>
|
||||
|
@ -33,24 +33,19 @@ func NewHandler(repo db.Repository, emailConfig utils.EmailConfig) http.Handler
|
||||
},
|
||||
}
|
||||
c.Directives.HasRole = func(ctx context.Context, obj interface{}, next graphql.Resolver, roles []RoleLevel, level ActionLevel, typeArg ObjectType) (interface{}, error) {
|
||||
/*
|
||||
TODO: add permission check
|
||||
role, ok := GetUserRole(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("user ID is missing")
|
||||
}
|
||||
if role == "admin" {
|
||||
return next(ctx)
|
||||
} else if level == ActionLevelOrg {
|
||||
return nil, errors.New("must be an org admin")
|
||||
}
|
||||
*/
|
||||
|
||||
userID, ok := GetUserID(ctx)
|
||||
userID, ok := GetUser(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("user must be logged in")
|
||||
}
|
||||
log.Info("has role")
|
||||
user, err := repo.GetUserAccountByID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user.RoleCode == "admin" {
|
||||
return next(ctx)
|
||||
} else if level == ActionLevelOrg {
|
||||
return nil, errors.New("must be an org admin")
|
||||
}
|
||||
|
||||
var subjectID uuid.UUID
|
||||
in := graphql.GetFieldContext(ctx).Args["input"]
|
||||
@ -90,7 +85,6 @@ func NewHandler(repo db.Repository, emailConfig utils.EmailConfig) http.Handler
|
||||
return nil, errors.New("error while casting subject uuid")
|
||||
}
|
||||
|
||||
var err error
|
||||
if level == ActionLevelProject {
|
||||
logger.New(ctx).WithFields(log.Fields{"subjectID": subjectID}).Info("fetching subject ID by typeArg")
|
||||
if typeArg == ObjectTypeTask {
|
||||
|
Loading…
Reference in New Issue
Block a user