Skip to content

Instantly share code, notes, and snippets.

@scneptune
Last active March 12, 2018 09:39
Show Gist options
  • Save scneptune/5da5fc7c481a66ffd7462493f3142639 to your computer and use it in GitHub Desktop.
Save scneptune/5da5fc7c481a66ffd7462493f3142639 to your computer and use it in GitHub Desktop.
simple description of whats going on in the bulkDelivery Page.

How this state will work

An example state after making the appropriate get API request to /bulk_deliveries

{
     "deliveryLineItemIds": [
          "39773",
          "41046",
          "41201",
          "41706",
          "55768",
          "55770"
     ],
     "deliveryLineItems": {
          "39773": {
               "id": null,
               "alt_episode_number": 1,
               "air_date": "",
               "delivery_date": "",
               "episode_title": "Time to Expand",
               "deliverable_id": 39773,
               "deliverable_type": "MediaObject",
               "delivery_destination_id": null
          },
          "41046": {
               "id": null,
               "alt_episode_number": 2,
               "air_date": "",
               "delivery_date": "",
               "episode_title": "Job Interview",
               "deliverable_id": 41046,
               "deliverable_type": "MediaObject",
               "delivery_destination_id": null
          },
          "41201": {
               "id": null,
               "alt_episode_number": 2,
               "air_date": "",
               "delivery_date": "",
               "episode_title": "The Big Secret",
               "deliverable_id": 41201,
               "deliverable_type": "MediaObject",
               "delivery_destination_id": null
          },
          "41706": {
               "id": null,
               "alt_episode_number": 1,
               "air_date": "",
               "delivery_date": "",
               "episode_title": "Birthday Party",
               "deliverable_id": 41706,
               "deliverable_type": "MediaObject",
               "delivery_destination_id": null
          },
          "55768": {
               "id": null,
               "alt_episode_number": null,
               "air_date": "",
               "delivery_date": "",
               "episode_title": "The Trailer!",
               "deliverable_id": 55768,
               "deliverable_type": "MediaObject",
               "delivery_destination_id": null
          },
          "55770": {
               "id": null,
               "alt_episode_number": 1,
               "air_date": "",
               "delivery_date": "",
               "episode_title": "Style Test",
               "deliverable_id": 55770,
               "deliverable_type": "MediaObject",
               "delivery_destination_id": null
          }
     },
     "deliveryDestinations": [],
     "longFormDeliveryItemIds": [],
     "shortFormDeliveryItemIds": [],
     "bulkDeliveryCollection": {
          "tiny_stylist-season_1-short_form": {
               "collectionName": "season_1-short_form",
               "title": "Season 1-short_form",
               "format": "Season 1",
               "enabled": true,
               "deliveryLineItemIds": [
                    "41046",
                    "41706"
               ]
          },
          "tiny_stylist-season_1-long_form": {
               "collectionName": "season_1-long_form",
               "title": "Season 1-long_form",
               "format": "Season 1",
               "enabled": true,
               "deliveryLineItemIds": [
                    "55770"
               ]
          },
          "olivia_has_2_moms-season_1-short_form": {
               "collectionName": "season_1-short_form",
               "title": "Season 1-short_form",
               "format": "Season 1",
               "enabled": true,
               "deliveryLineItemIds": [
                    "39773",
                    "41201"
               ]
          },
          "olivia_has_2_moms-ancillary": {
               "collectionName": "ancillary",
               "title": "Ancillary",
               "format": null,
               "enabled": true,
               "deliveryLineItemIds": [
                    "55768"
               ]
          }
     },
     "bulkDeliveryShows": {
          "tiny_stylist": {
               "showName": "tiny_stylist",
               "title": "Tiny stylist",
               "enabled": true,
               "collections": [
                    "tiny_stylist-season_1-short_form",
                    "tiny_stylist-season_1-long_form"
               ]
          },
          "olivia_has_2_moms": {
               "showName": "olivia_has_2_moms",
               "title": "Olivia has_2_moms",
               "enabled": true,
               "collections": [
                    "olivia_has_2_moms-season_1-short_form",
                    "olivia_has_2_moms-ancillary"
               ]
          }
     }
}

