@knocklabs/react-core 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cjs/modules/core/constants.js.map +1 -1
  3. package/dist/cjs/modules/core/context/KnockProvider.js +1 -1
  4. package/dist/cjs/modules/core/context/KnockProvider.js.map +1 -1
  5. package/dist/cjs/modules/core/hooks/useAuthenticatedKnockClient.js.map +1 -1
  6. package/dist/cjs/modules/core/utils.js.map +1 -1
  7. package/dist/cjs/modules/feed/context/KnockFeedProvider.js +1 -1
  8. package/dist/cjs/modules/feed/context/KnockFeedProvider.js.map +1 -1
  9. package/dist/cjs/modules/feed/hooks/useFeedSettings.js.map +1 -1
  10. package/dist/cjs/modules/feed/hooks/useNotifications.js.map +1 -1
  11. package/dist/cjs/modules/i18n/context/KnockI18nProvider.js +1 -1
  12. package/dist/cjs/modules/i18n/context/KnockI18nProvider.js.map +1 -1
  13. package/dist/cjs/modules/i18n/hooks/useTranslations.js.map +1 -1
  14. package/dist/cjs/modules/i18n/languages/de.js.map +1 -1
  15. package/dist/cjs/modules/i18n/languages/en.js.map +1 -1
  16. package/dist/cjs/modules/i18n/languages/index.js.map +1 -1
  17. package/dist/cjs/modules/slack/context/KnockSlackProvider.js +1 -1
  18. package/dist/cjs/modules/slack/context/KnockSlackProvider.js.map +1 -1
  19. package/dist/cjs/modules/slack/hooks/useConnectedSlackChannels.js +1 -1
  20. package/dist/cjs/modules/slack/hooks/useConnectedSlackChannels.js.map +1 -1
  21. package/dist/cjs/modules/slack/hooks/useSlackAuth.js +1 -1
  22. package/dist/cjs/modules/slack/hooks/useSlackAuth.js.map +1 -1
  23. package/dist/cjs/modules/slack/hooks/useSlackChannels.js +1 -1
  24. package/dist/cjs/modules/slack/hooks/useSlackChannels.js.map +1 -1
  25. package/dist/cjs/modules/slack/hooks/useSlackConnectionStatus.js.map +1 -1
  26. package/dist/esm/modules/core/constants.mjs.map +1 -1
  27. package/dist/esm/modules/core/context/KnockProvider.mjs +25 -42
  28. package/dist/esm/modules/core/context/KnockProvider.mjs.map +1 -1
  29. package/dist/esm/modules/core/hooks/useAuthenticatedKnockClient.mjs.map +1 -1
  30. package/dist/esm/modules/core/utils.mjs +1 -7
  31. package/dist/esm/modules/core/utils.mjs.map +1 -1
  32. package/dist/esm/modules/feed/context/KnockFeedProvider.mjs +17 -27
  33. package/dist/esm/modules/feed/context/KnockFeedProvider.mjs.map +1 -1
  34. package/dist/esm/modules/feed/hooks/useFeedSettings.mjs +4 -1
  35. package/dist/esm/modules/feed/hooks/useFeedSettings.mjs.map +1 -1
  36. package/dist/esm/modules/feed/hooks/useNotifications.mjs +1 -8
  37. package/dist/esm/modules/feed/hooks/useNotifications.mjs.map +1 -1
  38. package/dist/esm/modules/i18n/context/KnockI18nProvider.mjs +8 -9
  39. package/dist/esm/modules/i18n/context/KnockI18nProvider.mjs.map +1 -1
  40. package/dist/esm/modules/i18n/hooks/useTranslations.mjs +4 -1
  41. package/dist/esm/modules/i18n/hooks/useTranslations.mjs.map +1 -1
  42. package/dist/esm/modules/i18n/languages/de.mjs.map +1 -1
  43. package/dist/esm/modules/i18n/languages/en.mjs.map +1 -1
  44. package/dist/esm/modules/i18n/languages/index.mjs +4 -1
  45. package/dist/esm/modules/i18n/languages/index.mjs.map +1 -1
  46. package/dist/esm/modules/slack/context/KnockSlackProvider.mjs +35 -47
  47. package/dist/esm/modules/slack/context/KnockSlackProvider.mjs.map +1 -1
  48. package/dist/esm/modules/slack/hooks/useConnectedSlackChannels.mjs +15 -11
  49. package/dist/esm/modules/slack/hooks/useConnectedSlackChannels.mjs.map +1 -1
  50. package/dist/esm/modules/slack/hooks/useSlackAuth.mjs +10 -23
  51. package/dist/esm/modules/slack/hooks/useSlackAuth.mjs.map +1 -1
  52. package/dist/esm/modules/slack/hooks/useSlackChannels.mjs +37 -39
  53. package/dist/esm/modules/slack/hooks/useSlackChannels.mjs.map +1 -1
  54. package/dist/esm/modules/slack/hooks/useSlackConnectionStatus.mjs +3 -1
  55. package/dist/esm/modules/slack/hooks/useSlackConnectionStatus.mjs.map +1 -1
  56. package/dist/types/modules/slack/context/KnockSlackProvider.d.ts.map +1 -1
  57. package/dist/types/modules/slack/hooks/useSlackChannels.d.ts.map +1 -1
  58. package/package.json +5 -4
  59. package/src/modules/slack/context/KnockSlackProvider.tsx +1 -4
  60. package/src/modules/slack/hooks/useSlackChannels.ts +62 -34
@@ -1,51 +1,49 @@
1
- import { useKnockSlackClient as s } from "../context/KnockSlackProvider.mjs";
2
- import { useMemo as N, useEffect as E } from "react";
1
+ import { useKnockSlackClient as L } from "../context/KnockSlackProvider.mjs";
2
+ import { useMemo as N, useEffect as g } from "react";
3
3
  import "../../i18n/context/KnockI18nProvider.mjs";
