bucket-builder.js

import { getNumberOfDays } from '../../../utility/common/DatesHelper'

// constants
const BUCKET_DEFAULT = 'assorted'
const ITEMS = 'items'
const COUNT = '_count'
const CLASSNAME = '_class'

// bubble classes
const CLASS_NEW = 'new'
const CLASS_UPCOMING = 'upcoming'
const CLASS_MONTH = 'month'
const CLASS_WEEK = 'week'
const CLASS_COUPLE_DAYS = 'couple_days'
const CLASS_SAME_DAY = 'zero'
const CLASS_PAST_DUE = 'negative'

function classificationBasedOnDays(days, isNew) {
  if (days > 7 && isNew) return CLASS_NEW

  if (days > 30) return CLASS_UPCOMING
  else if (days > 7) return CLASS_MONTH
  else if (days > 3) return CLASS_WEEK
  else if (days > 1) return CLASS_COUPLE_DAYS
  else if (days === 0) return CLASS_SAME_DAY
  else if (days < 0) return CLASS_PAST_DUE
}

function bubbleProcessor(bubble) {
  const now = new Date()
  const { dates } = bubble
  const { createdAt, dueDate } = dates
  const daysToDueDate = getNumberOfDays(now, dueDate)
  const isNew = getNumberOfDays(now, createdAt)
  bubble[CLASSNAME] = classificationBasedOnDays(daysToDueDate, isNew)
  return bubble
}

// create buckets and add bubbles based on tags
// for nested tags create nested buckets
//
// assign size to buckets based on nesting depths
// and total number of items
//
// assign classname to
// assign size to each bubble and
// assign color to items
//
// that are
// - approaching due date
// - has due date today
// - has passed due date
export default function bubblesProcessor(bubbles) {
  const buckets = {
    [BUCKET_DEFAULT]: { [ITEMS]: [], [COUNT]: 0 }
  }

  bubbles.map((data) => {
    const bubble = bubbleProcessor(data)
    const { tags } = bubble
    const tagName = tags?.length ? tags[0] : BUCKET_DEFAULT
    const numberOfItems = addBubbleToBucket(buckets, bubble, tags)
    const currentCount = buckets[tagName][COUNT]
    buckets[tagName][COUNT] = isNaN(currentCount)
      ? numberOfItems
      : currentCount + numberOfItems
  })

  return buckets
}

function addBubbleToBucket(buckets, bubble, tags, level = 0) {
  let numberOfItems = 0
  const isUntagged = tags.length === 0
  const tagName = isUntagged ? BUCKET_DEFAULT : tags[level]
  if (tags.length === level + 1 || isUntagged) {
    if (buckets[tagName]) {
      const bucketItems = buckets[tagName][ITEMS]
      if (Array.isArray(bucketItems)) {
        numberOfItems++
        bucketItems.push(bubble)
        buckets[tagName][ITEMS] = bucketItems
        buckets[tagName][COUNT] = bucketItems.length
      }
    } else {
      numberOfItems++
      buckets[tagName] = { [ITEMS]: [bubble] }
      buckets[tagName][COUNT] = 1
    }
  } else {
    if (!buckets[tagName]) {
      buckets[tagName] = { [ITEMS]: [], [COUNT]: 0 }
    }
    const currentBucket = buckets[tagName]
    numberOfItems += addBubbleToBucket(currentBucket, bubble, tags, level + 1)
  }
  return numberOfItems
}