All deliveryLineItems unique id is their deliverable_id, which how we can look up specific deliveryLineItems, like deliveryLineItems[2].

NOTE: This is different from how this reducer is used on a detail page: (eg. show detail page where deliveryLineItems are seasons, or episode details page where ids reflect uncreated deliveryLineItems with the prefix new or saved ones which reference the deliveryLineItems activemodel record id).

We will be using the deliveryLineItemIds array to determine which deliveryLineItem objects we will be sending back to the server in the post request back to /bulk_deliveries as the param ['delivery_line_items'].

An example of this if our delliveryLineItems object contains

{
  1: {
      ...id,
      deliverable_type: null,
      alt_episode_number,
      etc.
  },
  2: {
    ...id,
    etc,
  },
  3: {
    ...id,
    etc.
  },
  4: {
    ...id,
    etc.
  }
  5: {
    ...id,
    etc.
  }
}

and our deliveryLineItemIds is only [1, 2, 5]

then when we make the request to /bulk_deliveries, the parameters will only be [ { id: null, deliverable_id: 1 ... etc. }, { id: null, deliverable_id: 2, ... etc. }, { id: null, deliverable_id: 5, ...etc. } ]

Toggling Bulk Deliveries

Chief in concern here how we will trigger and arrange content around the bulk deliveries container to render a row component imagine a pseudo-code-jsx structure like this:

// This is for illustrative purposes only, not intended to be actual markup
<Show key={show.showName}>
  <heading> {show.title} </heading>
  <checkEnabled>{show.enabled}</checkEnabled>
   {show.collections.map(collection) =>
      (<Collection key={collection.collectionName}>
        <heading>{collection.title} - {collection.format} </heading>
        <checkEnabled>{collection.enabled}</checkEnabled>
        {collection.deliveryLineItemIds.map(
          (id) => <DeliveryLineItemRow id={id}>
            <checkEnabled>{deliveryLineItemIds.includes(id)}</checkEnabled>
          </DeliveryLineItemRow>)
        }
      </Collection>)
    }
</Show>

In order to create this structure the components will iterate over the bulkDeliveryShows Object keys. like stated earlier when we want to untoggle deliveryLineItems from being exported we will dropping them out of the deliveryLineItemIds array.

for example here is how we get all the shows that will render in a connector.

  let { bulkDeliveryShows } = getState().deliveryLineItemState.bulkDeliveryShows

  Object.keys(bulkDeliveryShows).map(showKey => bulkDeliveryShows[showKey]);

further more if we want to load all collections (seasons, both short and long and ancillary) for that specific show, we could do:

  //assuming showKey represents something like "olivia_has_2_moms"

  let { bulkDeliveryShows, bulkDeliveryCollections } = getState().deliveryLineItemState;

  bulkDeliveryShows[showKey].collections.map(
    collectionKey => bulkDeliveryCollections[collectionKey]
  )

and further more the same pattern applies to get deliveryLineItems off a collection

// assuming collectionName is something like "olivia_has_2_moms-season_1-short_form"
let { bulkDeliveryCollections, deliveryLineItems } = getState().deliveryLineItemState;

bulkDeliveryCollections[collectionName].deliveryLineItemIds.map(
  deliveryLineItemId => deliveryLineItems[deliveryLineItemId]
)

