Skip to content

Instantly share code, notes, and snippets.

@siassaj
Created February 3, 2019 02:58
Show Gist options
  • Select an option

  • Save siassaj/03a6362ad66bfcd8d1b6ab5c5058e24f to your computer and use it in GitHub Desktop.

Select an option

Save siassaj/03a6362ad66bfcd8d1b6ab5c5058e24f to your computer and use it in GitHub Desktop.
import { StateSoruce, Reducer } from '@cycle/state'
import { Stream } from 'xstream'
import { DOMSource, VNode } from '@cycle/dom'
import { HTTPSource, Request } from '@cycle/http'
type Payload = object
interface StoreState = {
userProfile: object
}
type ActionName = "reloadProfile" | "clearSession" | "whateverElse"
interface Action {
category: string
name: ActionName
payload: Payload
}
interface StoreSource {
selectAction: (action: Action) => Stream<Payload>
stream: Stream<StoreState>
}
interface UISources {
DOM: DOMSource,
state: StateSorurce
store: StoreSource
}
interface UISinks {
state: Stream<Reducer>
store: Stream<Action>
DOM: Stream<VNode>
}
interface StoreSources {
HTTP: HTTPSource
state: StateSource
store: StoreSource
}
interface StoreSinks {
HTTP: Stream<Request>
state: Stream<Reducer>
}
// UI Component that displays user profile
function UIMain(sources: UISources): UISinks {
const clickReload$ = sources.DOM.select('.reload').events('click')
const dispatchProfile$ = clickReload$.mapTo({
category: "reloadProfile",
action: "reloadProfile",
payload: {}
})
const showActivityIndicator$ = clickReload$.mapTo(() => prev => ({
...prev,
showActivityIndicator = true
}))
const hideActivityIndicator$ = sources.store.select('reload').flatten().mapTo(() => prev => ({
...prev,
showActivityIndicator = false
}))
const view$ = xs.combine(sources.state.stream, sources.store.stream).
map(state, store => (
div([
state.showActivityIndicator ?
activityIndicator()
:
userProfile(store.userProfile)
])
))
return {
DOM: view(sources.state.stream, sources.store.stream)
state: xs.merge(showActivityIndicator$, hideActivityIndicator$)
store: reloadProfile$
}
}
function StoreMain(sources: StoreSources): StoreSinks {
const reloadProfile$ = sources.store.selectAction('reloadProfile')
const requestProfile$ = reloadProfile$.mapTo({
category: 'requestProfile',
url: "http://somePlace/api/v1/getProfile",
})
const receiveProfile$ = sources.HTTP.select('requestProfile').flatten().
map(response => prev => ({
...prev,
userProfile: response.userProfile
}))
return {
HTTP: requestProfile$
state: receiveProfile$
}
}
interface ActionLifecycleResponse {
status: "received" | "getting" | "setting" | "failure"
category: string
payload: any
}
type ActionResponse$ = Stream<ActionLifecycleResponse>
interface ActionComponentSources {
action: Stream<Payload>
HTTP: HTTPSource
}
interface ActionComponentSinks {
action: Stream<ActionResponse$>
HTTP: Stream<Request>
}
ActionComponent = (sources: ActionComponentSources) => ActionComponentSinks
interface ActionDefinitions {
[k: ActionName]: ActionComponent
}
function createStore(actionDefinitions: ActionDefinitions): store {
const actionSources = constructActionSources
const componentSinks = map(actionDefinitions, (component, actionName) => {
innerSources = {
...actionSources,
action: actionSources.action.select(actionName)
}
const sinks = component(innerSources)
return {
...sinks,
action: sinks.action.map(actionResponse$: ActionResponse$ => {
actionResponse$.actionName = actionName
return actionResponse$
})
}
})
return mergeCompononentSinks(componentSinks)
}
storeSinks = createStore({
reloadProfile: (sources) => {
//...do stuff
return sinks
},
clearSession: (sources) => {
const clear$ = sources.action.mapTo(prev => { ...prev, userProfile: null })
return {
state: clear$
}
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment