drafts.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import { Language, License, VideoCategory } from '@/api/queries'
  2. import { CommonStore, createStore } from '@/store'
  3. import { createId } from '@/utils/createId'
  4. import { readFromLocalStorage } from '@/utils/localStorage'
  5. export type CommonDraftProps = {
  6. id: string
  7. channelId: string
  8. updatedAt: string
  9. seen?: boolean
  10. }
  11. export type Draft = VideoDraft
  12. export type DraftType = 'video'
  13. export type VideoDraft = {
  14. type: 'video'
  15. title?: string | null
  16. description?: string | null
  17. isPublic?: boolean | null
  18. publishedBeforeJoystream?: string | null
  19. hasMarketing?: boolean | null
  20. isExplicit?: boolean | null
  21. language?: Language['iso'] | null
  22. category?: VideoCategory['id'] | null
  23. licenseCode?: License['code'] | null
  24. licenseCustomText?: License['customText'] | null
  25. licenseAttribution?: License['attribution'] | null
  26. } & CommonDraftProps
  27. export type RawDraft = Omit<Draft, 'id' | 'updatedAt'>
  28. type DraftStoreState = {
  29. drafts: Draft[]
  30. }
  31. type DraftStoreActions = {
  32. addDraft: (draft: RawDraft, explicitId?: string) => Draft
  33. updateDraft: (draftId: string, draftProps: RawDraft) => void
  34. removeDrafts: (draftIds: string[]) => void
  35. removeAllDrafts: (channelId: string) => void
  36. markAllDraftsAsSeenForChannel: (channelId: string) => void
  37. }
  38. export const useDraftStore = createStore<DraftStoreState, DraftStoreActions>(
  39. {
  40. state: {
  41. drafts: [], // includes drafts for different channels
  42. },
  43. actionsFactory: (set) => ({
  44. addDraft: (draft, explicitId) => {
  45. const id = explicitId ?? createId()
  46. const updatedAt = new Date().toISOString()
  47. const newDraft: Draft = { ...draft, updatedAt, id, seen: false }
  48. set((draftState) => {
  49. draftState.drafts.unshift(newDraft)
  50. })
  51. return newDraft
  52. },
  53. updateDraft: (draftId, draftProps) => {
  54. const updatedAt = new Date().toISOString()
  55. set((draftState) => {
  56. const idx = draftState.drafts.findIndex((d) => d.id === draftId)
  57. if (idx >= 0) {
  58. draftState.drafts[idx] = { ...draftState.drafts[idx], ...draftProps, updatedAt }
  59. }
  60. })
  61. },
  62. removeDrafts: (draftIds) => {
  63. set((draftState) => {
  64. draftState.drafts = draftState.drafts.filter((draft) => !draftIds.includes(draft.id))
  65. })
  66. },
  67. removeAllDrafts: (channelId) => {
  68. set((draftState) => {
  69. draftState.drafts = draftState.drafts.filter((draft) => draft.channelId !== channelId)
  70. })
  71. },
  72. markAllDraftsAsSeenForChannel: (channelId) => {
  73. set((draftState) => {
  74. draftState.drafts = draftState.drafts.map((draft) => ({
  75. ...draft,
  76. seen: draft.channelId === channelId ? true : draft.seen,
  77. }))
  78. })
  79. },
  80. }),
  81. },
  82. {
  83. persist: {
  84. key: 'drafts',
  85. whitelist: ['drafts'],
  86. version: 1,
  87. migrate: (oldState, oldVersion, storageValue) => {
  88. // migrate store before zustand was added
  89. if (oldVersion === undefined) {
  90. const unseenDrafts = readFromLocalStorage<
  91. Array<{
  92. draftId: string
  93. channelId: string
  94. }>
  95. >('unseenDrafts')
  96. const drafts = [...(storageValue as Array<Draft>)].map((draft) => {
  97. return unseenDrafts?.find((unseen) => unseen.draftId === draft.id)
  98. ? { ...draft, seen: false }
  99. : { ...draft, seen: true }
  100. })
  101. return {
  102. drafts: drafts,
  103. }
  104. }
  105. },
  106. },
  107. }
  108. )
  109. export const singleDraftSelector = (id: string) => (store: CommonStore<DraftStoreState, DraftStoreActions>) =>
  110. store.drafts.find((draft) => draft.id === id)
  111. export const channelDraftsSelector = (channelId: string) => (store: CommonStore<DraftStoreState, DraftStoreActions>) =>
  112. store.drafts.filter((d) => d.channelId === channelId)
  113. export const chanelUnseenDraftsSelector = (channelId: string) => (
  114. store: CommonStore<DraftStoreState, DraftStoreActions>
  115. ) => store.drafts.filter((d) => d.channelId === channelId && d.seen === false)