when we toggle off an entire season we can easily pass it the collectionName and then do the recomposing on the associated relationships

  let activeCollection = bulkDeliveryCollections[`olivia_has_2_moms-season_1-short_form`];
  if (activeCollection.enabled) {
    let nextDeliveryLineItemSelection = deliveryLineItemIds.filter(
      // removes all ids from the deliveryLineItemIds that are part of that collection.
      (deliveryId) => !activeCollection.deliveryLineItemIds.includes(deliveryId)
    )  
  } else {
    // add the two arrays together
    let nextDeliveryLineItemSelection = deliveryLineItemIds.concat(
      activeCollection.deliveryLineItemIds
    ).filter( // this is done to insure uniqueness of ids.
      (id, index, arr) => arr.indexOf(id) === index)
    );
  }
  // then we could recompose this object with the state at it's key `olivia_has_2_moms-season_1-short_form`
  // with the enabled flag in the opposite direction
  // in state like:

  return {
    ...currentState,
    bulkDeliveryCollections: {
      ...currentState.bulkDeliveryCollections, // include all existing collections
      [`olivia_has_2_moms-season_1-short_form`]: {
        ...activeCollection, // none of the other properties have changed
        enabled: !activeCollection.enabled
      }
    },
    // now this has either removed or
    // added those ids for the rows that are selected.
    deliveryLineItemIds: nextDeliveryLineItemSelection
  }

The same principle can apply to shows as well, this time we memoize all the deliverable_ids across all the collections into a single array (idsToFilter), so we can use that to bulk add or remove deliveryLineItemIds

let nextDeliveryLineItemIdSelection, idsToFilter = [];
let activeShow = currentState.bulkDeliveryShows[value.showName];
let isEnabled = (typeof value.forceDirection === 'boolean' ?
// this makes our forceDirection an optional value from the action,
// we may not need this, but i'm adding the backdoor just in case
                  value.forceDirection :
                  activeShow.enabled);

//first we update all collections's effected enabled flag
let nextCollections = activeShow.collections.reduce(
  (collections, collectionId) => {
    // this pushes the deliveryLineItemIds array
    // attached to the collection elements into the idsToFilter array
    Array.prototype.push.apply(
      null,
      idsToFilter, currentState.bulkDeliveryCollections[collectionId].deliveryLineItemIds
    )

    collections[collectionId] = {
      ...currentState.bulkDeliveryCollections[collectionId],
      enabled: !isEnabled
    }
    return collections;
  }, {})


// now its pretty easy to take all those ids in `idsToFilter`
// and do the same thing we've done with the collections above
if (isEnabled) {
  nextDeliveryLineItemIdSelection = currentState.deliveryLineItemIds.filter(
    deliveryId => (idsToFilter.indexOf(deliveryId) === -1)
  )
} else {
  nextDeliveryLineItemIdSelection = currentState.deliveryLineItemIds.concat(
    idsToFilter
  ).filter(
    (id, index, combinedArr) => combinedArr.indexOf(id) === index
  )
}
return {
  ...currentState,
  bulkDeliveryShows: {
    ...currentState.bulkDeliveryShows,
    [value.showName]: {...activeShow, enabled: !isEnabled}
  },
  //merge the old collections with the new
  bulkDeliveryCollections: Object.assign(
    currentState.bulkDeliveryCollections, nextCollections
  ),
  deliveryLineItemIds: nextDeliveryLineItemIdSelection
}

Mass Assignment Of Delivery Line Items

Now for our final trick, we will update all the values of the deliveryLineItems in one fell swoop.

return {
  ...currentState,
  // iterate over all the deliveryLineItem keys,
  // whether they are selected or not in `deliveryLineItemIds`
  deliveryLineItems: Object.keys(
    currentState.deliveryLineItems
  ).reduce((updatedDeliveryLineItems, deliveryKey) => {
    updatedDeliveryLineItems[deliveryKey] = {
      //copy over all existing attributes of the `deliveryLineItem`
      ...currentState.deliveryLineItems[deliveryKey],
      // overwrite the attribute that matches the fieldName
      [value.fieldName]: value.fieldValue
    }
    return updatedDeliveryLineItems
  }, {})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment