krasimir/navigo

Support for "detour" routes

mrbrahman opened this issue · 2 comments

In almost all systems where login is needed, and which supports sharing of links, say when a link like http://abc.com/#/about is shared, if the user has not already logged in, the system prompts for login, and upon successful login takes the user directly to the about view.

I am trying to implement something similar with Navigo, but am stuck. While Navigo does have Hooks, it seems there is no way to take a "detour" (i.e. first login, and then actual requested page).

Here's my made up example.

<div id="app"></div>

<script src="https://unpkg.com/navigo"></script>
<script>
  const router = new Navigo('/', {hash: true});
  const app = document.getElementById('app');

  let loggedIn = false;

  router.on('/login', function(){
    console.log('**** in login');
    app.innerHTML = `
    <h1>Login</h1>
    <input type=button id="submit" value="Click to login"></input>
    `
    document.getElementById('submit').addEventListener('click', ()=>{
      loggedIn=true;
      alert('you are now logged in!');
      router.navigate('/home');  // would be nice to navigate to the actual view the user wanted
    })
  });

  router.hooks({
    before(done, match){
      console.log('check if logged in');
      if(loggedIn){
        done()
      } else {
        console.log('need to login');
        done(false);
        router.navigate('/login');   // take a detour
      }
    }
  });

  router.on('/home', ()=>{
    console.log('in home');
    app.innerText = "In home"
  });

  router.on('/about', function(){
    console.log('in about');
    app.innerText = "In about"
  });

  router.on('/photos', function(){
    console.log('in photos');
    app.innerText = "In photos"
  });

  router.on('/videos', function(){
    console.log('in videos');
    app.innerText = "In videos"
  });

  router.on('/logout', function(){
    console.log('in logout');
    loggedIn = false;
    app.innerText = "Logged out"
  });

  router.on('/', function(){
    console.log('in /');
    router.navigate('/home')
  });

  router.resolve();

</script>

In the example above, upon successful login, the user is always directed to /home as that is hardcoded. It would be nice if the user is directed to whichever view/page was in the original link. And if there was none (i.e. the user wants to hit the home page), then redirect appropriately.

Thanks for your consideration.

I did manage to do a hacky, dirty workaround - by capturing the done before it is called and then, call it later when needed. See next() in the code below.

<div id="app"></div>

<script src="https://unpkg.com/navigo"></script>
<script>
  const router = new Navigo('/', {hash: true});
  const app = document.getElementById('app');

  let loggedIn = false;
  var next;

  router.on('/login', function(){
    console.log('**** in login');
    // console.log(next);
    app.innerHTML = `
    <h1>Login</h1>
    <input type=button id="submit" value="Click to login"></input>
    `
    document.getElementById('submit').addEventListener('click', ()=>{
      loggedIn=true;
      alert('you are now logged in!');
      if(next){
        next()                         // 2. call here
      } else {
        router.navigate('/home');
      }
    })
  });

  router.hooks({
    before(done, match){
      console.log('check if logged in');
      if(loggedIn){
        done()
      } else {
        console.log('need to login');
        next = done;                   // 1. capture here
        done(false);
        router.navigate('/login');
      }
    }
  });

  router.on('/home', ()=>{
    console.log('in home');
    app.innerText = "In home"
  });

  router.on('/about', function(){
    console.log('in about');
    app.innerText = "In about"
  });

  router.on('/photos', function(){
    console.log('in photos');
    app.innerText = "In photos"
  });

  router.on('/videos', function(){
    console.log('in videos');
    app.innerText = "In videos"
  });

  router.on('/logout', function(){
    console.log('in logout');
    loggedIn = false;
    app.innerText = "Logged out"
  });

  router.on('/', function(){
    console.log('in /');
    router.navigate('/home')
  });

  router.resolve();
  // router.navigate('/photos');

</script>

However, with this the URL is not changed upon successful login. For e.g.

Screen Shot 2022-12-11 at 12 00 09 AM

Would love to see a cleaner solution!

@mrbrahman A common approach is to store the URL in localStorage/sessionStorage before redirecting to /login. Then after the user logs in you check localStorage to see if there's a URL there. If there is a URL, then you redirect to it, otherwise redirect to /home.