renzholy/mongood

View on GitHub
src/utils/storage.ts

Summary

Maintainability
A
2 hrs
Test Coverage
import { Connection, DisplayMode } from 'types'

enum StorageType {
  STRING,
  NUMBER,
  JSON,
}

function getItem<T>(
  type: StorageType,
  key: string,
): string | number | T | undefined {
  if (typeof window === 'undefined') {
    return undefined
  }
  const item = localStorage.getItem(key)
  switch (type) {
    case StorageType.STRING: {
      return item || undefined
    }
    case StorageType.NUMBER: {
      try {
        return item === null ? undefined : parseInt(item, 10)
      } catch {
        return undefined
      }
    }
    case StorageType.JSON: {
      try {
        return item === null ? undefined : JSON.parse(item)
      } catch {
        return undefined
      }
    }
    default: {
      return undefined
    }
  }
}

function setItem<T>(
  type: StorageType,
  key: string,
): (value?: T | number | string) => void {
  if (typeof window === 'undefined') {
    return () => null
  }
  return (value) => {
    if (value === undefined) {
      localStorage.removeItem(key)
      return
    }
    switch (type) {
      case StorageType.STRING: {
        localStorage.setItem(key, value as string)
        break
      }
      case StorageType.NUMBER: {
        localStorage.setItem(key, (value as number).toString())
        break
      }
      case StorageType.JSON: {
        localStorage.setItem(key, JSON.stringify(value))
        break
      }
      default: {
        // do nothing
      }
    }
  }
}

function genGetSet(
  type: StorageType.STRING,
  key: string,
  defaultValue: string,
): { get: string; set: (value?: string) => void }
function genGetSet(
  type: StorageType.STRING,
  key: string,
): { get: string | undefined; set: (value?: string) => void }
function genGetSet<T extends string>(
  type: StorageType.STRING,
  key: string,
  defaultValue: T,
): { get: T; set: (value?: T) => void }
function genGetSet<T extends string>(
  type: StorageType.STRING,
  key: string,
): { get: T | undefined; set: (value?: T) => void }
function genGetSet(
  type: StorageType.NUMBER,
  key: string,
  defaultValue: number,
): { get: number; set: (value?: number) => void }
function genGetSet(
  type: StorageType.NUMBER,
  key: string,
): { get: number | undefined; set: (value?: number) => void }
function genGetSet<T>(
  type: StorageType.JSON,
  key: string,
  defaultValue: T,
): { get: T; set: (value?: T) => void }
function genGetSet<T>(
  type: StorageType.JSON,
  key: string,
): { get: T | undefined; set: (value?: T) => void }
function genGetSet(type: StorageType, key: string, defaultValue?: any) {
  return {
    get: getItem(type, key) || defaultValue,
    set: setItem(type, key),
  }
}

export const storage = {
  selfAddedConnections: genGetSet<Connection[]>(
    StorageType.JSON,
    'connections',
    [],
  ),

  displayMode: genGetSet<DisplayMode>(
    StorageType.STRING,
    'displayMode',
    DisplayMode.TABLE,
  ),

  limit: genGetSet(StorageType.NUMBER, 'limit', 25),

  tabSize: genGetSet(StorageType.NUMBER, 'settings.tabSize', 2),

  timezoneOffset: genGetSet(StorageType.NUMBER, 'settings.timezoneOffset', 0),

  /**
   * @see https://tech.yandex.com/maps/staticapi/doc/1.x/dg/concepts/input_params-docpage/
   */
  staticMapUrlTemplate: genGetSet(
    StorageType.STRING,
    'settings.staticMapUrlTemplate',
    'https://static-maps.yandex.ru/1.x/?lang=en_US&ll={{longitude}},{{latitude}}&size={{width}},{{height}}&z=8&l=map&pt={{longitude}},{{latitude}},round',
  ),
}