history.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import {
  2. addDoc,
  3. collection,
  4. deleteDoc,
  5. doc,
  6. getDocs,
  7. getFirestore,
  8. limit,
  9. onSnapshot,
  10. orderBy,
  11. query,
  12. updateDoc,
  13. } from "firebase/firestore"
  14. import { currentUser$ } from "./auth"
  15. import { settingsStore } from "~/newstore/settings"
  16. import {
  17. GQLHistoryEntry,
  18. graphqlHistoryStore,
  19. HISTORY_LIMIT,
  20. RESTHistoryEntry,
  21. restHistoryStore,
  22. setGraphqlHistoryEntries,
  23. setRESTHistoryEntries,
  24. translateToNewGQLHistory,
  25. translateToNewRESTHistory,
  26. } from "~/newstore/history"
  27. type HistoryFBCollections = "history" | "graphqlHistory"
  28. /**
  29. * Whether the history are loaded. If this is set to true
  30. * Updates to the history store are written into firebase.
  31. *
  32. * If you have want to update the store and not fire the store update
  33. * subscription, set this variable to false, do the update and then
  34. * set it to true
  35. */
  36. let loadedRESTHistory = false
  37. /**
  38. * Whether the history are loaded. If this is set to true
  39. * Updates to the history store are written into firebase.
  40. *
  41. * If you have want to update the store and not fire the store update
  42. * subscription, set this variable to false, do the update and then
  43. * set it to true
  44. */
  45. let loadedGraphqlHistory = false
  46. async function writeHistory(entry: any, col: HistoryFBCollections) {
  47. if (currentUser$.value == null)
  48. throw new Error("User not logged in to sync history")
  49. const hs = {
  50. ...entry,
  51. updatedOn: new Date(),
  52. }
  53. try {
  54. await addDoc(
  55. collection(getFirestore(), "users", currentUser$.value.uid, col),
  56. hs
  57. )
  58. } catch (e) {
  59. console.error("error writing to history", hs, e)
  60. throw e
  61. }
  62. }
  63. async function deleteHistory(entry: any, col: HistoryFBCollections) {
  64. if (currentUser$.value == null)
  65. throw new Error("User not logged in to delete history")
  66. try {
  67. await deleteDoc(
  68. doc(getFirestore(), "users", currentUser$.value.uid, col, entry.id)
  69. )
  70. } catch (e) {
  71. console.error("error deleting history", entry, e)
  72. throw e
  73. }
  74. }
  75. async function clearHistory(col: HistoryFBCollections) {
  76. if (currentUser$.value == null)
  77. throw new Error("User not logged in to clear history")
  78. const { docs } = await getDocs(
  79. collection(getFirestore(), "users", currentUser$.value.uid, col)
  80. )
  81. await Promise.all(docs.map((e) => deleteHistory(e, col)))
  82. }
  83. async function toggleStar(entry: any, col: HistoryFBCollections) {
  84. if (currentUser$.value == null)
  85. throw new Error("User not logged in to toggle star")
  86. try {
  87. await updateDoc(
  88. doc(getFirestore(), "users", currentUser$.value.uid, col, entry.id),
  89. { star: !entry.star }
  90. )
  91. } catch (e) {
  92. console.error("error toggling star", entry, e)
  93. throw e
  94. }
  95. }
  96. export function initHistory() {
  97. restHistoryStore.dispatches$.subscribe((dispatch) => {
  98. if (
  99. loadedRESTHistory &&
  100. currentUser$.value &&
  101. settingsStore.value.syncHistory
  102. ) {
  103. if (dispatch.dispatcher === "addEntry") {
  104. writeHistory(dispatch.payload.entry, "history")
  105. } else if (dispatch.dispatcher === "deleteEntry") {
  106. deleteHistory(dispatch.payload.entry, "history")
  107. } else if (dispatch.dispatcher === "clearHistory") {
  108. clearHistory("history")
  109. } else if (dispatch.dispatcher === "toggleStar") {
  110. toggleStar(dispatch.payload.entry, "history")
  111. }
  112. }
  113. })
  114. graphqlHistoryStore.dispatches$.subscribe((dispatch) => {
  115. if (
  116. loadedGraphqlHistory &&
  117. currentUser$.value &&
  118. settingsStore.value.syncHistory
  119. ) {
  120. if (dispatch.dispatcher === "addEntry") {
  121. writeHistory(dispatch.payload.entry, "graphqlHistory")
  122. } else if (dispatch.dispatcher === "deleteEntry") {
  123. deleteHistory(dispatch.payload.entry, "graphqlHistory")
  124. } else if (dispatch.dispatcher === "clearHistory") {
  125. clearHistory("graphqlHistory")
  126. } else if (dispatch.dispatcher === "toggleStar") {
  127. toggleStar(dispatch.payload.entry, "graphqlHistory")
  128. }
  129. }
  130. })
  131. let restSnapshotStop: (() => void) | null = null
  132. let graphqlSnapshotStop: (() => void) | null = null
  133. currentUser$.subscribe((user) => {
  134. if (!user) {
  135. // Clear the snapshot listeners when the user logs out
  136. if (restSnapshotStop) {
  137. restSnapshotStop()
  138. restSnapshotStop = null
  139. }
  140. if (graphqlSnapshotStop) {
  141. graphqlSnapshotStop()
  142. graphqlSnapshotStop = null
  143. }
  144. } else {
  145. restSnapshotStop = onSnapshot(
  146. query(
  147. collection(getFirestore(), "users", user.uid, "history"),
  148. orderBy("updatedOn", "desc"),
  149. limit(HISTORY_LIMIT)
  150. ),
  151. (historyRef) => {
  152. const history: RESTHistoryEntry[] = []
  153. historyRef.forEach((doc) => {
  154. const entry = doc.data()
  155. entry.id = doc.id
  156. history.push(translateToNewRESTHistory(entry))
  157. })
  158. loadedRESTHistory = false
  159. setRESTHistoryEntries(history)
  160. loadedRESTHistory = true
  161. }
  162. )
  163. graphqlSnapshotStop = onSnapshot(
  164. query(
  165. collection(getFirestore(), "users", user.uid, "graphqlHistory"),
  166. orderBy("updatedOn", "desc"),
  167. limit(HISTORY_LIMIT)
  168. ),
  169. (historyRef) => {
  170. const history: GQLHistoryEntry[] = []
  171. historyRef.forEach((doc) => {
  172. const entry = doc.data()
  173. entry.id = doc.id
  174. history.push(translateToNewGQLHistory(entry))
  175. })
  176. loadedGraphqlHistory = false
  177. setGraphqlHistoryEntries(history)
  178. loadedGraphqlHistory = true
  179. }
  180. )
  181. }
  182. })
  183. }