Coursemology/coursemology2

View on GitHub
client/app/lib/hooks/router/dynamicNest/builder.ts

Summary

Maintainability
A
2 hrs
Test Coverage
import { Location } from 'react-router-dom';

import { buildCrumbData, CrumbData, CrumbState } from './crumbs';
import {
  getHandleData,
  getHandleRequestData,
  getShouldRevalidateCrumb,
} from './handles';
import { isPromise, Match, Promisable } from './utils';

interface CrumbsDataBuilderResult {
  data: Promisable<CrumbData[]>;
  hasPending: boolean;
  invalidCrumbs: Set<string>;
}

export const buildCrumbsData = (
  matches: Match[],
  location: Location,
  state: CrumbState,
): CrumbsDataBuilderResult => {
  const invalidCrumbs = new Set(Object.keys(state));
  const oldCrumbsCount = invalidCrumbs.size;

  let hasPromise = false;
  let newCrumbsCount = 0;

  const delta = matches.reduce<Promisable<CrumbData>[]>((crumbs, match) => {
    const handleData = getHandleData(match, location);
    if (!handleData) return crumbs;

    newCrumbsCount += 1;

    const crumbExists = invalidCrumbs.has(match.pathname);

    if (getShouldRevalidateCrumb(handleData) || crumbExists)
      invalidCrumbs.delete(match.pathname);

    if (getShouldRevalidateCrumb(handleData) || !crumbExists) {
      const content = getHandleRequestData(handleData);

      if (isPromise(content)) {
        hasPromise = true;
        crumbs.push(content.then((data) => buildCrumbData(match, data)));
      } else {
        crumbs.push(buildCrumbData(match, content));
      }
    }

    return crumbs;
  }, []);

  const validCrumbsCount = oldCrumbsCount - invalidCrumbs.size;

  return {
    data: hasPromise ? Promise.all(delta) : (delta as CrumbData[]),
    hasPending: newCrumbsCount > validCrumbsCount,
    invalidCrumbs,
  };
};