www.carecom.de is an universal (isomorphic) React Single Page Application (SPA) using Redux, React-Router, TypeScript, Bootstrap and an ASP.NET Core backend.

It's based on the excellent Microsoft ASP.NET Core JavaScript Services project. Some extensions stem from the great community on Github other I've implemented on my own:

  • Multi-tenant support so I can easily reuse all this goodness for my customers
  • Localization (client & server)
  • Meta tags and titles
  • Added Google Analytics component
  • Added Google Ads component
  • Added cookie warning component
  • Added gross / net price switcher component
  • Added basic authentication support
  • Added modal dialog component
  • Added contact form component
  • Added code prettify component
  • Added smooth scroll / scroll to hashtag component
  • Sitemap.xml
  • Transfer of "global state" between server and client
  • Improved cookie handling
  • Nested redux reducers
  • ...

Over time I will add to this blog entry detailing more aspects of the app design. Explaining the underlying technologies is out of scope for this post.

For now it's more of a stub for things to come.

I love it

  • how easy Redux makes it to create reusable components – or just components on the fly like
    let PhotographySlider = (props) =>
            <Slider id="PhotographySlider" baseUrl="/tenants/carecom/images/photography/slides/" fromNr={1} toNr={42} />
  • the elegance of ES6, like object destructuringes6 destructuring objects
  • ...

Let's have a look at part of the main React Layout component (written using JSX; code in {} is TypeScript) for the site:

        return <div className="layoutContainer">
            <DocumentMeta {...getMeta()} />

            <NavMenu userId={this.props.userId} isLoggedIn={this.props.isLoggedIn} onLogout={this.props.onLogout} />
            {this.props.slider}

            <main className='container mainLayoutContainer'>
                {
                    breadCrumb &&
                    <div className='row hidden-xs hidden-sm'>
                        <div className='col-md-6 breadCrumb'>{breadCrumb}</div>
                    </div>
                }
                
                {
                    title &&
                    <div className='row'>
                        <header className={`col-md - ${(side ? 0 : 3) + (translations ? 6 : 9)} col-xs - ${ translations ? 9 : 12 } `}>
                            <h1>{title}</h1>
                        </header>

                        {
                            translations &&
                            <div className='col-xs-3 translations'>
                                <span className='glyphicon glyphicon-flag'></span>&nbsp;{translations}
                            </div>
                        }
                    </div>
                }

                <div className='row'>
                    <div className={`col- md - ${side ? 9 : 12 }`} role='main'>{ this.props.body }</div>

                    {
                        side &&
                        <aside className='col-md-3'>{ side }</aside>
                    }
                </div>

            </main>

            <footer>
                <BottomMenu />
                <Footer />
            </footer>
        </div>

DocumentMeta (from React Document Meta) ensures that info like title, description, meta tags will be associated with the component using this Layout.getMeta() is from a helper module that gets the meta info for the current route.

Breadcrumb, title & translations (links to other language versions of a route) will only be rendered if they are supplied by the current route.


export default (
    <Route path='/' component={Layout}>
        { /* de */ }
        <IndexRoute components={EnhHomeComp} />

        <Route path="de">
            <IndexRoute components={EnhHomeComp} />
          
            <Route path='consulting'>
                <IndexRoute components={{ body: Consulting, side: ConsultingQuotation }} />
                <Route path='informatiker' components={{ body: ComputerScientist, side: SideHaraldMuehlhoff }} />
                <Route path='referenzen' components={{ body: ConsultingReferences }} />
                <Route path='remote-support' components={{ body: RemoteSupport, side: SideHaraldMuehlhoff }} />
            </Route>

            <Route path='distribution'>
                <IndexRoute components={{ body: Distribution, side: DistributionQuotation }} />
                <Route path='referenzen' components={{ body: DistributionReferences }} />
                <Route path='selbstbedienung' components={{ body: SelfService }} />
            </Route>

E.g. not every Route has a side component. This has effects on the applied bootstrap styles (className={`col-md-${side ? 9 : 12}`}).