0.0.3 • Published 2 years ago

@claritale/react-fx-hook v0.0.3

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

@claritale/react-fx-hook

Just another React custom Hook for managing components Logic/Effects

Try this demo!

This library was generated with Nx.

NPM JavaScript Style Guide

Install

npm install --save @claritale/react-fx-hook

Usage

Once upon a ....well, just try to follow the Tale :)

import React from 'react'

// @here, Import the Hook and Phases to drive your widget // (I prefer to put my logic/effects in a separate file, as I do with styles) import { useLogic, logicPhases } from '@claritale/react-fx-hook'

// This will be a pure presentational component import MyOffersSellingDialog from './MyOffersSellingDialog'

const logicSetup = { mainLogicGen: AppLogic, initialState: InitialState, actionsMap: ActionsMap, }

const MyAppSellWidget = (props) => {

const state, actions = useLogic(logicSetup, props);

const { info, error } = state;

return (

<div className={'App'}>
  <h1>Offers Selling App Widget</h1>

  <MyOffersSellingDialog
    info={info}
    error={error}
    onSelect={(opt) => actions.select(opt)}      
  />
</div> 

) }

MyAppSellWidget.propTypes = { complete: PropType.func.required }

// -------------------------------

/**

  • Now, let's setup state initial values and the expected actions map
  • (to really have fully working type-checking, these declarations
  • should be either in typescript, flow, or jsDoc annotations) */ const InitialState = { info: { step: '', title: '', subtitle: '', opts: [] }, error: '', } const ActionsMap = { select: (option) => ({ option }), }

// Pick the needed phases to code your widget logic/effects const { applyIoPhasesShapes, delay, } = logicPhases

// Init bindings of i/o phases with their respective shapes // (this is indeed the step that enables type-checking of running results of used phases) const { untilAction, setState, fromProps } = applyIoPhasesShapes({ stateShape: InitialState, actionsShape: ActionsMap })

/**

  • Now just express your component logic ..sequentially like when using async/await,
  • but here, using es6 generators (at a lower level, but like Redux-Saga !) */

    const offersStack = { 1: { code: 'TRIP', caption: 'Offer #1 - Vacations ..', details: "You can't wait to breathe ..", taken: false, }, 2: { code: 'SPA', caption: 'Offer #2 - Spa time! ..', details: "Why not ..", taken: false, } }

function* AppLogic() {

// on landing, start by greeting for a moment.. yield setState({ info: { step: 'Intro', title: 'Welcome to my App :>', } }) yield delay(3000)

// And start the selling show while (true) { const optionsMap = { 1: { opt: 1, disabled: offersStack1.taken, caption: offersStack1.caption + ' See more', }, 2: { opt: 2, disabled: offersStack2.taken, caption: offersStack2.caption + ' See more', }, }

// ..Display available offers
yield* setState({ 
  info: { 
    step: 'Offers of the Day', 
    title: 'Here you have only the Best !',
    opts: Object.values(optionsMap)
  } 
})

// then let your user make her choise
const { option: offerId } = yield* untilAction('select')

const offer = offersStack[offerId]

// let her know more..
yield* setState({ 
  info: { 
    step: 'Offer Details', 
    title: offer.caption,
    subtitle: offer.details,
    opts: [
      { opt: 1, caption: 'I want this offer!' },
      { opt: 2, caption: 'Back to list' },
    ]
  } 
})

while (true) {

  // ..once again, the user .. 
  // (same action / dif effect)
  const { option } = yield* untilAction('select')

  if (option === 1) { // it's like, she want it

      if (offer.code === 'SPA') {
          // ..bad luck ?? :/
          yield* flashError('Oops sorry, something went wrong booking ..')

          if (offersStack[1].taken) {
            // Then, here ends the flow 
            yield* flashError('It seems our service is down. \n Please, try again later')
            yield* fromProps.call((p) => p.complete())
            return
          }

      } else {
          // no the SPA,
          // good choise ;)
          yield* booking(offer)

          offer.taken = true

          yield* setState({ 
            info: { 
              step: 'Completing', 
              title: 'Nice !!',
              subtitle: 'Wanna keep looking ?',
              opts: [
                { opt: 1, caption: 'That will be all' },
                { opt: 2, caption: 'Back to list' },
              ]
            } 
          })
          const { option } = yield* untilAction('select')
          if (option === 1) {
            yield* fromProps.call((p) => p.complete())
            return
          }
          break
      }

  } else {
      // didn't want it, ok, back to the list
      break
  }

}

} }

function booking(offer) { // could imply an Api call .. "> yield setState({ info: { step: 'Booking ..', title: 'Booking your awesome choise ! \n ' + offer.caption, subtitle: '..just a second.', opts: [], } })

// tick tock
yield* delay(3000)

// confirm her place in that Vacation ...oopss, Busted :p
yield* setState({ 
  info: { 
    step: 'confim', 
    title: "Good News, you've just locked this offer"
    subtitle: '>> the ' + offer.caption,
    opts: [
      { opt: 1, caption: "Okeeey" }
    ]
  } 
})
yield* untilAction('select')

}

function flashError(message) { // display the important message yield setState({ error: message }) // let it be yield delay(3000) // and take it out yield setState({ error: '' }) }

<br />

> .. was it easy to follow the widget's subtle intentions ?

<br />

### if so, we the people, at <b><i>ClariTale</i></b>, are pleased. Thanks for your visit !


">

<br />

## Running unit tests

Run this to execute the unit tests via [Jest](https://jestjs.io).

```bash
nx test react-fx-hook

License

MIT ©