reapp / reapp-routes

Simple route DSL
MIT License
34 stars 13 forks source link

Conditional routes #6

Open clauderic opened 9 years ago

clauderic commented 9 years ago

How would you go about having a conditional default route? For example, if a user is logged out, show the login screen, otherwise, skip the login and show the app home screen.

natew commented 9 years ago

I do this in an app I'm building:

// auto requires files based on name
router(require,
  route('app', '/', { dir: '' },
    route('loading', { default: true }),
    route('splash'),
    route('tasks',
      route('create', '/tasks/create'),
      route('view', '/tasks/:id')
    ),
    route('auth', '/',
      route('cb', '/'),
      route('signin')
    )
  )
);

And in my root App.jsx

class App extends React.Component {
  componentDidMount() {
    if (!loggedIn) this.router().transitionTo('/auth/signin')
    else this.router().transitionTo('/tasks')

  }

  render() {
    return this.props.child();
  }
}
natew commented 9 years ago

Make sure in this example in your Tasks.jsx file you need to have it be a React.Page to handle sub-routes like so (this should be cleaned up in the future):

import { React } from 'reapp-kit';

export default class extends React.Page {
  render() {
    return (
      <ViewList
        {...this.routedViewListProps()}>

        <View></View>

        {this.childRouteHandler()}
      </ViewList>
    );
  }
};

Notice this.routedViewListProps(), this.childRouteHandler(); and React.Page usage. This is handled automatically for you with your root route, but for sub-routes you'll need to set it up like this.

clauderic commented 9 years ago

Ah, perfect, worked like a charm, thank you. I was fairly close, had missed a couple of details though.

Would be nice to have this a little more documented. For instance, is there any way to control the direction from which views can transition in? I.e. it would be nice to be able to transition a view in from the bottom a la Ionic Modal or Touchstone view transitions

natew commented 9 years ago

You can actually do this (I have it working today). I'd like to write a tutorial, but you can by using a plain ViewList, and then import the behavior for NestedViewListBehavior and DrawerViewListBehavior. Have your initial state be Nested, and spread it to the viewlist, then update it to Drawer when you need and it will just work. Taken from mine:

import {
  React,
  ViewList,
  View,
  DrawerViewListBehavior,
  NestedViewListBehavior } from 'reapp-kit';

class Tasks extends React.Page {
  constructor(props) {
    super(props);
    this.state = {
      behavior: NestedViewListBehavior
    };
  }

  componentWillMount() {
    if (this.router().getCurrentPathname().match(/create/))
      this.setState({ behavior: DrawerViewListBehavior });
  }

  handleAdd() {
    this.action.disableKeyboardScroll();
    this.setState({ behavior: DrawerViewListBehavior }, () => this.goTo('/tasks/create'));
  }

  handleView(id) {
    this.setState({ behavior: NestedViewListBehavior }, () => this.goTo(`/tasks/${id}`));
  }

  // bugfix ios/web
  goTo(path) {
    setTimeout(() => this.router().transitionTo(path), 10)
  }

  render() {
    return (
      <ViewList
        {...this.state.behavior}
        {...this.routedViewListProps()}>

        <View>
        </View>

        {this.childRouteHandler({ id })}
      </ViewList>
    );
  }
}

If you get this all working and are feeling in a charitable mood, would love some docs help, even if it was just in the form of a super quick article on getting this working! :smile:

clauderic commented 9 years ago

Ah, very slick, got it to work. Only small thing I've noticed is that the sub-view ends up 44px from the top (see the matrix3d in attached screenshot), not sure if this is expected behaviour?

alt text

Also, I was wondering, from this point, is it possible or would it be possible to also have nested views within that drawer? I've attempted to get it to work but to no avail.

As for a tutorial, I could give a stab at it within the next few weeks. I'm in the process of transitioning a large Ionic application to Reapp due to poor Ionic/Angular performance, so I'm most definitely going to be documenting the process and writing an article about it once the transition is complete and would happily help out with any help you'd want on docs.

natew commented 9 years ago

Yea I had it because its meant to mimic the way drawers slide up but not all the way. You'd have to change the animation on the ViewList (load in a new animation) which requires modifying the theme. Not too hard but also not well documented.

You could do nested within the drawer, you'd just need to keep nesting ViewLists. Just keep playing with it.

I want to work on next a pushable navigation system much like native and I think Ionic has it as well. Would make this stuff easier to use, but its a pretty big size project.

clauderic commented 9 years ago

Got it, created a new animations.js file under /theme and called it in /app/theme/index.js under theme({animations: [iOS.animations, require('./animations)]}) and it worked. Only thing is I had to call AnimationHelpers file with the direct path to the file (/node_modules/...), not sure if there's a better way to import that file (i.e., through an export of that file in reapp-ui, something like import AnimationHelpers from 'reapp-ui/lib/AnimationHelpers';)

As for nesting within the drawer, I've tried setting up the Drawer view as follows but it doesn't work, and no error is thrown:

 class Drawer extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            step: 0
        }
    }
    render() {
        return (
            <View {...this.props}>
                <ViewList scrollToStep={this.state.step}>
                    <View title="First view">
                    <p>Hello, from the sub route!</p>
                        <p>You can drag from the left side of the screen to drag this view back out</p>
                        <p>Ready to deploy? Run <code>reapp build</code> and check your build directory</p>

                        <Button onTap={() => this.setState({ step: 1 })}>
                            Go to nested sub view
                        </Button>
                    </View>
                    <View title="Second view">
                      <p>Hello, from the second sub route!</p>
                      <Button onTap={() => this.setState({ step: 0 })}>
                        Go back to first view
                      </Button>
                    </View>
                </ViewList>
            </View>
        );
    }
}

Both sub views appear on top of each other inside of the drawer. I've also tried setting up as a React.Page as stated above but also to no avail. I took inspiration from https://github.com/reapp/kitchen-sink/blob/master/app/components/kitchen/ViewLists.jsx for the sub-views, not sure if that's still best practice.

Here is the kind of setup I'd ideally like to have

route('home', '/home',
    route('drawer',
        route('sub1'),
        route('sub2'),
        route('sub3',
            route('sub3-1'),
            route('sub3-2')
        )
    )
)
natew commented 9 years ago

Nice! Glad that worked without much pain, happy to see the system is working in general.

As for animation helpers you are right, I should export that. For now you should be safe.

And yea, the kitchen sink example is about right.

Rather than ViewList I'd use NestedViewList since it has the styles/behavior. You can't use a ViewList without props, and Nested gives you that view. Sorry I wasn't explicit on that earlier.

clauderic commented 9 years ago

Ah wonderful, didn't realize there was a distinction between ViewList and NestedViewList. Works like a charm :)

clauderic commented 9 years ago

Only bug i've noticed is if you use the Swipe from the edge to go back feature and pull down at the same time as you pull back, it tries to close the drawer at the same time as it tries to go back to the previous nested sub-view.

Here's an example: alt text

natew commented 9 years ago

You've got to disable the parent view list once you nest in. See your previous link:

https://github.com/reapp/kitchen-sink/blob/master/app/components/kitchen/ViewLists.jsx

the this.props.disableParentViewList, which then calls this:

https://github.com/reapp/kitchen-sink/blob/23e3d4dad2c0406469b840d9c0066ad1c4648de1/app/components/Kitchen.jsx#L150

You can call that on mount or like I do after it goes ahead one view. It should be pretty flexible because you could also pass in different touchable areas to your parent view list.