4
- import { useInfiniteQuery as I } from "@tanstack/react-query";
5
- import { useKnockClient as S } from "../../core/context/KnockProvider.mjs";
4
+ import A from "swr/infinite";
5
+ import { useKnockClient as I } from "../../core/context/KnockProvider.mjs";
6
6
  import "@knocklabs/client";
7
7
  import "date-fns";
8
- const M = 1e3, d = 200, A = "private_channel,public_channel";
8
+ const P = 1e3, K = 200, M = "private_channel,public_channel", u = "SLACK_CHANNELS";
9
+ function z(n, e) {
10
+ return n === 0 ? [u, ""] : e && ["", null].includes(e.next_cursor) ? null : [u, e.next_cursor];
11
+ }
9
12
  function G({
10
- queryOptions: c
13
+ queryOptions: n
11
14
  }) {
12
- const k = S(), { knockSlackChannelId: C, tenant: _, connectionStatus: r } = s(), u = ({ pageParam: n }) => k.slack.getChannels({
13
- tenant: _,
14
- knockChannelId: C,
15
+ var C, _;
16
+ const e = I(), {
17
+ knockSlackChannelId: S,
18
+ tenant: d,
19
+ connectionStatus: a
20
+ } = L(), x = (c) => e.slack.getChannels({
21
+ tenant: d,
22
+ knockChannelId: S,
15
23
  queryOptions: {
16
- ...c,
17
- cursor: n,
18
- limit: (c == null ? void 0 : c.limitPerPage) || d,
19
- types: (c == null ? void 0 : c.types) || A
24
+ ...n,
25
+ cursor: c ? c[1] : "",
26
+ limit: (n == null ? void 0 : n.limitPerPage) || K,
27
+ types: (n == null ? void 0 : n.types) || M
20
28
  }
21
29
  }), {
22
30
  data: t,
23
- isLoading: x,
24
- isFetching: m,
25
- fetchNextPage: f,
26
- hasNextPage: i,
27
- refetch: a,
28
- error: h
29
- } = I({
30
- queryKey: ["slackChannels"],
31
- queryFn: u,
32
- initialPageParam: "",
33
- getNextPageParam: (n) => (n == null ? void 0 : n.next_cursor) === "" ? null : n == null ? void 0 : n.next_cursor
34
- }), e = N(() => {
35
- var n;
36
- return ((n = t == null ? void 0 : t.pages) == null ? void 0 : n.flatMap((o) => o == null ? void 0 : o.slack_channels).filter((o) => !!o)) || [];
37
- }, [t == null ? void 0 : t.pages]), l = (c == null ? void 0 : c.maxCount) || M;
38
- return E(() => {
39
- r === "connected" && !h && i && !m && (e == null ? void 0 : e.length) < l && f();
40
- }, [
41
- e == null ? void 0 : e.length,
42
- f,
43
- i,
44
- m,
45
- l,
46
- h,
47
- r
48
- ]), { data: e, isLoading: x, refetch: a };
31
+ error: i,
32
+ isLoading: l,
33
+ isValidating: o,
34
+ size: f,
35
+ setSize: m,
36
+ mutate: E
37
+ } = A(z, x, {
38
+ initialSize: 0
39
+ }), s = (t == null ? void 0 : t.length) || 0, h = s === 0 || t && ((C = t[s]) == null ? void 0 : C.next_cursor) && ((_ = t[s]) == null ? void 0 : _.next_cursor) !== "", r = N(() => (t ?? []).flatMap((c) => c == null ? void 0 : c.slack_channels).filter((c) => !!c), [t]), k = (n == null ? void 0 : n.maxCount) || P;
40
+ return g(() => {
41
+ a === "connected" && !i && h && !l && !o && r.length < k && m(f + 1);
42
+ }, [r.length, m, f, h, l, o, k, i, a]), {
43
+ data: r,
44
+ isLoading: l || o,
45
+ refetch: () => E()
46
+ };
49
47
  }
50
48
  export {
51
49
  G as default
@@ -1 +1 @@
1
- {"version":3,"file":"useSlackChannels.mjs","sources":["../../../../../src/modules/slack/hooks/useSlackChannels.ts"],"sourcesContent":["import { SlackChannelQueryOptions, useKnockSlackClient } from \"..\";\nimport { SlackChannel } from \"@knocklabs/client\";\nimport { useInfiniteQuery } from \"@tanstack/react-query\";\nimport { useEffect, useMemo } from \"react\";\n\nimport { useKnockClient } from \"../../core\";\n\nconst MAX_COUNT = 1000;\nconst LIMIT_PER_PAGE = 200;\nconst CHANNEL_TYPES = \"private_channel,public_channel\";\n\ntype UseSlackChannelsProps = {\n queryOptions?: SlackChannelQueryOptions;\n};\n\ntype UseSlackChannelOutput = {\n data: SlackChannel[];\n isLoading: boolean;\n refetch: () => void;\n};\n\nfunction useSlackChannels({\n queryOptions,\n}: UseSlackChannelsProps): UseSlackChannelOutput {\n const knock = useKnockClient();\n const { knockSlackChannelId, tenant, connectionStatus } =\n useKnockSlackClient();\n\n const fetchChannels = ({ pageParam }: { pageParam: string }) => {\n return knock.slack.getChannels({\n tenant,\n knockChannelId: knockSlackChannelId,\n queryOptions: {\n ...queryOptions,\n cursor: pageParam,\n limit: queryOptions?.limitPerPage || LIMIT_PER_PAGE,\n types: queryOptions?.types || CHANNEL_TYPES,\n },\n });\n };\n\n const {\n data,\n isLoading,\n isFetching,\n fetchNextPage,\n hasNextPage,\n refetch,\n error,\n } = useInfiniteQuery({\n queryKey: [\"slackChannels\"],\n queryFn: fetchChannels,\n initialPageParam: \"\",\n getNextPageParam: (lastPage) =>\n lastPage?.next_cursor === \"\" ? null : lastPage?.next_cursor,\n });\n\n const slackChannels = useMemo(() => {\n return (\n data?.pages\n ?.flatMap((page) => page?.slack_channels)\n .filter((channel) => !!channel) || []\n );\n }, [data?.pages]);\n\n const maxCount = queryOptions?.maxCount || MAX_COUNT;\n\n useEffect(() => {\n if (\n connectionStatus === \"connected\" &&\n !error &&\n hasNextPage &&\n !isFetching &&\n slackChannels?.length < maxCount\n ) {\n fetchNextPage();\n }\n }, [\n slackChannels?.length,\n fetchNextPage,\n hasNextPage,\n isFetching,\n maxCount,\n error,\n connectionStatus,\n ]);\n\n return { data: slackChannels, isLoading, refetch };\n}\n\nexport default useSlackChannels;\n"],"names":["MAX_COUNT","LIMIT_PER_PAGE","CHANNEL_TYPES","useSlackChannels","queryOptions","knock","useKnockClient","knockSlackChannelId","tenant","connectionStatus","useKnockSlackClient","fetchChannels","pageParam","data","isLoading","isFetching","fetchNextPage","hasNextPage","refetch","error","useInfiniteQuery","lastPage","slackChannels","useMemo","_a","page","channel","maxCount","useEffect"],"mappings":";;;;;;;AAOA,MAAMA,IAAY,KACZC,IAAiB,KACjBC,IAAgB;AAYtB,SAASC,EAAiB;AAAA,EACxB,cAAAC;AACF,GAAiD;AAC/C,QAAMC,IAAQC,KACR,EAAE,qBAAAC,GAAqB,QAAAC,GAAQ,kBAAAC,MACnCC,EAAoB,GAEhBC,IAAgB,CAAC,EAAE,WAAAC,QAChBP,EAAM,MAAM,YAAY;AAAA,IAC7B,QAAAG;AAAA,IACA,gBAAgBD;AAAA,IAChB,cAAc;AAAA,MACZ,GAAGH;AAAA,MACH,QAAQQ;AAAA,MACR,QAAOR,KAAA,gBAAAA,EAAc,iBAAgBH;AAAA,MACrC,QAAOG,KAAA,gBAAAA,EAAc,UAASF;AAAA,IAChC;AAAA,EAAA,CACD,GAGG;AAAA,IACJ,MAAAW;AAAA,IACA,WAAAC;AAAA,IACA,YAAAC;AAAA,IACA,eAAAC;AAAA,IACA,aAAAC;AAAA,IACA,SAAAC;AAAA,IACA,OAAAC;AAAA,MACEC,EAAiB;AAAA,IACnB,UAAU,CAAC,eAAe;AAAA,IAC1B,SAAST;AAAA,IACT,kBAAkB;AAAA,IAClB,kBAAkB,CAACU,OACjBA,KAAA,gBAAAA,EAAU,iBAAgB,KAAK,OAAOA,KAAA,gBAAAA,EAAU;AAAA,EAAA,CACnD,GAEKC,IAAgBC,EAAQ,MAAM;;AAClC,aACEC,IAAAX,KAAA,gBAAAA,EAAM,UAAN,gBAAAW,EACI,QAAQ,CAACC,MAASA,KAAA,gBAAAA,EAAM,gBACzB,OAAO,CAACC,MAAY,CAAC,CAACA,OAAY,CAAA;AAAA,EAAC,GAEvC,CAACb,KAAA,gBAAAA,EAAM,KAAK,CAAC,GAEVc,KAAWvB,KAAA,gBAAAA,EAAc,aAAYJ;AAE3C,SAAA4B,EAAU,MAAM;AAEZ,IAAAnB,MAAqB,eACrB,CAACU,KACDF,KACA,CAACF,MACDO,KAAA,gBAAAA,EAAe,UAASK,KAEVX;EAChB,GACC;AAAA,IACDM,KAAA,gBAAAA,EAAe;AAAA,IACfN;AAAA,IACAC;AAAA,IACAF;AAAA,IACAY;AAAA,IACAR;AAAA,IACAV;AAAA,EAAA,CACD,GAEM,EAAE,MAAMa,GAAe,WAAAR,GAAW,SAAAI,EAAQ;AACnD;"}
1
+ {"version":3,"file":"useSlackChannels.mjs","sources":["../../../../../src/modules/slack/hooks/useSlackChannels.ts"],"sourcesContent":["import { SlackChannelQueryOptions, useKnockSlackClient } from \"..\";\nimport { GetSlackChannelsResponse, SlackChannel } from \"@knocklabs/client\";\nimport { useEffect, useMemo } from \"react\";\nimport useSWRInfinite from \"swr/infinite\";\n\nimport { useKnockClient } from \"../../core\";\n\nconst MAX_COUNT = 1000;\nconst LIMIT_PER_PAGE = 200;\nconst CHANNEL_TYPES = \"private_channel,public_channel\";\n\nconst QUERY_KEY = \"SLACK_CHANNELS\";\n\ntype UseSlackChannelsProps = {\n queryOptions?: SlackChannelQueryOptions;\n};\n\ntype UseSlackChannelOutput = {\n data: SlackChannel[];\n isLoading: boolean;\n refetch: () => void;\n};\n\ntype QueryKey = [key: string, cursor: string] | null;\n\nfunction getQueryKey(\n pageIndex: number,\n previousPageData: GetSlackChannelsResponse,\n): QueryKey {\n // First page so just pass empty\n if (pageIndex === 0) {\n return [QUERY_KEY, \"\"];\n }\n\n // If there's no more data then return an empty next cursor\n if (previousPageData && [\"\", null].includes(previousPageData.next_cursor)) {\n return null;\n }\n\n // Next cursor exists so pass it\n return [QUERY_KEY, previousPageData.next_cursor];\n}\n\nfunction useSlackChannels({\n queryOptions,\n}: UseSlackChannelsProps): UseSlackChannelOutput {\n const knock = useKnockClient();\n const { knockSlackChannelId, tenant, connectionStatus } =\n useKnockSlackClient();\n\n const fetchChannels = (queryKey: QueryKey) => {\n return knock.slack.getChannels({\n tenant,\n knockChannelId: knockSlackChannelId,\n queryOptions: {\n ...queryOptions,\n cursor: queryKey ? queryKey[1] : \"\",\n limit: queryOptions?.limitPerPage || LIMIT_PER_PAGE,\n types: queryOptions?.types || CHANNEL_TYPES,\n },\n });\n };\n\n const { data, error, isLoading, isValidating, size, setSize, mutate } =\n useSWRInfinite<GetSlackChannelsResponse>(getQueryKey, fetchChannels, {\n initialSize: 0,\n });\n\n const currentPage = data?.length || 0;\n\n const hasNextPage =\n currentPage === 0 ||\n (data &&\n data[currentPage]?.next_cursor &&\n data[currentPage]?.next_cursor !== \"\");\n\n const slackChannels: SlackChannel[] = useMemo(\n () =>\n (data ?? [])\n .flatMap((page) => page?.slack_channels)\n .filter((channel) => !!channel),\n [data],\n );\n\n const maxCount = queryOptions?.maxCount || MAX_COUNT;\n\n useEffect(() => {\n if (\n connectionStatus === \"connected\" &&\n !error &&\n hasNextPage &&\n !isLoading &&\n !isValidating &&\n slackChannels.length < maxCount\n ) {\n // Fetch a page at a time until we have nothing else left to fetch\n // or we've already hit the max amount of channels to fetch\n setSize(size + 1);\n }\n }, [\n slackChannels.length,\n setSize,\n size,\n hasNextPage,\n isLoading,\n isValidating,\n maxCount,\n error,\n connectionStatus,\n ]);\n\n return {\n data: slackChannels,\n isLoading: isLoading || isValidating,\n refetch: () => mutate(),\n };\n}\n\nexport default useSlackChannels;\n"],"names":["MAX_COUNT","LIMIT_PER_PAGE","CHANNEL_TYPES","QUERY_KEY","getQueryKey","pageIndex","previousPageData","includes","next_cursor","useSlackChannels","queryOptions","knock","useKnockClient","knockSlackChannelId","tenant","connectionStatus","useKnockSlackClient","fetchChannels","queryKey","slack","getChannels","knockChannelId","cursor","limit","limitPerPage","types","data","error","isLoading","isValidating","size","setSize","mutate","useSWRInfinite","initialSize","currentPage","length","hasNextPage","slackChannels","useMemo","flatMap","page","slack_channels","filter","channel","maxCount","useEffect","refetch"],"mappings":";;;;;;;AAOA,MAAMA,IAAY,KACZC,IAAiB,KACjBC,IAAgB,kCAEhBC,IAAY;AAclB,SAASC,EACPC,GACAC,GACU;AAEV,SAAID,MAAc,IACT,CAACF,GAAW,EAAE,IAInBG,KAAoB,CAAC,IAAI,IAAI,EAAEC,SAASD,EAAiBE,WAAW,IAC/D,OAIF,CAACL,GAAWG,EAAiBE,WAAW;AACjD;AAEA,SAASC,EAAiB;AAAA,EACxBC,cAAAA;AACqB,GAA0B;;AAC/C,QAAMC,IAAQC,KACR;AAAA,IAAEC,qBAAAA;AAAAA,IAAqBC,QAAAA;AAAAA,IAAQC,kBAAAA;AAAAA,MACnCC,EAAoB,GAEhBC,IAAgBA,CAACC,MACdP,EAAMQ,MAAMC,YAAY;AAAA,IAC7BN,QAAAA;AAAAA,IACAO,gBAAgBR;AAAAA,IAChBH,cAAc;AAAA,MACZ,GAAGA;AAAAA,MACHY,QAAQJ,IAAWA,EAAS,CAAC,IAAI;AAAA,MACjCK,QAAOb,KAAAA,gBAAAA,EAAcc,iBAAgBvB;AAAAA,MACrCwB,QAAOf,KAAAA,gBAAAA,EAAce,UAASvB;AAAAA,IAChC;AAAA,EAAA,CACD,GAGG;AAAA,IAAEwB,MAAAA;AAAAA,IAAMC,OAAAA;AAAAA,IAAOC,WAAAA;AAAAA,IAAWC,cAAAA;AAAAA,IAAcC,MAAAA;AAAAA,IAAMC,SAAAA;AAAAA,IAASC,QAAAA;AAAAA,EAAAA,IAC3DC,EAAyC7B,GAAaa,GAAe;AAAA,IACnEiB,aAAa;AAAA,EAAA,CACd,GAEGC,KAAcT,KAAAA,gBAAAA,EAAMU,WAAU,GAE9BC,IACJF,MAAgB,KACfT,OACCA,IAAAA,EAAKS,CAAW,MAAhBT,gBAAAA,EAAmBlB,kBACnBkB,IAAAA,EAAKS,CAAW,MAAhBT,gBAAAA,EAAmBlB,iBAAgB,IAEjC8B,IAAgCC,EACpC,OACGb,KAAQ,IACNc,QAASC,CAASA,MAAAA,KAAAA,gBAAAA,EAAMC,cAAc,EACtCC,OAAQC,OAAY,CAAC,CAACA,CAAO,GAClC,CAAClB,CAAI,CACP,GAEMmB,KAAWnC,KAAAA,gBAAAA,EAAcmC,aAAY7C;AAE3C8C,SAAAA,EAAU,MAAM;AAEZ/B,IAAAA,MAAqB,eACrB,CAACY,KACDU,KACA,CAACT,KACD,CAACC,KACDS,EAAcF,SAASS,KAIvBd,EAAQD,IAAO,CAAC;AAAA,EAEjB,GAAA,CACDQ,EAAcF,QACdL,GACAD,GACAO,GACAT,GACAC,GACAgB,GACAlB,GACAZ,CAAgB,CACjB,GAEM;AAAA,IACLW,MAAMY;AAAAA,IACNV,WAAWA,KAAaC;AAAAA,IACxBkB,SAASA,MAAMf,EAAO;AAAA,EAAA;AAE1B;"}
@@ -6,7 +6,9 @@ const C = (o) => {
6
6
  return e == null ? void 0 : e.concat(c).replace("_", " ");
7
7
  };
8
8
  function y(o, e, c) {
9
- const { t: a } = A(), [r, n] = s("connecting"), [p, i] = s(null), [b, m] = s(null);
9
+ const {
10
+ t: a
11
+ } = A(), [r, n] = s("connecting"), [p, i] = s(null), [b, m] = s(null);
10
12
  return g(() => {
11
13
  (async () => {
12
14
  var u, l, f, k, S, d, h;
@@ -1 +1 @@
1
- {"version":3,"file":"useSlackConnectionStatus.mjs","sources":["../../../../../src/modules/slack/hooks/useSlackConnectionStatus.ts"],"sourcesContent":["import Knock from \"@knocklabs/client\";\nimport { useEffect, useState } from \"react\";\n\nimport { useTranslations } from \"../../i18n\";\n\nexport type ConnectionStatus =\n | \"connecting\"\n | \"connected\"\n | \"disconnected\"\n | \"error\"\n | \"disconnecting\";\n\ntype UseSlackConnectionStatusOutput = {\n connectionStatus: ConnectionStatus;\n setConnectionStatus: (status: ConnectionStatus) => void;\n errorLabel: string | null;\n setErrorLabel: (errorLabel: string) => void;\n actionLabel: string | null;\n setActionLabel: (actionLabel: string | null) => void;\n};\n\n/**\n * Transforms a slack error message into\n * a formatted one. Slack error messages: https://api.slack.com/methods/auth.test#errors\n *\n * Ex.: \"account_inactive\" -> \"Account inactive\"\n */\nconst formatSlackErrorMessage = (errorMessage: string) => {\n const firstLetter = errorMessage.substring(0, 1).toUpperCase();\n const rest = errorMessage.substring(1);\n return firstLetter?.concat(rest).replace(\"_\", \" \");\n};\n\nfunction useSlackConnectionStatus(\n knock: Knock,\n knockSlackChannelId: string,\n tenant: string,\n): UseSlackConnectionStatusOutput {\n const { t } = useTranslations();\n const [connectionStatus, setConnectionStatus] =\n useState<ConnectionStatus>(\"connecting\");\n const [errorLabel, setErrorLabel] = useState<string | null>(null);\n const [actionLabel, setActionLabel] = useState<string | null>(null);\n\n useEffect(() => {\n const checkAuthStatus = async () => {\n if (connectionStatus !== \"connecting\") return;\n\n try {\n const authRes = await knock.slack.authCheck({\n tenant,\n knockChannelId: knockSlackChannelId,\n });\n\n if (authRes.connection?.ok) {\n return setConnectionStatus(\"connected\");\n }\n\n if (!authRes.connection?.ok) {\n return setConnectionStatus(\"disconnected\");\n }\n\n // This is a normal response for a tenant that doesn't have an access\n // token set on it, meaning it's not connected to Slack, so we\n // give it a \"disconnected\" status instead of an error status.\n if (\n authRes.code === \"ERR_BAD_REQUEST\" &&\n authRes.response?.data?.message === t(\"slackAccessTokenNotSet\")\n ) {\n return setConnectionStatus(\"disconnected\");\n }\n\n // This is for an error coming directly from Slack.\n if (!authRes.connection?.ok && authRes.connection?.error) {\n const errorLabel = formatSlackErrorMessage(authRes.connection?.error);\n setErrorLabel(errorLabel);\n setConnectionStatus(\"error\");\n return;\n }\n\n // This is for any Knock errors that would require a reconnect.\n\n setConnectionStatus(\"error\");\n } catch (error) {\n setConnectionStatus(\"error\");\n }\n };\n\n checkAuthStatus();\n }, [connectionStatus, tenant, knockSlackChannelId, knock.slack, t]);\n\n return {\n connectionStatus,\n setConnectionStatus,\n errorLabel,\n setErrorLabel,\n actionLabel,\n setActionLabel,\n };\n}\n\nexport default useSlackConnectionStatus;\n"],"names":["formatSlackErrorMessage","errorMessage","firstLetter","rest","useSlackConnectionStatus","knock","knockSlackChannelId","tenant","t","useTranslations","connectionStatus","setConnectionStatus","useState","errorLabel","setErrorLabel","actionLabel","setActionLabel","useEffect","authRes","_a","_b","_d","_c","_e","_f","_g"],"mappings":";;;AA2BA,MAAMA,IAA0B,CAACC,MAAyB;AACxD,QAAMC,IAAcD,EAAa,UAAU,GAAG,CAAC,EAAE,eAC3CE,IAAOF,EAAa,UAAU,CAAC;AACrC,SAAOC,KAAA,gBAAAA,EAAa,OAAOC,GAAM,QAAQ,KAAK;AAChD;AAEA,SAASC,EACPC,GACAC,GACAC,GACgC;AAC1B,QAAA,EAAE,GAAAC,MAAMC,KACR,CAACC,GAAkBC,CAAmB,IAC1CC,EAA2B,YAAY,GACnC,CAACC,GAAYC,CAAa,IAAIF,EAAwB,IAAI,GAC1D,CAACG,GAAaC,CAAc,IAAIJ,EAAwB,IAAI;AAElE,SAAAK,EAAU,MAAM;AA4CE,KA3CQ,YAAY;;AAClC,UAAIP,MAAqB;AAErB,YAAA;AACF,gBAAMQ,IAAU,MAAMb,EAAM,MAAM,UAAU;AAAA,YAC1C,QAAAE;AAAA,YACA,gBAAgBD;AAAA,UAAA,CACjB;AAEG,eAAAa,IAAAD,EAAQ,eAAR,QAAAC,EAAoB;AACtB,mBAAOR,EAAoB,WAAW;AAWtC,cARE,GAACS,IAAAF,EAAQ,eAAR,QAAAE,EAAoB,OAQvBF,EAAQ,SAAS,uBACjBG,KAAAC,IAAAJ,EAAQ,aAAR,gBAAAI,EAAkB,SAAlB,gBAAAD,EAAwB,aAAYb,EAAE,wBAAwB;AAE9D,mBAAOG,EAAoB,cAAc;AAI3C,cAAI,GAACY,IAAAL,EAAQ,eAAR,QAAAK,EAAoB,SAAMC,IAAAN,EAAQ,eAAR,QAAAM,EAAoB,QAAO;AACxD,kBAAMX,IAAab,GAAwByB,IAAAP,EAAQ,eAAR,gBAAAO,EAAoB,KAAK;AACpE,YAAAX,EAAcD,CAAU,GACxBF,EAAoB,OAAO;AAC3B;AAAA,UACF;AAIA,UAAAA,EAAoB,OAAO;AAAA,gBACb;AACd,UAAAA,EAAoB,OAAO;AAAA,QAC7B;AAAA,IAAA;EAGc,GACf,CAACD,GAAkBH,GAAQD,GAAqBD,EAAM,OAAOG,CAAC,CAAC,GAE3D;AAAA,IACL,kBAAAE;AAAA,IACA,qBAAAC;AAAA,IACA,YAAAE;AAAA,IACA,eAAAC;AAAA,IACA,aAAAC;AAAA,IACA,gBAAAC;AAAA,EAAA;AAEJ;"}
1
+ {"version":3,"file":"useSlackConnectionStatus.mjs","sources":["../../../../../src/modules/slack/hooks/useSlackConnectionStatus.ts"],"sourcesContent":["import Knock from \"@knocklabs/client\";\nimport { useEffect, useState } from \"react\";\n\nimport { useTranslations } from \"../../i18n\";\n\nexport type ConnectionStatus =\n | \"connecting\"\n | \"connected\"\n | \"disconnected\"\n | \"error\"\n | \"disconnecting\";\n\ntype UseSlackConnectionStatusOutput = {\n connectionStatus: ConnectionStatus;\n setConnectionStatus: (status: ConnectionStatus) => void;\n errorLabel: string | null;\n setErrorLabel: (errorLabel: string) => void;\n actionLabel: string | null;\n setActionLabel: (actionLabel: string | null) => void;\n};\n\n/**\n * Transforms a slack error message into\n * a formatted one. Slack error messages: https://api.slack.com/methods/auth.test#errors\n *\n * Ex.: \"account_inactive\" -> \"Account inactive\"\n */\nconst formatSlackErrorMessage = (errorMessage: string) => {\n const firstLetter = errorMessage.substring(0, 1).toUpperCase();\n const rest = errorMessage.substring(1);\n return firstLetter?.concat(rest).replace(\"_\", \" \");\n};\n\nfunction useSlackConnectionStatus(\n knock: Knock,\n knockSlackChannelId: string,\n tenant: string,\n): UseSlackConnectionStatusOutput {\n const { t } = useTranslations();\n const [connectionStatus, setConnectionStatus] =\n useState<ConnectionStatus>(\"connecting\");\n const [errorLabel, setErrorLabel] = useState<string | null>(null);\n const [actionLabel, setActionLabel] = useState<string | null>(null);\n\n useEffect(() => {\n const checkAuthStatus = async () => {\n if (connectionStatus !== \"connecting\") return;\n\n try {\n const authRes = await knock.slack.authCheck({\n tenant,\n knockChannelId: knockSlackChannelId,\n });\n\n if (authRes.connection?.ok) {\n return setConnectionStatus(\"connected\");\n }\n\n if (!authRes.connection?.ok) {\n return setConnectionStatus(\"disconnected\");\n }\n\n // This is a normal response for a tenant that doesn't have an access\n // token set on it, meaning it's not connected to Slack, so we\n // give it a \"disconnected\" status instead of an error status.\n if (\n authRes.code === \"ERR_BAD_REQUEST\" &&\n authRes.response?.data?.message === t(\"slackAccessTokenNotSet\")\n ) {\n return setConnectionStatus(\"disconnected\");\n }\n\n // This is for an error coming directly from Slack.\n if (!authRes.connection?.ok && authRes.connection?.error) {\n const errorLabel = formatSlackErrorMessage(authRes.connection?.error);\n setErrorLabel(errorLabel);\n setConnectionStatus(\"error\");\n return;\n }\n\n // This is for any Knock errors that would require a reconnect.\n\n setConnectionStatus(\"error\");\n } catch (error) {\n setConnectionStatus(\"error\");\n }\n };\n\n checkAuthStatus();\n }, [connectionStatus, tenant, knockSlackChannelId, knock.slack, t]);\n\n return {\n connectionStatus,\n setConnectionStatus,\n errorLabel,\n setErrorLabel,\n actionLabel,\n setActionLabel,\n };\n}\n\nexport default useSlackConnectionStatus;\n"],"names":["formatSlackErrorMessage","errorMessage","firstLetter","substring","toUpperCase","rest","concat","replace","useSlackConnectionStatus","knock","knockSlackChannelId","tenant","t","useTranslations","connectionStatus","setConnectionStatus","useState","errorLabel","setErrorLabel","actionLabel","setActionLabel","useEffect","authRes","slack","authCheck","knockChannelId","connection","ok","code","response","data","message","error"],"mappings":";;;AA2BA,MAAMA,IAA0BA,CAACC,MAAyB;AACxD,QAAMC,IAAcD,EAAaE,UAAU,GAAG,CAAC,EAAEC,eAC3CC,IAAOJ,EAAaE,UAAU,CAAC;AACrC,SAAOD,KAAAA,gBAAAA,EAAaI,OAAOD,GAAME,QAAQ,KAAK;AAChD;AAEA,SAASC,EACPC,GACAC,GACAC,GACgC;AAC1B,QAAA;AAAA,IAAEC,GAAAA;AAAAA,MAAMC,EAAgB,GACxB,CAACC,GAAkBC,CAAmB,IAC1CC,EAA2B,YAAY,GACnC,CAACC,GAAYC,CAAa,IAAIF,EAAwB,IAAI,GAC1D,CAACG,GAAaC,CAAc,IAAIJ,EAAwB,IAAI;AAElEK,SAAAA,EAAU,MAAM;AA4CE,KA3CQ,YAAY;;AAClC,UAAIP,MAAqB;AAErB,YAAA;AACF,gBAAMQ,IAAU,MAAMb,EAAMc,MAAMC,UAAU;AAAA,YAC1Cb,QAAAA;AAAAA,YACAc,gBAAgBf;AAAAA,UAAAA,CACjB;AAEGY,eAAAA,IAAAA,EAAQI,eAARJ,QAAAA,EAAoBK;AACtB,mBAAOZ,EAAoB,WAAW;AAWtCO,cARE,GAACA,IAAAA,EAAQI,eAARJ,QAAAA,EAAoBK,OAQvBL,EAAQM,SAAS,uBACjBN,KAAAA,IAAAA,EAAQO,aAARP,gBAAAA,EAAkBQ,SAAlBR,gBAAAA,EAAwBS,aAAYnB,EAAE,wBAAwB;AAE9D,mBAAOG,EAAoB,cAAc;AAI3C,cAAI,GAACO,IAAAA,EAAQI,eAARJ,QAAAA,EAAoBK,SAAML,IAAAA,EAAQI,eAARJ,QAAAA,EAAoBU,QAAO;AACxD,kBAAMf,IAAajB,GAAwBsB,IAAAA,EAAQI,eAARJ,gBAAAA,EAAoBU,KAAK;AACpEd,YAAAA,EAAcD,CAAU,GACxBF,EAAoB,OAAO;AAC3B;AAAA,UACF;AAIAA,UAAAA,EAAoB,OAAO;AAAA,gBACb;AACdA,UAAAA,EAAoB,OAAO;AAAA,QAC7B;AAAA,IAAA;EAGc,GACf,CAACD,GAAkBH,GAAQD,GAAqBD,EAAMc,OAAOX,CAAC,CAAC,GAE3D;AAAA,IACLE,kBAAAA;AAAAA,IACAC,qBAAAA;AAAAA,IACAE,YAAAA;AAAAA,IACAC,eAAAA;AAAAA,IACAC,aAAAA;AAAAA,IACAC,gBAAAA;AAAAA,EAAAA;AAEJ;"}
@@ -1 +1 @@
1
- {"version":3,"file":"KnockSlackProvider.d.ts","sourceRoot":"","sources":["../../../../../src/modules/slack/context/KnockSlackProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAIrE,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAChD;AAKD,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;CAC/B;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAsChE,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,uBAUtC,CAAC"}
1
+ {"version":3,"file":"KnockSlackProvider.d.ts","sourceRoot":"","sources":["../../../../../src/modules/slack/context/KnockSlackProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAErE,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAChD;AAKD,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;CAC/B;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAsChE,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,uBAUtC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useSlackChannels.d.ts","sourceRoot":"","sources":["../../../../../src/modules/slack/hooks/useSlackChannels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAuB,MAAM,IAAI,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAUjD,KAAK,qBAAqB,GAAG;IAC3B,YAAY,CAAC,EAAE,wBAAwB,CAAC;CACzC,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,iBAAS,gBAAgB,CAAC,EACxB,YAAY,GACb,EAAE,qBAAqB,GAAG,qBAAqB,CAiE/C;AAED,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"useSlackChannels.d.ts","sourceRoot":"","sources":["../../../../../src/modules/slack/hooks/useSlackChannels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAuB,MAAM,IAAI,CAAC;AACnE,OAAO,EAA4B,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAY3E,KAAK,qBAAqB,GAAG;IAC3B,YAAY,CAAC,EAAE,wBAAwB,CAAC;CACzC,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAsBF,iBAAS,gBAAgB,CAAC,EACxB,YAAY,GACb,EAAE,qBAAqB,GAAG,qBAAqB,CAuE/C;AAED,eAAe,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@knocklabs/react-core",
3
3
  "description": "A set of React components to build notification experiences powered by Knock",
4
4
  "author": "@knocklabs",
5
- "version": "0.2.7",
5
+ "version": "0.2.9",
6
6
  "license": "MIT",
7
7
  "main": "dist/cjs/index.js",
8
8
  "module": "dist/esm/index.mjs",
@@ -45,12 +45,12 @@
45
45
  "url": "https://github.com/knocklabs/javascript/issues"
46
46
  },
47
47
  "peerDependencies": {
48
- "react": ">=16.8.0"
48
+ "react": "^16.11.0 || ^17.0.0 || ^18.0.0"
49
49
  },
50
50
  "dependencies": {
51
- "@knocklabs/client": "^0.10.0",
52
- "@tanstack/react-query": "^5.18.1",
51
+ "@knocklabs/client": "^0.10.1",
53
52
  "date-fns": "^3.3.1",
53
+ "swr": "^2.2.5",
54
54
  "zustand": "^3.7.2"
55
55
  },
56
56
  "devDependencies": {
@@ -59,6 +59,7 @@
59
59
  "@typescript-eslint/eslint-plugin": "^6.10.0",
60
60
  "@typescript-eslint/parser": "^6.10.0",
61
61
  "@vitejs/plugin-react": "^4.2.0",
62
+ "babel-plugin-react-require": "^4.0.2",
62
63
  "eslint": "^8.53.0",
63
64
  "eslint-plugin-react-hooks": "^4.6.0",
64
65
  "eslint-plugin-react-refresh": "^0.4.4",
@@ -1,13 +1,10 @@
1
1
  import { useSlackConnectionStatus } from "..";
2
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3
2
  import * as React from "react";
4
3
 
5
4
  import { slackProviderKey } from "../../core";
6
5
  import { useKnockClient } from "../../core";
7
6
  import { ConnectionStatus } from "../hooks/useSlackConnectionStatus";
8
7
 
9
- const queryClient = new QueryClient();
10
-
11
8
  export interface KnockSlackProviderState {
12
9
  knockSlackChannelId: string;
13
10
  tenant: string;
@@ -63,7 +60,7 @@ export const KnockSlackProvider: React.FC<KnockSlackProviderProps> = ({
63
60
  tenant,
64
61
  }}
65
62
  >
66
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
63
+ {children}
67
64
  </SlackProviderStateContext.Provider>
68
65
  );
69
66
  };
@@ -1,7 +1,7 @@
1
1
  import { SlackChannelQueryOptions, useKnockSlackClient } from "..";
2
- import { SlackChannel } from "@knocklabs/client";
3
- import { useInfiniteQuery } from "@tanstack/react-query";
2
+ import { GetSlackChannelsResponse, SlackChannel } from "@knocklabs/client";
4
3
  import { useEffect, useMemo } from "react";
4
+ import useSWRInfinite from "swr/infinite";
5
5
 
6
6
  import { useKnockClient } from "../../core";
7
7
 
@@ -9,6 +9,8 @@ const MAX_COUNT = 1000;
9
9
  const LIMIT_PER_PAGE = 200;
10
10
  const CHANNEL_TYPES = "private_channel,public_channel";
11
11
 
12
+ const QUERY_KEY = "SLACK_CHANNELS";
13
+
12
14
  type UseSlackChannelsProps = {
13
15
  queryOptions?: SlackChannelQueryOptions;
14
16
  };
@@ -19,6 +21,26 @@ type UseSlackChannelOutput = {
19
21
  refetch: () => void;
20
22
  };
21
23
 
24
+ type QueryKey = [key: string, cursor: string] | null;
25
+
26
+ function getQueryKey(
27
+ pageIndex: number,
28
+ previousPageData: GetSlackChannelsResponse,
29
+ ): QueryKey {
30
+ // First page so just pass empty
31
+ if (pageIndex === 0) {
32
+ return [QUERY_KEY, ""];
33
+ }
34
+
35
+ // If there's no more data then return an empty next cursor
36
+ if (previousPageData && ["", null].includes(previousPageData.next_cursor)) {
37
+ return null;
38
+ }
39
+
40
+ // Next cursor exists so pass it
41
+ return [QUERY_KEY, previousPageData.next_cursor];
42
+ }
43
+
22
44
  function useSlackChannels({
23
45
  queryOptions,
24
46
  }: UseSlackChannelsProps): UseSlackChannelOutput {
@@ -26,42 +48,39 @@ function useSlackChannels({
26
48
  const { knockSlackChannelId, tenant, connectionStatus } =
27
49
  useKnockSlackClient();
28
50
 
29
- const fetchChannels = ({ pageParam }: { pageParam: string }) => {
51
+ const fetchChannels = (queryKey: QueryKey) => {
30
52
  return knock.slack.getChannels({
31
53
  tenant,
32
54
  knockChannelId: knockSlackChannelId,
33
55
  queryOptions: {
34
56
  ...queryOptions,
35
- cursor: pageParam,
57
+ cursor: queryKey ? queryKey[1] : "",
36
58
  limit: queryOptions?.limitPerPage || LIMIT_PER_PAGE,
37
59
  types: queryOptions?.types || CHANNEL_TYPES,
38
60
  },
39
61
  });
40
62
  };
41
63
 
42
- const {
43
- data,
44
- isLoading,
45
- isFetching,
46
- fetchNextPage,
47
- hasNextPage,
48
- refetch,
49
- error,
50
- } = useInfiniteQuery({
51
- queryKey: ["slackChannels"],
52
- queryFn: fetchChannels,
53
- initialPageParam: "",
54
- getNextPageParam: (lastPage) =>
55
- lastPage?.next_cursor === "" ? null : lastPage?.next_cursor,
56
- });
57
-
58
- const slackChannels = useMemo(() => {
59
- return (
60
- data?.pages
61
- ?.flatMap((page) => page?.slack_channels)
62
- .filter((channel) => !!channel) || []
63
- );
64
- }, [data?.pages]);
64
+ const { data, error, isLoading, isValidating, size, setSize, mutate } =
65
+ useSWRInfinite<GetSlackChannelsResponse>(getQueryKey, fetchChannels, {
66
+ initialSize: 0,
67
+ });
68
+
69
+ const currentPage = data?.length || 0;
70
+
71
+ const hasNextPage =
72
+ currentPage === 0 ||
73
+ (data &&
74
+ data[currentPage]?.next_cursor &&
75
+ data[currentPage]?.next_cursor !== "");
76
+
77
+ const slackChannels: SlackChannel[] = useMemo(
78
+ () =>
79
+ (data ?? [])
80
+ .flatMap((page) => page?.slack_channels)
81
+ .filter((channel) => !!channel),
82
+ [data],
83
+ );
65
84
 
66
85
  const maxCount = queryOptions?.maxCount || MAX_COUNT;
67
86
 
@@ -70,22 +89,31 @@ function useSlackChannels({
70
89
  connectionStatus === "connected" &&
71
90
  !error &&
72
91
  hasNextPage &&
73
- !isFetching &&
74
- slackChannels?.length < maxCount
92
+ !isLoading &&
93
+ !isValidating &&
94
+ slackChannels.length < maxCount
75
95
  ) {
76
- fetchNextPage();
96
+ // Fetch a page at a time until we have nothing else left to fetch
97
+ // or we've already hit the max amount of channels to fetch
98
+ setSize(size + 1);
77
99
  }
78
100
  }, [
79
- slackChannels?.length,
80
- fetchNextPage,
101
+ slackChannels.length,
102
+ setSize,
103
+ size,
81
104
  hasNextPage,
82
- isFetching,
105
+ isLoading,
106
+ isValidating,
83
107
  maxCount,
84
108
  error,
85
109
  connectionStatus,
86
110
  ]);
87
111
 
88
- return { data: slackChannels, isLoading, refetch };
112
+ return {
113
+ data: slackChannels,
114
+ isLoading: isLoading || isValidating,
115
+ refetch: () => mutate(),
116
+ };
89
117
  }
90
118
 
91
119
  export default useSlackChannels;