Monorepo containing core modules of Zeichen.
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

83 satır
2.6 KiB

  1. import {addTime, TimeDivision} from '../utilities/Date'
  2. import * as Serialization from '../utilities/Serialization'
  3. import LocalStorage from './LocalStorage'
  4. type LoadItemParams = {
  5. id: string,
  6. url: string,
  7. }
  8. type LoadItems = <T extends Record<string, unknown>>(params: LoadItemParams) => () => Promise<T[]>
  9. const loadItems: LoadItems = <T extends Record<string, unknown>>(params) => async (): Promise<T[]> => {
  10. const { id, url, } = params
  11. const storage = new LocalStorage(
  12. window.localStorage,
  13. Serialization.serialize,
  14. Serialization.deserialize
  15. )
  16. const localData = storage.getItem(id)
  17. if (localData === null) {
  18. const remoteItems = await window.fetch(url)
  19. // TODO add custom serialization method
  20. const theItems: T[] = await remoteItems.json()
  21. storage.setItem(id, {
  22. // TODO backend should set expiry
  23. expiry: addTime(new Date(), 30)(TimeDivision.DAYS).getTime(),
  24. items: theItems,
  25. })
  26. return theItems
  27. }
  28. const dataExpiry = new Date(Number(localData.expiry))
  29. const now = new Date()
  30. if (now.getTime() > dataExpiry.getTime()) {
  31. storage.removeItem(id)
  32. const loader: () => Promise<T[]> = loadItems(params)
  33. return loader()
  34. }
  35. return localData.items
  36. }
  37. type SaveItem = <T extends Record<string, unknown>>(p: LoadItemParams) => (item: T) => Promise<T>
  38. const saveItem: SaveItem = <T extends Record<string, unknown>>(params) => async (item) => {
  39. const { id: storageId, url } = params
  40. const storage = new LocalStorage(
  41. window.localStorage,
  42. Serialization.serialize,
  43. Serialization.deserialize
  44. )
  45. const localData = storage.getItem(storageId, {
  46. expiry: addTime(new Date(), 30)(TimeDivision.DAYS).getTime(),
  47. items: []
  48. })
  49. console.log(localData)
  50. const localItems = localData.items
  51. const { id: itemId, ...theBody } = item
  52. const theItems: T[] = (
  53. localItems.some(i => i.id === itemId)
  54. ? localItems.map(i => i.id === itemId ? item : i)
  55. : [...localItems, item]
  56. )
  57. storage.setItem(storageId, { ...localData, items: theItems })
  58. const response = await window.fetch(`${url}/${itemId}`, {
  59. method: 'put',
  60. body: JSON.stringify(theBody),
  61. headers: {
  62. 'Content-Type': 'application/json',
  63. },
  64. })
  65. const responseBody = await response.json()
  66. if (response.status !== 201 && response.status !== 200) {
  67. throw responseBody
  68. }
  69. return responseBody as T
  70. }
  71. export const loadNotes = loadItems({ id: 'notes', url: '/api/notes' })
  72. export const loadFolders = loadItems({ id: 'folders', url: '/api/folders' })
  73. export const saveNote = saveItem({ id: 'notes', url: '/api/notes' })
  74. export const saveFolder = saveItem({ id: 'folders', url: '/api/folders' })