Skip to content

Instantly share code, notes, and snippets.

@mattpocock
Last active May 28, 2019 15:42
Show Gist options
  • Select an option

  • Save mattpocock/de1b1982dc86ebfa91af78fd3ab6cd61 to your computer and use it in GitHub Desktop.

Select an option

Save mattpocock/de1b1982dc86ebfa91af78fd3ab6cd61 to your computer and use it in GitHub Desktop.
withFluxStore
/**
* Composes single-argument functions from right to left. The rightmost
* function can take multiple arguments as it provides the signature for
* the resulting composite function.
*
* @param {...Function} funcs The functions to compose.
* @returns {Function} A function obtained by composing the argument functions
* from right to left. For example, compose(f, g, h) is identical to doing
* (...args) => f(g(h(...args))).
*/
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
// React
import React from 'react'
import { Localisation } from 'javascript/config/features'
// Stores
import PagesStore from 'javascript/stores/pages'
// Actions
import PagesActions from 'javascript/actions/pages'
// Components
import PageLoader from 'javascript/components/page-loader'
import Blocks from 'javascript/views/blocks'
import Meta from 'react-document-meta'
import ListModal from 'javascript/components/list-modal'
import Modal from 'javascript/components/modal'
import compose from 'javascript/utils/compose';
import withPageHelper from 'javascript/utils/withPageHelper';
import withFluxStore from 'javascript/utils/withFluxStore';
class Home extends React.Component {
constructor(props) {
super(props)
this.state = {
modal: () => { }
}
}
componentDidMount() {
PagesActions.getResources({
include: 'page-images,meta-datum',
fields: {
'page-images': 'file,filename',
'pages': 'content-blocks,page-images,meta-datum',
'meta-datums': 'title,keywords,description'
},
filter: {
slug: Localisation.home.lower
}
})
}
addToList = (resource) => () => {
this.setState(() => ({
modal: () => (
<Modal delay={500} ref="modal" customContent={true} modifiers={['custom-content']}>
<ListModal resource={resource} closeEvent={this.unsetModal} user={this.props.user} />
</Modal>
)
}))
return false
}
render() {
const { pageLoadState, resource = {} } = this.props;
return (
<Meta
title={resource['meta-datum'] && resource['meta-datum'].title || resource.title}
meta={{
description: resource['meta-datum'] && resource['meta-datum'].description || '',
keywords: resource['meta-datum'] && resource['meta-datum'].keywords || ''
}}>
<PageLoader {...pageLoadState}>
<main>
<div className="fade-on-load">
{(resource['content-blocks'] || []).map((block) => {
const bgImage = block.bgImage ? resource['page-images'].find(i => i.id === block.bgImage.id) : null
return (
/* #region ae | banijay | cineflix | demo | drg | itv | keshet | rtv | sky */
<section key={block.id} className={[block.type !== 'banner-carousel' && 'content-block', block.type, block.background].join(' content-block--')} style={block.background === 'image' && bgImage ? {
backgroundImage: `url(${bgImage.file.url.replace('.net/', '.net/1600x600/')})`,
/* #region itv */
backgroundSize: 'cover'
/* #endregion */
} : null}>
/* #endregion */</section>
/* #region amc */
<section key={block.id} className={[block.type !== 'banner-carousel' && 'content-block', block.type, block.background, block.fullWidth && 'full'].join(' content-block--')} style={block.background === 'image' && bgImage ? {
backgroundImage: `url(${bgImage.file.url.replace('.net/', '.net/1600x600/')})`
} : null}>
/* #endregion */ </section>
/* #region all3 */
<section key={block.id} className={[block.type !== 'banner-carousel' && 'content-block', block.type, block.background].join(' content-block--')} >
{block.background === 'image' && bgImage && (
<img className="content-block__bg-image" src={bgImage.file.url.replace('.net/', '.net/1600x600/')} />
)}
/* #endregion */
<div className={(block.type !== 'html-markup' && block.type !== 'banner-carousel' && block.type !== 'promo-carousel' && block.type !== 'text-and-items' && block.type !== 'related-pages') ? 'container' : 'content-block__inner'}>
{Blocks(block, {
'page-images': resource['page-images']
}, { user: this.props.user, addToList: this.addToList })}
</div>
</section>
)
})}
</div>
/* #region ae | all3 | banijay | cineflix | demo | drg | itv | keshet | rtv | sky */
{this.state.modal()}
/* #endregion */
</main>
</PageLoader>
</Meta>
)
}
}
export default compose(
withPageHelper,
withFluxStore({
store: PagesStore,
changeEventKey: 'change',
handleChange: ({ store, setPassedDownProps, props }) => {
const resource = store.getResources()[0]
if (resource) {
setPassedDownProps({ resource })
props.finishedLoading()
}
}
}),
)(Home)
import React, { useEffect, useState } from 'react'
const withFluxStore = ({
store,
changeEventKey,
handleChange
}) => Component => props => {
const [hasConnected, setHasConnected] = useState(false)
const [passedDownProps, setPassedDownProps] = useState({})
const callHandleChangeCallback = () => {
handleChange({ store, props, setPassedDownProps })
}
useEffect(() => {
store.on(changeEventKey, callHandleChangeCallback)
setHasConnected(true)
return () => {
if (store.removeEventListener) {
store.removeEventListener(changeEventKey, callHandleChangeCallback)
}
}
}, [])
if (!hasConnected) {
return null
}
return <Component {...props} {...passedDownProps} />
}
export default withFluxStore
import React from 'react'
import { useState } from 'react'
const withPageHelper = Component => props => {
const [errored, setErrored] = useState(false)
const [loaded, setLoaded] = useState(false)
const receivedError = () => {
setErrored(true)
}
const finishedLoading = () => {
setLoaded(true)
}
return (
<Component
{...props}
finishedLoading={finishedLoading}
receivedError={receivedError}
pageLoadState={{ errored, loaded }}
/>
)
}
export default withPageHelper
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment