Skip to content
Snippets Groups Projects
Forked from an inaccessible project.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
utils.ts 4.30 KiB
import { Observable, forkJoin } from 'rxjs';
import { map } from 'rxjs/operators';
import { PlannedTermEra, PlannedTerm } from '@app/core/models/planned-term';
import { YearMapping } from '@app/core/models/year';
import { YearCode, TermCode } from '@app/core/models/termcode';

export const isValidTermCode = (anything: any): anything is string => {
  return /^\d{4}$/.test(anything);
};

export const pickTermName = (termOffset: string) => {
  switch (termOffset) {
    case '2':
    case '3':
      return 'fall';
    case '4':
      return 'spring';
    case '6':
      return 'summer';
    default:
      throw new Error(`'${termOffset}' is not a valid term offset`);
  }
};

export const pickTermEra = (
  termCode: TermCode,
  activeTermCodes: ReadonlyArray<TermCode>,
): PlannedTermEra => {
  const noActiveTermCodes = activeTermCodes.length === 0;
  const isActiveTermCode = activeTermCodes.some(tc => tc.equals(termCode));
  const beforeAllActiveTermCodes = activeTermCodes.every(tc =>
    tc.comesAfter(termCode),
  );
  if (noActiveTermCodes || isActiveTermCode) {
    return 'active';
  } else if (beforeAllActiveTermCodes) {
    return 'past';
  } else {
    return 'future';
  }
};

export const pickYearEra = (
  yearCode: YearCode,
  activeTermCodes: ReadonlyArray<TermCode>,
): PlannedTermEra => {
  const activeYearCodes = activeTermCodes.map(tc => tc.yearCode);
  const noActiveYearCodes = activeYearCodes.length === 0;
  const isActiveYearCode = activeYearCodes.some(yc => yc.equals(yearCode));
  const beforeAllActiveYearCodes = activeYearCodes.every(yc =>
    yc.comesAfter(yearCode),
  );
  if (noActiveYearCodes || isActiveYearCode) {
    return 'active';
  } else if (beforeAllActiveYearCodes) {
    return 'past';
  } else {
    return 'future';
  }
};

export const yearsToDropZoneIds = () => (years$: Observable<YearMapping>) => {
  return years$.pipe(
    map(years => {
      const yearCodes = Object.keys(years);
      const termCodes = yearCodes.reduce<string[]>((acc, yearCode) => {
        if (years[yearCode].fall.era !== 'past') {
          acc = acc.concat(years[yearCode].fall.termCode.toString());
        }
        if (years[yearCode].spring.era !== 'past') {
          acc = acc.concat(years[yearCode].spring.termCode.toString());
        }

        if (years[yearCode].summer.era !== 'past') {
          acc = acc.concat(years[yearCode].summer.termCode.toString());
        }

        return acc;
      }, []);

      const termIds = [
        'saved-courses',
        ...termCodes.map(termCode => `term-${termCode}`),
      ];
      return termIds;
    }),
  );
};

export const compareArrays = <T>(cmp: (a: T, b: T) => boolean) => {
  return (a: T[], b: T[]): boolean => {
    if (a.length === b.length) {
      return a.every((elem, i) => cmp(elem, b[i]));
    } else {
      return false;
    }
  };
};

export const compareStringArrays = compareArrays<string>((a, b) => a === b);

export const yearsToYearCodes = () => (years$: Observable<YearMapping>) => {
  return years$.pipe(
    map(years => {
      const yearCodes = Object.keys(years);
      const sortedYearCodes = yearCodes.sort();
      return sortedYearCodes;
    }),
  );
};

export const yearsToDroppableTermCodes = () => (
  years$: Observable<YearMapping>,
) => {
  return years$.pipe(
    map(years => {
      const yearCodes = Object.keys(years);
      return yearCodes.reduce<string[]>((acc, yearCode) => {
        if (years[yearCode].fall.era !== 'past') {
          acc = acc.concat(years[yearCode].fall.termCode.toString());
        }

        if (years[yearCode].spring.era !== 'past') {
          acc = acc.concat(years[yearCode].spring.termCode.toString());
        }

        if (years[yearCode].summer.era !== 'past') {
          acc = acc.concat(years[yearCode].summer.termCode.toString());
        }

        return acc;
      }, []);
    }),
  );
};

interface SimpleMap {
  [name: string]: any;
}

type ObservableMap<T = SimpleMap> = { [K in keyof T]: Observable<T[K]> };

export const forkJoinWithKeys = <T = SimpleMap>(pairs: ObservableMap<T>) => {
  const keys = Object.keys(pairs);
  const observables = keys.map(key => pairs[key]);
  return forkJoin(observables).pipe(
    map<any[], T>(values => {
      const valueMapping = {} as T;

      keys.forEach((key, index) => {
        valueMapping[key] = values[index];
      });

      return valueMapping;
    }),
  );
};