useFeedbackQueryKeys.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import {createContext, ReactNode, useCallback, useContext, useRef, useState} from 'react';
  2. import invariant from 'invariant';
  3. import getFeedbackItemQueryKey from 'sentry/components/feedback/getFeedbackItemQueryKey';
  4. import useFeedbackListQueryKey from 'sentry/components/feedback/useFeedbackListQueryKey';
  5. import type {Organization} from 'sentry/types';
  6. interface Props {
  7. children: ReactNode;
  8. organization: Organization;
  9. }
  10. type ListQueryKey = ReturnType<typeof useFeedbackListQueryKey>;
  11. type ItemQueryKeys = ReturnType<typeof getFeedbackItemQueryKey>;
  12. interface TContext {
  13. getItemQueryKeys: (id: string) => ItemQueryKeys;
  14. listHeadTime: number;
  15. listPrefetchQueryKey: ListQueryKey;
  16. listQueryKey: NonNullable<ListQueryKey>;
  17. resetListHeadTime: () => void;
  18. }
  19. const EMPTY_ITEM_QUERY_KEYS = {issueQueryKey: undefined, eventQueryKey: undefined};
  20. const DEFAULT_CONTEXT: TContext = {
  21. getItemQueryKeys: () => EMPTY_ITEM_QUERY_KEYS,
  22. listHeadTime: 0,
  23. listPrefetchQueryKey: [''],
  24. listQueryKey: [''],
  25. resetListHeadTime: () => undefined,
  26. };
  27. const FeedbackQueryKeysProvider = createContext<TContext>(DEFAULT_CONTEXT);
  28. export function FeedbackQueryKeys({children, organization}: Props) {
  29. // The "Head time" is the timestamp of the newest feedback that we can show in
  30. // the list (the head element in the array); the same time as when we loaded
  31. // the page. It can be updated without loading the page, when we want to see
  32. // fresh list items.
  33. const [listHeadTime, setHeadTime] = useState(() => Date.now());
  34. const resetListHeadTime = useCallback(() => {
  35. setHeadTime(Date.now());
  36. }, []);
  37. const itemQueryKeyRef = useRef<Map<string, ItemQueryKeys>>(new Map());
  38. const getItemQueryKeys = useCallback(
  39. (feedbackId: string) => {
  40. if (feedbackId && !itemQueryKeyRef.current.has(feedbackId)) {
  41. itemQueryKeyRef.current.set(
  42. feedbackId,
  43. getFeedbackItemQueryKey({feedbackId, organization})
  44. );
  45. }
  46. return itemQueryKeyRef.current.get(feedbackId) ?? EMPTY_ITEM_QUERY_KEYS;
  47. },
  48. [organization]
  49. );
  50. const listQueryKey = useFeedbackListQueryKey({
  51. listHeadTime,
  52. organization,
  53. prefetch: false,
  54. });
  55. invariant(listQueryKey, 'listQueryKey cannot be nullable when prefetch=false');
  56. const listPrefetchQueryKey = useFeedbackListQueryKey({
  57. listHeadTime,
  58. organization,
  59. prefetch: true,
  60. });
  61. return (
  62. <FeedbackQueryKeysProvider.Provider
  63. value={{
  64. getItemQueryKeys,
  65. listHeadTime,
  66. listPrefetchQueryKey,
  67. listQueryKey,
  68. resetListHeadTime,
  69. }}
  70. >
  71. {children}
  72. </FeedbackQueryKeysProvider.Provider>
  73. );
  74. }
  75. export default function useFeedbackQueryKeys() {
  76. return useContext(FeedbackQueryKeysProvider);
  77. }