Tableau de visualisation SNCF (sorry, post in french only)

Je dois dire que je suis un habitué de l’app fusion de la sncf sobrement appelé « SNCF » https://play.google.com/store/apps/details?id=com.sncf.fusion.
Et rien à dire, elle est plutôt complète puisqu’elle offre la possibilité de visualiser les horaires par gare ou par ligne, où que l’on se trouve.
Elle permet aussi d’avoir toutes les infos « publiées » (donc pas toutes évidemment) sur les difficultés de circulation.

Mais une fonctionnalité, pourtant visible dans toutes les gares, n’est pas offerte à l’identique sur l’app : le tableau de visualisation.
Sur l’app, on voit les horaires, mais il faut toucher chaque passage pour voir la desserte.
J’aimerais bien mieux avoir un écran identique à celui en gare sur mon smartphone.

Certains ont déjà fait une version plutôt fidèle à la réalité : http://monrer.fr, mais ça ne marche qu’autour de paris.

Donc j’ai essayé de la refaire en sauce react-native. Vous pouvez y jeter un coup d’œil à la version expo (n’étant pas encore définitive je ne l’ai pas publiée sur play store) : https://expo.io/@libe/sncf-le-panneau
Il existe encore un ou deux bugs : des fois la desserte est affichée totalement, y compris les gares de provenance, et des fois le défilement de la desserte n’est pas complètement fait (on voit des bouts de la ligne suivante)

Amusez vous bien avec ce prototype.
screenshot_20170731-094208_480_360

react & react native at once : 1 app = 1 program ?

One question everyone is likely to ask one day, while using the react framework, is :

« can I use the same app on a browser AND on a mobile device without rewriting the app ? » In other words, is the principle « write once, run everywhere » respected ?

The short answer is no, and the longer one is « yes but ».
There is a quite simple to trick to make a react app work on different devices.

On a react-web app, you will write this kind of render :
<div>

<div>This is some text</div>
<img src= »logo.png » alt= »this is a picture » />

</div>
Whereas on a react-native app, the layout would look like this one :

<View><Text>This is some text</Text>
<Image source= »logo.png » alt= »this is a picture »/></View>

Quite similar, isn’t it ? But problem is that you cannot declare a common declaration for both environments.

…Or you would need to branch with an if instruction. That will work, but it will make the code less concise and you will have some ‘copy/paste’ sessions between your components.

I found a better option, not the best one (I am more of a beginner in react) : Just provide the same language to both environment. Declare a provider in each environment, and make it provide exactly the same markup with some common attributes.

This is how your code looked like before :

import {View, TextInput} from 'react-native'
export default class Console extends Component {
render(){return (
 <View className="console" style={{height:'100%', width:'100%', flex: 1}}>
 <TextInput id="commandLine" value={this.state.command}/>
 </View>
) /* and it only works on a mobile */
}}

And this is how you can change it to make it work on several envs :

export default class Console extends Component {
render(){
const [View, TextInput] = ['View', 'TextInput'].map(componentName => this.context.componentsProvider(componentName))
return (
 <View className="console" style={{height:'100%', width:'100%', flex: 1}}>
 <TextInput id="commandLine" value={this.state.command}/>
 </View>
) /* and it only works on a mobile */
}}

And last but not least, declare a provider which will gives you these elements :

import { Component } from 'react'
import PropTypes from 'prop-types'

export default class ComponentsProvider extends Component {
    getChildContext() {
        return {
            componentsProvider: this.props.impl,
        }
    }

    render() {
        return this.props.children;
    }
}

ComponentsProvider.propTypes = {
    children: PropTypes.element,
    impl: PropTypes.func.isRequired
}
ComponentsProvider.childContextTypes = {
    componentsProvider: PropTypes.func.isRequired,
}


Your app will need to be surrounded by your provider, in each version :

<ComponentsProvider impl={(name) => nativeMapping(name) || ReactNative[name] || MaterialUi[name] || ReactNative.View}>
    <MaterialUi.ThemeProvider uiTheme={uiTheme}>
        <App muiTheme={uiTheme} />
    </MaterialUi.ThemeProvider>
</ComponentsProvider>


Now you are ready to deploy the same app on different devices with very little effort.

Please have a look at my NON-HELLOWORLD example : https://github.com/libetl/amadeus-console
I deployed the same app on google chrome and android. The app is what you see on the screen when you board in a plane or when you complain about your flight booking. The UI is a kind of a console which can help you manage all your bookings.