@cstar.help/react 0.10.3 → 0.11.0
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.
- package/dist/index.cjs +171 -168
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +118 -115
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -465,105 +465,117 @@ function useCategories() {
|
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
// src/library/useArticles.ts
|
|
468
|
+
var import_react11 = require("react");
|
|
469
|
+
|
|
470
|
+
// src/useLatestCall.ts
|
|
468
471
|
var import_react10 = require("react");
|
|
472
|
+
function useLatestCall() {
|
|
473
|
+
const latest = (0, import_react10.useRef)(0);
|
|
474
|
+
(0, import_react10.useEffect)(
|
|
475
|
+
() => () => {
|
|
476
|
+
latest.current += 1;
|
|
477
|
+
},
|
|
478
|
+
[]
|
|
479
|
+
);
|
|
480
|
+
return (0, import_react10.useCallback)(() => {
|
|
481
|
+
const call = latest.current += 1;
|
|
482
|
+
return () => call === latest.current;
|
|
483
|
+
}, []);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// src/library/useArticles.ts
|
|
469
487
|
function useArticles(params) {
|
|
470
488
|
const client = useLibraryClient();
|
|
471
|
-
const [articles, setArticles] = (0,
|
|
472
|
-
const [isLoading, setIsLoading] = (0,
|
|
473
|
-
const [error, setError] = (0,
|
|
474
|
-
const
|
|
489
|
+
const [articles, setArticles] = (0, import_react11.useState)([]);
|
|
490
|
+
const [isLoading, setIsLoading] = (0, import_react11.useState)(true);
|
|
491
|
+
const [error, setError] = (0, import_react11.useState)(null);
|
|
492
|
+
const startCall = useLatestCall();
|
|
475
493
|
const categorySlug = params?.categorySlug;
|
|
476
494
|
const limit = params?.limit;
|
|
477
495
|
const offset = params?.offset;
|
|
478
|
-
const refresh = (0,
|
|
496
|
+
const refresh = (0, import_react11.useCallback)(async () => {
|
|
497
|
+
const isLatest = startCall();
|
|
479
498
|
setIsLoading(true);
|
|
480
499
|
setError(null);
|
|
481
500
|
try {
|
|
482
501
|
const data = await client.articles({ categorySlug, limit, offset });
|
|
483
|
-
if (
|
|
502
|
+
if (isLatest()) {
|
|
484
503
|
setArticles(data);
|
|
485
504
|
}
|
|
486
505
|
} catch (err) {
|
|
487
|
-
if (
|
|
506
|
+
if (isLatest()) {
|
|
488
507
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
489
508
|
}
|
|
490
509
|
} finally {
|
|
491
|
-
if (
|
|
510
|
+
if (isLatest()) {
|
|
492
511
|
setIsLoading(false);
|
|
493
512
|
}
|
|
494
513
|
}
|
|
495
|
-
}, [client, categorySlug, limit, offset]);
|
|
496
|
-
(0,
|
|
497
|
-
mountedRef.current = true;
|
|
514
|
+
}, [client, categorySlug, limit, offset, startCall]);
|
|
515
|
+
(0, import_react11.useEffect)(() => {
|
|
498
516
|
refresh();
|
|
499
|
-
return () => {
|
|
500
|
-
mountedRef.current = false;
|
|
501
|
-
};
|
|
502
517
|
}, [refresh]);
|
|
503
518
|
return { articles, isLoading, error, refresh };
|
|
504
519
|
}
|
|
505
520
|
|
|
506
521
|
// src/library/useArticle.ts
|
|
507
|
-
var
|
|
522
|
+
var import_react12 = require("react");
|
|
508
523
|
function useArticle(slug) {
|
|
509
524
|
const client = useLibraryClient();
|
|
510
|
-
const [article, setArticle] = (0,
|
|
511
|
-
const [isLoading, setIsLoading] = (0,
|
|
512
|
-
const [error, setError] = (0,
|
|
513
|
-
const
|
|
514
|
-
const refresh = (0,
|
|
525
|
+
const [article, setArticle] = (0, import_react12.useState)(null);
|
|
526
|
+
const [isLoading, setIsLoading] = (0, import_react12.useState)(true);
|
|
527
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
528
|
+
const startCall = useLatestCall();
|
|
529
|
+
const refresh = (0, import_react12.useCallback)(async () => {
|
|
515
530
|
if (!slug) return;
|
|
531
|
+
const isLatest = startCall();
|
|
516
532
|
setIsLoading(true);
|
|
517
533
|
setError(null);
|
|
518
534
|
try {
|
|
519
535
|
const data = await client.article(slug);
|
|
520
|
-
if (
|
|
536
|
+
if (isLatest()) {
|
|
521
537
|
setArticle(data);
|
|
522
538
|
}
|
|
523
539
|
} catch (err) {
|
|
524
|
-
if (
|
|
540
|
+
if (isLatest()) {
|
|
525
541
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
526
542
|
}
|
|
527
543
|
} finally {
|
|
528
|
-
if (
|
|
544
|
+
if (isLatest()) {
|
|
529
545
|
setIsLoading(false);
|
|
530
546
|
}
|
|
531
547
|
}
|
|
532
|
-
}, [client, slug]);
|
|
533
|
-
const recordView = (0,
|
|
548
|
+
}, [client, slug, startCall]);
|
|
549
|
+
const recordView = (0, import_react12.useCallback)(async () => {
|
|
534
550
|
if (!slug) return;
|
|
535
551
|
try {
|
|
536
552
|
await client.recordView(slug);
|
|
537
553
|
} catch {
|
|
538
554
|
}
|
|
539
555
|
}, [client, slug]);
|
|
540
|
-
(0,
|
|
541
|
-
mountedRef.current = true;
|
|
556
|
+
(0, import_react12.useEffect)(() => {
|
|
542
557
|
if (!slug) {
|
|
558
|
+
startCall();
|
|
543
559
|
setArticle(null);
|
|
544
560
|
setIsLoading(false);
|
|
545
561
|
return;
|
|
546
562
|
}
|
|
547
563
|
refresh();
|
|
548
|
-
|
|
549
|
-
mountedRef.current = false;
|
|
550
|
-
};
|
|
551
|
-
}, [slug, refresh]);
|
|
564
|
+
}, [slug, refresh, startCall]);
|
|
552
565
|
return { article, isLoading, error, refresh, recordView };
|
|
553
566
|
}
|
|
554
567
|
|
|
555
568
|
// src/library/useArticleSearch.ts
|
|
556
|
-
var
|
|
569
|
+
var import_react13 = require("react");
|
|
557
570
|
var DEBOUNCE_MS = 300;
|
|
558
571
|
function useArticleSearch(query) {
|
|
559
572
|
const client = useLibraryClient();
|
|
560
|
-
const [results, setResults] = (0,
|
|
561
|
-
const [totalCount, setTotalCount] = (0,
|
|
562
|
-
const [isLoading, setIsLoading] = (0,
|
|
563
|
-
const [error, setError] = (0,
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
mountedRef.current = true;
|
|
573
|
+
const [results, setResults] = (0, import_react13.useState)([]);
|
|
574
|
+
const [totalCount, setTotalCount] = (0, import_react13.useState)(0);
|
|
575
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
|
|
576
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
577
|
+
(0, import_react13.useEffect)(() => {
|
|
578
|
+
let cancelled = false;
|
|
567
579
|
const trimmed = query.trim();
|
|
568
580
|
if (!trimmed) {
|
|
569
581
|
setResults([]);
|
|
@@ -576,23 +588,23 @@ function useArticleSearch(query) {
|
|
|
576
588
|
const timer = setTimeout(async () => {
|
|
577
589
|
try {
|
|
578
590
|
const result = await client.search(trimmed);
|
|
579
|
-
if (
|
|
591
|
+
if (!cancelled) {
|
|
580
592
|
setResults(result.data);
|
|
581
593
|
setTotalCount(result.count);
|
|
582
594
|
setError(null);
|
|
583
595
|
}
|
|
584
596
|
} catch (err) {
|
|
585
|
-
if (
|
|
597
|
+
if (!cancelled) {
|
|
586
598
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
587
599
|
}
|
|
588
600
|
} finally {
|
|
589
|
-
if (
|
|
601
|
+
if (!cancelled) {
|
|
590
602
|
setIsLoading(false);
|
|
591
603
|
}
|
|
592
604
|
}
|
|
593
605
|
}, DEBOUNCE_MS);
|
|
594
606
|
return () => {
|
|
595
|
-
|
|
607
|
+
cancelled = true;
|
|
596
608
|
clearTimeout(timer);
|
|
597
609
|
};
|
|
598
610
|
}, [client, query]);
|
|
@@ -600,11 +612,11 @@ function useArticleSearch(query) {
|
|
|
600
612
|
}
|
|
601
613
|
|
|
602
614
|
// src/community/CStarCommunityProvider.tsx
|
|
603
|
-
var
|
|
615
|
+
var import_react14 = require("react");
|
|
604
616
|
var import_community = require("@cstar.help/js/community");
|
|
605
617
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
606
618
|
function CStarCommunityProvider({ children, ...config }) {
|
|
607
|
-
const clientRef = (0,
|
|
619
|
+
const clientRef = (0, import_react14.useRef)(null);
|
|
608
620
|
if (!clientRef.current) {
|
|
609
621
|
clientRef.current = new import_community.CommunityClient(config);
|
|
610
622
|
}
|
|
@@ -612,14 +624,14 @@ function CStarCommunityProvider({ children, ...config }) {
|
|
|
612
624
|
}
|
|
613
625
|
|
|
614
626
|
// src/community/useTopics.ts
|
|
615
|
-
var
|
|
627
|
+
var import_react15 = require("react");
|
|
616
628
|
function useTopics() {
|
|
617
629
|
const client = useCommunityClient();
|
|
618
|
-
const [topics, setTopics] = (0,
|
|
619
|
-
const [isLoading, setIsLoading] = (0,
|
|
620
|
-
const [error, setError] = (0,
|
|
621
|
-
const mountedRef = (0,
|
|
622
|
-
const refresh = (0,
|
|
630
|
+
const [topics, setTopics] = (0, import_react15.useState)([]);
|
|
631
|
+
const [isLoading, setIsLoading] = (0, import_react15.useState)(true);
|
|
632
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
633
|
+
const mountedRef = (0, import_react15.useRef)(true);
|
|
634
|
+
const refresh = (0, import_react15.useCallback)(async () => {
|
|
623
635
|
setIsLoading(true);
|
|
624
636
|
setError(null);
|
|
625
637
|
try {
|
|
@@ -637,7 +649,7 @@ function useTopics() {
|
|
|
637
649
|
}
|
|
638
650
|
}
|
|
639
651
|
}, [client]);
|
|
640
|
-
(0,
|
|
652
|
+
(0, import_react15.useEffect)(() => {
|
|
641
653
|
mountedRef.current = true;
|
|
642
654
|
refresh();
|
|
643
655
|
return () => {
|
|
@@ -648,131 +660,121 @@ function useTopics() {
|
|
|
648
660
|
}
|
|
649
661
|
|
|
650
662
|
// src/community/usePosts.ts
|
|
651
|
-
var
|
|
663
|
+
var import_react16 = require("react");
|
|
652
664
|
function usePosts(params) {
|
|
653
665
|
const client = useCommunityClient();
|
|
654
|
-
const [posts, setPosts] = (0,
|
|
655
|
-
const [count, setCount] = (0,
|
|
656
|
-
const [isLoading, setIsLoading] = (0,
|
|
657
|
-
const [error, setError] = (0,
|
|
658
|
-
const
|
|
666
|
+
const [posts, setPosts] = (0, import_react16.useState)([]);
|
|
667
|
+
const [count, setCount] = (0, import_react16.useState)(0);
|
|
668
|
+
const [isLoading, setIsLoading] = (0, import_react16.useState)(true);
|
|
669
|
+
const [error, setError] = (0, import_react16.useState)(null);
|
|
670
|
+
const startCall = useLatestCall();
|
|
659
671
|
const topicSlug = params?.topicSlug;
|
|
660
672
|
const status = params?.status;
|
|
661
673
|
const sort = params?.sort;
|
|
662
674
|
const limit = params?.limit;
|
|
663
675
|
const offset = params?.offset;
|
|
664
|
-
const refresh = (0,
|
|
676
|
+
const refresh = (0, import_react16.useCallback)(async () => {
|
|
677
|
+
const isLatest = startCall();
|
|
665
678
|
setIsLoading(true);
|
|
666
679
|
setError(null);
|
|
667
680
|
try {
|
|
668
681
|
const result = await client.posts({ topicSlug, status, sort, limit, offset });
|
|
669
|
-
if (
|
|
682
|
+
if (isLatest()) {
|
|
670
683
|
setPosts(result.posts);
|
|
671
684
|
setCount(result.count);
|
|
672
685
|
}
|
|
673
686
|
} catch (err) {
|
|
674
|
-
if (
|
|
687
|
+
if (isLatest()) {
|
|
675
688
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
676
689
|
}
|
|
677
690
|
} finally {
|
|
678
|
-
if (
|
|
691
|
+
if (isLatest()) {
|
|
679
692
|
setIsLoading(false);
|
|
680
693
|
}
|
|
681
694
|
}
|
|
682
|
-
}, [client, topicSlug, status, sort, limit, offset]);
|
|
683
|
-
(0,
|
|
684
|
-
mountedRef.current = true;
|
|
695
|
+
}, [client, topicSlug, status, sort, limit, offset, startCall]);
|
|
696
|
+
(0, import_react16.useEffect)(() => {
|
|
685
697
|
refresh();
|
|
686
|
-
return () => {
|
|
687
|
-
mountedRef.current = false;
|
|
688
|
-
};
|
|
689
698
|
}, [refresh]);
|
|
690
699
|
return { posts, count, isLoading, error, refresh };
|
|
691
700
|
}
|
|
692
701
|
|
|
693
702
|
// src/community/usePost.ts
|
|
694
|
-
var
|
|
703
|
+
var import_react17 = require("react");
|
|
695
704
|
function usePost(slug) {
|
|
696
705
|
const client = useCommunityClient();
|
|
697
|
-
const [data, setData] = (0,
|
|
698
|
-
const [isLoading, setIsLoading] = (0,
|
|
699
|
-
const [error, setError] = (0,
|
|
700
|
-
const
|
|
701
|
-
const refresh = (0,
|
|
706
|
+
const [data, setData] = (0, import_react17.useState)(null);
|
|
707
|
+
const [isLoading, setIsLoading] = (0, import_react17.useState)(true);
|
|
708
|
+
const [error, setError] = (0, import_react17.useState)(null);
|
|
709
|
+
const startCall = useLatestCall();
|
|
710
|
+
const refresh = (0, import_react17.useCallback)(async () => {
|
|
711
|
+
const isLatest = startCall();
|
|
702
712
|
setIsLoading(true);
|
|
703
713
|
setError(null);
|
|
704
714
|
try {
|
|
705
715
|
const result = await client.post(slug);
|
|
706
|
-
if (
|
|
716
|
+
if (isLatest()) {
|
|
707
717
|
setData(result);
|
|
708
718
|
}
|
|
709
719
|
} catch (err) {
|
|
710
|
-
if (
|
|
720
|
+
if (isLatest()) {
|
|
711
721
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
712
722
|
}
|
|
713
723
|
} finally {
|
|
714
|
-
if (
|
|
724
|
+
if (isLatest()) {
|
|
715
725
|
setIsLoading(false);
|
|
716
726
|
}
|
|
717
727
|
}
|
|
718
|
-
}, [client, slug]);
|
|
719
|
-
(0,
|
|
720
|
-
mountedRef.current = true;
|
|
728
|
+
}, [client, slug, startCall]);
|
|
729
|
+
(0, import_react17.useEffect)(() => {
|
|
721
730
|
refresh();
|
|
722
|
-
return () => {
|
|
723
|
-
mountedRef.current = false;
|
|
724
|
-
};
|
|
725
731
|
}, [refresh]);
|
|
726
732
|
return { data, isLoading, error, refresh };
|
|
727
733
|
}
|
|
728
734
|
|
|
729
735
|
// src/community/useCommunitySearch.ts
|
|
730
|
-
var
|
|
736
|
+
var import_react18 = require("react");
|
|
731
737
|
function useCommunitySearch() {
|
|
732
738
|
const client = useCommunityClient();
|
|
733
|
-
const [results, setResults] = (0,
|
|
734
|
-
const [isLoading, setIsLoading] = (0,
|
|
735
|
-
const [error, setError] = (0,
|
|
736
|
-
const
|
|
737
|
-
(0,
|
|
738
|
-
mountedRef.current = true;
|
|
739
|
-
return () => {
|
|
740
|
-
mountedRef.current = false;
|
|
741
|
-
};
|
|
742
|
-
}, []);
|
|
743
|
-
const search = (0, import_react17.useCallback)(
|
|
739
|
+
const [results, setResults] = (0, import_react18.useState)(null);
|
|
740
|
+
const [isLoading, setIsLoading] = (0, import_react18.useState)(false);
|
|
741
|
+
const [error, setError] = (0, import_react18.useState)(null);
|
|
742
|
+
const startCall = useLatestCall();
|
|
743
|
+
const search = (0, import_react18.useCallback)(
|
|
744
744
|
async (query) => {
|
|
745
|
+
const isLatest = startCall();
|
|
745
746
|
if (!query.trim()) {
|
|
746
747
|
setResults(null);
|
|
748
|
+
setIsLoading(false);
|
|
747
749
|
return;
|
|
748
750
|
}
|
|
749
751
|
setIsLoading(true);
|
|
750
752
|
setError(null);
|
|
751
753
|
try {
|
|
752
754
|
const data = await client.search(query);
|
|
753
|
-
if (
|
|
755
|
+
if (isLatest()) {
|
|
754
756
|
setResults(data);
|
|
755
757
|
}
|
|
756
758
|
} catch (err) {
|
|
757
|
-
if (
|
|
759
|
+
if (isLatest()) {
|
|
758
760
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
759
761
|
}
|
|
760
762
|
} finally {
|
|
761
|
-
if (
|
|
763
|
+
if (isLatest()) {
|
|
762
764
|
setIsLoading(false);
|
|
763
765
|
}
|
|
764
766
|
}
|
|
765
767
|
},
|
|
766
|
-
[client]
|
|
768
|
+
[client, startCall]
|
|
767
769
|
);
|
|
768
770
|
return { results, isLoading, error, search };
|
|
769
771
|
}
|
|
770
772
|
|
|
771
773
|
// src/dashboard/CStarDashboardProvider.tsx
|
|
772
|
-
var
|
|
774
|
+
var import_react19 = require("react");
|
|
773
775
|
var import_js = require("@cstar.help/js");
|
|
774
776
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
775
|
-
var CStarDashboardContext = (0,
|
|
777
|
+
var CStarDashboardContext = (0, import_react19.createContext)(null);
|
|
776
778
|
function CStarDashboardProvider({
|
|
777
779
|
config,
|
|
778
780
|
client: providedClient,
|
|
@@ -783,7 +785,7 @@ function CStarDashboardProvider({
|
|
|
783
785
|
"CStarDashboardProvider requires either a `config` prop (`{ apiKey, teamId }`, recommended) or a `client` prop (a pre-built CStarClient instance, deprecated). See https://www.cstar.help/developers/sdk/react#dashboard"
|
|
784
786
|
);
|
|
785
787
|
}
|
|
786
|
-
const client = (0,
|
|
788
|
+
const client = (0, import_react19.useMemo)(() => {
|
|
787
789
|
if (providedClient) return providedClient;
|
|
788
790
|
return new import_js.CStarClient(config);
|
|
789
791
|
}, [
|
|
@@ -795,12 +797,12 @@ function CStarDashboardProvider({
|
|
|
795
797
|
config?.maxRetries,
|
|
796
798
|
config?.timeout
|
|
797
799
|
]);
|
|
798
|
-
const contextValue = (0,
|
|
800
|
+
const contextValue = (0, import_react19.useMemo)(() => ({ client }), [client]);
|
|
799
801
|
useDisconnectOnUnmount(providedClient ? null : client, (owned) => owned.realtime?.disconnect?.());
|
|
800
802
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CStarDashboardContext.Provider, { value: contextValue, children });
|
|
801
803
|
}
|
|
802
804
|
function useDashboardClient() {
|
|
803
|
-
const ctx = (0,
|
|
805
|
+
const ctx = (0, import_react19.useContext)(CStarDashboardContext);
|
|
804
806
|
if (!ctx) {
|
|
805
807
|
throw new Error("useDashboardClient must be used within a <CStarDashboardProvider>");
|
|
806
808
|
}
|
|
@@ -808,7 +810,7 @@ function useDashboardClient() {
|
|
|
808
810
|
}
|
|
809
811
|
|
|
810
812
|
// src/dashboard/useCStarQuery.ts
|
|
811
|
-
var
|
|
813
|
+
var import_react20 = require("react");
|
|
812
814
|
var import_js2 = require("@cstar.help/js");
|
|
813
815
|
function resolveResource(client, path) {
|
|
814
816
|
const parts = path.split(".");
|
|
@@ -827,12 +829,12 @@ function useCStarQuery(resource, params) {
|
|
|
827
829
|
);
|
|
828
830
|
}
|
|
829
831
|
const client = useDashboardClient();
|
|
830
|
-
const [data, setData] = (0,
|
|
831
|
-
const [loading, setLoading] = (0,
|
|
832
|
-
const [error, setError] = (0,
|
|
833
|
-
const subscriptionRef = (0,
|
|
832
|
+
const [data, setData] = (0, import_react20.useState)(null);
|
|
833
|
+
const [loading, setLoading] = (0, import_react20.useState)(true);
|
|
834
|
+
const [error, setError] = (0, import_react20.useState)(null);
|
|
835
|
+
const subscriptionRef = (0, import_react20.useRef)(null);
|
|
834
836
|
const paramsKey = params ? JSON.stringify(params) : "";
|
|
835
|
-
(0,
|
|
837
|
+
(0, import_react20.useEffect)(() => {
|
|
836
838
|
const resolved = resolveResource(client, resource);
|
|
837
839
|
if (!resolved) {
|
|
838
840
|
setError(new Error(`Invalid resource path: ${resource}. Expected format: 'tickets.list'`));
|
|
@@ -855,7 +857,7 @@ function useCStarQuery(resource, params) {
|
|
|
855
857
|
subscriptionRef.current = null;
|
|
856
858
|
};
|
|
857
859
|
}, [client, resource, paramsKey]);
|
|
858
|
-
const refresh = (0,
|
|
860
|
+
const refresh = (0, import_react20.useCallback)(async () => {
|
|
859
861
|
if (subscriptionRef.current) {
|
|
860
862
|
await subscriptionRef.current.refresh();
|
|
861
863
|
}
|
|
@@ -864,37 +866,38 @@ function useCStarQuery(resource, params) {
|
|
|
864
866
|
}
|
|
865
867
|
|
|
866
868
|
// src/dashboard/useCStarMutation.ts
|
|
867
|
-
var
|
|
869
|
+
var import_react21 = require("react");
|
|
868
870
|
function resolveMutation(client, path) {
|
|
869
871
|
const parts = path.split(".");
|
|
870
872
|
if (parts.length < 2) return null;
|
|
871
|
-
const
|
|
872
|
-
const methodName =
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
if (typeof method !== "function") return null;
|
|
878
|
-
if (methodName === "update") {
|
|
879
|
-
return (params) => {
|
|
880
|
-
const p = params;
|
|
881
|
-
const { id, ...rest } = p;
|
|
882
|
-
return method.call(resource, id, rest);
|
|
883
|
-
};
|
|
873
|
+
const last = parts[parts.length - 1];
|
|
874
|
+
const methodName = last === "delete" ? "del" : last;
|
|
875
|
+
let resource = client;
|
|
876
|
+
for (const part of parts.slice(0, -1)) {
|
|
877
|
+
resource = resource?.[part];
|
|
878
|
+
if (!resource || typeof resource !== "object") return null;
|
|
884
879
|
}
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
880
|
+
const method = resource[methodName];
|
|
881
|
+
if (typeof method !== "function") return null;
|
|
882
|
+
const call = method;
|
|
883
|
+
const needsId = methodName === "del" || methodName === "update" && call.length >= 2;
|
|
884
|
+
return (params) => {
|
|
885
|
+
if (Array.isArray(params)) return call.apply(resource, params);
|
|
886
|
+
const { id, ...rest } = params ?? {};
|
|
887
|
+
if (typeof id === "string" && id) {
|
|
888
|
+
return Object.keys(rest).length > 0 ? call.call(resource, id, rest) : call.call(resource, id);
|
|
889
|
+
}
|
|
890
|
+
if (needsId) {
|
|
891
|
+
return Promise.reject(new Error(`Missing or invalid "id" for ${methodName} operation`));
|
|
892
|
+
}
|
|
893
|
+
return call.call(resource, params);
|
|
894
|
+
};
|
|
892
895
|
}
|
|
893
896
|
function useCStarMutation(resource) {
|
|
894
897
|
const client = useDashboardClient();
|
|
895
|
-
const [loading, setLoading] = (0,
|
|
896
|
-
const [error, setError] = (0,
|
|
897
|
-
const mutate = (0,
|
|
898
|
+
const [loading, setLoading] = (0, import_react21.useState)(false);
|
|
899
|
+
const [error, setError] = (0, import_react21.useState)(null);
|
|
900
|
+
const mutate = (0, import_react21.useCallback)(
|
|
898
901
|
async (params) => {
|
|
899
902
|
const fn = resolveMutation(client, resource);
|
|
900
903
|
if (!fn) {
|
|
@@ -919,14 +922,14 @@ function useCStarMutation(resource) {
|
|
|
919
922
|
}
|
|
920
923
|
|
|
921
924
|
// src/dashboard/useCStarEvents.ts
|
|
922
|
-
var
|
|
925
|
+
var import_react22 = require("react");
|
|
923
926
|
var MAX_EVENTS = 100;
|
|
924
927
|
function useCStarEvents(types) {
|
|
925
928
|
const client = useDashboardClient();
|
|
926
|
-
const [events, setEvents] = (0,
|
|
927
|
-
const [connected, setConnected] = (0,
|
|
929
|
+
const [events, setEvents] = (0, import_react22.useState)([]);
|
|
930
|
+
const [connected, setConnected] = (0, import_react22.useState)(false);
|
|
928
931
|
const typesKey = types ? types.join(",") : "";
|
|
929
|
-
(0,
|
|
932
|
+
(0, import_react22.useEffect)(() => {
|
|
930
933
|
const realtime = client.realtime;
|
|
931
934
|
const handler = (event) => {
|
|
932
935
|
if (types && types.length > 0) {
|
|
@@ -958,14 +961,14 @@ function useCStarEvents(types) {
|
|
|
958
961
|
}
|
|
959
962
|
|
|
960
963
|
// src/dashboard/useBossBattle.ts
|
|
961
|
-
var
|
|
964
|
+
var import_react23 = require("react");
|
|
962
965
|
function useBossBattle() {
|
|
963
966
|
const client = useDashboardClient();
|
|
964
|
-
const [boss, setBoss] = (0,
|
|
965
|
-
const [loading, setLoading] = (0,
|
|
966
|
-
const [error, setError] = (0,
|
|
967
|
-
const subRef = (0,
|
|
968
|
-
(0,
|
|
967
|
+
const [boss, setBoss] = (0, import_react23.useState)(null);
|
|
968
|
+
const [loading, setLoading] = (0, import_react23.useState)(true);
|
|
969
|
+
const [error, setError] = (0, import_react23.useState)(null);
|
|
970
|
+
const subRef = (0, import_react23.useRef)(null);
|
|
971
|
+
(0, import_react23.useEffect)(() => {
|
|
969
972
|
const sub = client.game.subscribeBoss(client.realtime);
|
|
970
973
|
subRef.current = sub;
|
|
971
974
|
sub.on("change", (data) => {
|
|
@@ -982,21 +985,21 @@ function useBossBattle() {
|
|
|
982
985
|
subRef.current = null;
|
|
983
986
|
};
|
|
984
987
|
}, [client]);
|
|
985
|
-
const refresh = (0,
|
|
988
|
+
const refresh = (0, import_react23.useCallback)(async () => {
|
|
986
989
|
if (subRef.current) await subRef.current.refresh();
|
|
987
990
|
}, []);
|
|
988
|
-
return { boss, active: boss
|
|
991
|
+
return { boss, active: boss !== null, loading, error, refresh };
|
|
989
992
|
}
|
|
990
993
|
|
|
991
994
|
// src/dashboard/usePlayerStats.ts
|
|
992
|
-
var
|
|
995
|
+
var import_react24 = require("react");
|
|
993
996
|
function usePlayerStats(memberId) {
|
|
994
997
|
const client = useDashboardClient();
|
|
995
|
-
const [player, setPlayer] = (0,
|
|
996
|
-
const [loading, setLoading] = (0,
|
|
997
|
-
const [error, setError] = (0,
|
|
998
|
-
const subRef = (0,
|
|
999
|
-
(0,
|
|
998
|
+
const [player, setPlayer] = (0, import_react24.useState)(null);
|
|
999
|
+
const [loading, setLoading] = (0, import_react24.useState)(true);
|
|
1000
|
+
const [error, setError] = (0, import_react24.useState)(null);
|
|
1001
|
+
const subRef = (0, import_react24.useRef)(null);
|
|
1002
|
+
(0, import_react24.useEffect)(() => {
|
|
1000
1003
|
const sub = client.game.subscribePlayer(client.realtime, memberId);
|
|
1001
1004
|
subRef.current = sub;
|
|
1002
1005
|
sub.on("change", (data) => {
|
|
@@ -1013,21 +1016,21 @@ function usePlayerStats(memberId) {
|
|
|
1013
1016
|
subRef.current = null;
|
|
1014
1017
|
};
|
|
1015
1018
|
}, [client, memberId]);
|
|
1016
|
-
const refresh = (0,
|
|
1019
|
+
const refresh = (0, import_react24.useCallback)(async () => {
|
|
1017
1020
|
if (subRef.current) await subRef.current.refresh();
|
|
1018
1021
|
}, []);
|
|
1019
1022
|
return { player, loading, error, refresh };
|
|
1020
1023
|
}
|
|
1021
1024
|
|
|
1022
1025
|
// src/dashboard/useLeaderboard.ts
|
|
1023
|
-
var
|
|
1026
|
+
var import_react25 = require("react");
|
|
1024
1027
|
function useLeaderboard(period) {
|
|
1025
1028
|
const client = useDashboardClient();
|
|
1026
|
-
const [entries, setEntries] = (0,
|
|
1027
|
-
const [loading, setLoading] = (0,
|
|
1028
|
-
const [error, setError] = (0,
|
|
1029
|
-
const subRef = (0,
|
|
1030
|
-
(0,
|
|
1029
|
+
const [entries, setEntries] = (0, import_react25.useState)([]);
|
|
1030
|
+
const [loading, setLoading] = (0, import_react25.useState)(true);
|
|
1031
|
+
const [error, setError] = (0, import_react25.useState)(null);
|
|
1032
|
+
const subRef = (0, import_react25.useRef)(null);
|
|
1033
|
+
(0, import_react25.useEffect)(() => {
|
|
1031
1034
|
const sub = client.game.subscribeLeaderboard(client.realtime, period ? { period } : void 0);
|
|
1032
1035
|
subRef.current = sub;
|
|
1033
1036
|
sub.on("change", (data) => {
|
|
@@ -1044,21 +1047,21 @@ function useLeaderboard(period) {
|
|
|
1044
1047
|
subRef.current = null;
|
|
1045
1048
|
};
|
|
1046
1049
|
}, [client, period]);
|
|
1047
|
-
const refresh = (0,
|
|
1050
|
+
const refresh = (0, import_react25.useCallback)(async () => {
|
|
1048
1051
|
if (subRef.current) await subRef.current.refresh();
|
|
1049
1052
|
}, []);
|
|
1050
1053
|
return { entries, loading, error, refresh };
|
|
1051
1054
|
}
|
|
1052
1055
|
|
|
1053
1056
|
// src/dashboard/useGameActivity.ts
|
|
1054
|
-
var
|
|
1057
|
+
var import_react26 = require("react");
|
|
1055
1058
|
function useGameActivity() {
|
|
1056
1059
|
const client = useDashboardClient();
|
|
1057
|
-
const [events, setEvents] = (0,
|
|
1058
|
-
const [loading, setLoading] = (0,
|
|
1059
|
-
const [error, setError] = (0,
|
|
1060
|
-
const subRef = (0,
|
|
1061
|
-
(0,
|
|
1060
|
+
const [events, setEvents] = (0, import_react26.useState)([]);
|
|
1061
|
+
const [loading, setLoading] = (0, import_react26.useState)(true);
|
|
1062
|
+
const [error, setError] = (0, import_react26.useState)(null);
|
|
1063
|
+
const subRef = (0, import_react26.useRef)(null);
|
|
1064
|
+
(0, import_react26.useEffect)(() => {
|
|
1062
1065
|
const sub = client.game.subscribeActivity(client.realtime);
|
|
1063
1066
|
subRef.current = sub;
|
|
1064
1067
|
sub.on("change", (data) => {
|
|
@@ -1075,7 +1078,7 @@ function useGameActivity() {
|
|
|
1075
1078
|
subRef.current = null;
|
|
1076
1079
|
};
|
|
1077
1080
|
}, [client]);
|
|
1078
|
-
const refresh = (0,
|
|
1081
|
+
const refresh = (0, import_react26.useCallback)(async () => {
|
|
1079
1082
|
if (subRef.current) await subRef.current.refresh();
|
|
1080
1083
|
}, []);
|
|
1081
1084
|
return { events, loading, error, refresh };
|
package/dist/index.d.cts
CHANGED
|
@@ -484,7 +484,7 @@ interface UseBossBattleReturn {
|
|
|
484
484
|
* ```tsx
|
|
485
485
|
* const { boss, active, loading, error } = useBossBattle();
|
|
486
486
|
* if (active) {
|
|
487
|
-
* return <BossHPBar hp={boss.
|
|
487
|
+
* return <BossHPBar hp={boss.currentHealth} max={boss.maxHealth} />;
|
|
488
488
|
* }
|
|
489
489
|
* ```
|
|
490
490
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -484,7 +484,7 @@ interface UseBossBattleReturn {
|
|
|
484
484
|
* ```tsx
|
|
485
485
|
* const { boss, active, loading, error } = useBossBattle();
|
|
486
486
|
* if (active) {
|
|
487
|
-
* return <BossHPBar hp={boss.
|
|
487
|
+
* return <BossHPBar hp={boss.currentHealth} max={boss.maxHealth} />;
|
|
488
488
|
* }
|
|
489
489
|
* ```
|
|
490
490
|
*/
|
package/dist/index.js
CHANGED
|
@@ -411,95 +411,108 @@ function useCategories() {
|
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
// src/library/useArticles.ts
|
|
414
|
-
import { useState as useState6, useEffect as
|
|
414
|
+
import { useState as useState6, useEffect as useEffect8, useCallback as useCallback7 } from "react";
|
|
415
|
+
|
|
416
|
+
// src/useLatestCall.ts
|
|
417
|
+
import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef8 } from "react";
|
|
418
|
+
function useLatestCall() {
|
|
419
|
+
const latest = useRef8(0);
|
|
420
|
+
useEffect7(
|
|
421
|
+
() => () => {
|
|
422
|
+
latest.current += 1;
|
|
423
|
+
},
|
|
424
|
+
[]
|
|
425
|
+
);
|
|
426
|
+
return useCallback6(() => {
|
|
427
|
+
const call = latest.current += 1;
|
|
428
|
+
return () => call === latest.current;
|
|
429
|
+
}, []);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// src/library/useArticles.ts
|
|
415
433
|
function useArticles(params) {
|
|
416
434
|
const client = useLibraryClient();
|
|
417
435
|
const [articles, setArticles] = useState6([]);
|
|
418
436
|
const [isLoading, setIsLoading] = useState6(true);
|
|
419
437
|
const [error, setError] = useState6(null);
|
|
420
|
-
const
|
|
438
|
+
const startCall = useLatestCall();
|
|
421
439
|
const categorySlug = params?.categorySlug;
|
|
422
440
|
const limit = params?.limit;
|
|
423
441
|
const offset = params?.offset;
|
|
424
|
-
const refresh =
|
|
442
|
+
const refresh = useCallback7(async () => {
|
|
443
|
+
const isLatest = startCall();
|
|
425
444
|
setIsLoading(true);
|
|
426
445
|
setError(null);
|
|
427
446
|
try {
|
|
428
447
|
const data = await client.articles({ categorySlug, limit, offset });
|
|
429
|
-
if (
|
|
448
|
+
if (isLatest()) {
|
|
430
449
|
setArticles(data);
|
|
431
450
|
}
|
|
432
451
|
} catch (err) {
|
|
433
|
-
if (
|
|
452
|
+
if (isLatest()) {
|
|
434
453
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
435
454
|
}
|
|
436
455
|
} finally {
|
|
437
|
-
if (
|
|
456
|
+
if (isLatest()) {
|
|
438
457
|
setIsLoading(false);
|
|
439
458
|
}
|
|
440
459
|
}
|
|
441
|
-
}, [client, categorySlug, limit, offset]);
|
|
442
|
-
|
|
443
|
-
mountedRef.current = true;
|
|
460
|
+
}, [client, categorySlug, limit, offset, startCall]);
|
|
461
|
+
useEffect8(() => {
|
|
444
462
|
refresh();
|
|
445
|
-
return () => {
|
|
446
|
-
mountedRef.current = false;
|
|
447
|
-
};
|
|
448
463
|
}, [refresh]);
|
|
449
464
|
return { articles, isLoading, error, refresh };
|
|
450
465
|
}
|
|
451
466
|
|
|
452
467
|
// src/library/useArticle.ts
|
|
453
|
-
import { useState as useState7, useEffect as
|
|
468
|
+
import { useState as useState7, useEffect as useEffect9, useCallback as useCallback8 } from "react";
|
|
454
469
|
function useArticle(slug) {
|
|
455
470
|
const client = useLibraryClient();
|
|
456
471
|
const [article, setArticle] = useState7(null);
|
|
457
472
|
const [isLoading, setIsLoading] = useState7(true);
|
|
458
473
|
const [error, setError] = useState7(null);
|
|
459
|
-
const
|
|
460
|
-
const refresh =
|
|
474
|
+
const startCall = useLatestCall();
|
|
475
|
+
const refresh = useCallback8(async () => {
|
|
461
476
|
if (!slug) return;
|
|
477
|
+
const isLatest = startCall();
|
|
462
478
|
setIsLoading(true);
|
|
463
479
|
setError(null);
|
|
464
480
|
try {
|
|
465
481
|
const data = await client.article(slug);
|
|
466
|
-
if (
|
|
482
|
+
if (isLatest()) {
|
|
467
483
|
setArticle(data);
|
|
468
484
|
}
|
|
469
485
|
} catch (err) {
|
|
470
|
-
if (
|
|
486
|
+
if (isLatest()) {
|
|
471
487
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
472
488
|
}
|
|
473
489
|
} finally {
|
|
474
|
-
if (
|
|
490
|
+
if (isLatest()) {
|
|
475
491
|
setIsLoading(false);
|
|
476
492
|
}
|
|
477
493
|
}
|
|
478
|
-
}, [client, slug]);
|
|
479
|
-
const recordView =
|
|
494
|
+
}, [client, slug, startCall]);
|
|
495
|
+
const recordView = useCallback8(async () => {
|
|
480
496
|
if (!slug) return;
|
|
481
497
|
try {
|
|
482
498
|
await client.recordView(slug);
|
|
483
499
|
} catch {
|
|
484
500
|
}
|
|
485
501
|
}, [client, slug]);
|
|
486
|
-
|
|
487
|
-
mountedRef.current = true;
|
|
502
|
+
useEffect9(() => {
|
|
488
503
|
if (!slug) {
|
|
504
|
+
startCall();
|
|
489
505
|
setArticle(null);
|
|
490
506
|
setIsLoading(false);
|
|
491
507
|
return;
|
|
492
508
|
}
|
|
493
509
|
refresh();
|
|
494
|
-
|
|
495
|
-
mountedRef.current = false;
|
|
496
|
-
};
|
|
497
|
-
}, [slug, refresh]);
|
|
510
|
+
}, [slug, refresh, startCall]);
|
|
498
511
|
return { article, isLoading, error, refresh, recordView };
|
|
499
512
|
}
|
|
500
513
|
|
|
501
514
|
// src/library/useArticleSearch.ts
|
|
502
|
-
import { useState as useState8, useEffect as
|
|
515
|
+
import { useState as useState8, useEffect as useEffect10 } from "react";
|
|
503
516
|
var DEBOUNCE_MS = 300;
|
|
504
517
|
function useArticleSearch(query) {
|
|
505
518
|
const client = useLibraryClient();
|
|
@@ -507,9 +520,8 @@ function useArticleSearch(query) {
|
|
|
507
520
|
const [totalCount, setTotalCount] = useState8(0);
|
|
508
521
|
const [isLoading, setIsLoading] = useState8(false);
|
|
509
522
|
const [error, setError] = useState8(null);
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
mountedRef.current = true;
|
|
523
|
+
useEffect10(() => {
|
|
524
|
+
let cancelled = false;
|
|
513
525
|
const trimmed = query.trim();
|
|
514
526
|
if (!trimmed) {
|
|
515
527
|
setResults([]);
|
|
@@ -522,23 +534,23 @@ function useArticleSearch(query) {
|
|
|
522
534
|
const timer = setTimeout(async () => {
|
|
523
535
|
try {
|
|
524
536
|
const result = await client.search(trimmed);
|
|
525
|
-
if (
|
|
537
|
+
if (!cancelled) {
|
|
526
538
|
setResults(result.data);
|
|
527
539
|
setTotalCount(result.count);
|
|
528
540
|
setError(null);
|
|
529
541
|
}
|
|
530
542
|
} catch (err) {
|
|
531
|
-
if (
|
|
543
|
+
if (!cancelled) {
|
|
532
544
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
533
545
|
}
|
|
534
546
|
} finally {
|
|
535
|
-
if (
|
|
547
|
+
if (!cancelled) {
|
|
536
548
|
setIsLoading(false);
|
|
537
549
|
}
|
|
538
550
|
}
|
|
539
551
|
}, DEBOUNCE_MS);
|
|
540
552
|
return () => {
|
|
541
|
-
|
|
553
|
+
cancelled = true;
|
|
542
554
|
clearTimeout(timer);
|
|
543
555
|
};
|
|
544
556
|
}, [client, query]);
|
|
@@ -546,11 +558,11 @@ function useArticleSearch(query) {
|
|
|
546
558
|
}
|
|
547
559
|
|
|
548
560
|
// src/community/CStarCommunityProvider.tsx
|
|
549
|
-
import { useRef as
|
|
561
|
+
import { useRef as useRef9 } from "react";
|
|
550
562
|
import { CommunityClient } from "@cstar.help/js/community";
|
|
551
563
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
552
564
|
function CStarCommunityProvider({ children, ...config }) {
|
|
553
|
-
const clientRef =
|
|
565
|
+
const clientRef = useRef9(null);
|
|
554
566
|
if (!clientRef.current) {
|
|
555
567
|
clientRef.current = new CommunityClient(config);
|
|
556
568
|
}
|
|
@@ -558,14 +570,14 @@ function CStarCommunityProvider({ children, ...config }) {
|
|
|
558
570
|
}
|
|
559
571
|
|
|
560
572
|
// src/community/useTopics.ts
|
|
561
|
-
import { useState as useState9, useEffect as
|
|
573
|
+
import { useState as useState9, useEffect as useEffect11, useCallback as useCallback9, useRef as useRef10 } from "react";
|
|
562
574
|
function useTopics() {
|
|
563
575
|
const client = useCommunityClient();
|
|
564
576
|
const [topics, setTopics] = useState9([]);
|
|
565
577
|
const [isLoading, setIsLoading] = useState9(true);
|
|
566
578
|
const [error, setError] = useState9(null);
|
|
567
|
-
const mountedRef =
|
|
568
|
-
const refresh =
|
|
579
|
+
const mountedRef = useRef10(true);
|
|
580
|
+
const refresh = useCallback9(async () => {
|
|
569
581
|
setIsLoading(true);
|
|
570
582
|
setError(null);
|
|
571
583
|
try {
|
|
@@ -583,7 +595,7 @@ function useTopics() {
|
|
|
583
595
|
}
|
|
584
596
|
}
|
|
585
597
|
}, [client]);
|
|
586
|
-
|
|
598
|
+
useEffect11(() => {
|
|
587
599
|
mountedRef.current = true;
|
|
588
600
|
refresh();
|
|
589
601
|
return () => {
|
|
@@ -594,122 +606,112 @@ function useTopics() {
|
|
|
594
606
|
}
|
|
595
607
|
|
|
596
608
|
// src/community/usePosts.ts
|
|
597
|
-
import { useState as useState10, useEffect as
|
|
609
|
+
import { useState as useState10, useEffect as useEffect12, useCallback as useCallback10 } from "react";
|
|
598
610
|
function usePosts(params) {
|
|
599
611
|
const client = useCommunityClient();
|
|
600
612
|
const [posts, setPosts] = useState10([]);
|
|
601
613
|
const [count, setCount] = useState10(0);
|
|
602
614
|
const [isLoading, setIsLoading] = useState10(true);
|
|
603
615
|
const [error, setError] = useState10(null);
|
|
604
|
-
const
|
|
616
|
+
const startCall = useLatestCall();
|
|
605
617
|
const topicSlug = params?.topicSlug;
|
|
606
618
|
const status = params?.status;
|
|
607
619
|
const sort = params?.sort;
|
|
608
620
|
const limit = params?.limit;
|
|
609
621
|
const offset = params?.offset;
|
|
610
|
-
const refresh =
|
|
622
|
+
const refresh = useCallback10(async () => {
|
|
623
|
+
const isLatest = startCall();
|
|
611
624
|
setIsLoading(true);
|
|
612
625
|
setError(null);
|
|
613
626
|
try {
|
|
614
627
|
const result = await client.posts({ topicSlug, status, sort, limit, offset });
|
|
615
|
-
if (
|
|
628
|
+
if (isLatest()) {
|
|
616
629
|
setPosts(result.posts);
|
|
617
630
|
setCount(result.count);
|
|
618
631
|
}
|
|
619
632
|
} catch (err) {
|
|
620
|
-
if (
|
|
633
|
+
if (isLatest()) {
|
|
621
634
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
622
635
|
}
|
|
623
636
|
} finally {
|
|
624
|
-
if (
|
|
637
|
+
if (isLatest()) {
|
|
625
638
|
setIsLoading(false);
|
|
626
639
|
}
|
|
627
640
|
}
|
|
628
|
-
}, [client, topicSlug, status, sort, limit, offset]);
|
|
629
|
-
|
|
630
|
-
mountedRef.current = true;
|
|
641
|
+
}, [client, topicSlug, status, sort, limit, offset, startCall]);
|
|
642
|
+
useEffect12(() => {
|
|
631
643
|
refresh();
|
|
632
|
-
return () => {
|
|
633
|
-
mountedRef.current = false;
|
|
634
|
-
};
|
|
635
644
|
}, [refresh]);
|
|
636
645
|
return { posts, count, isLoading, error, refresh };
|
|
637
646
|
}
|
|
638
647
|
|
|
639
648
|
// src/community/usePost.ts
|
|
640
|
-
import { useState as useState11, useEffect as
|
|
649
|
+
import { useState as useState11, useEffect as useEffect13, useCallback as useCallback11 } from "react";
|
|
641
650
|
function usePost(slug) {
|
|
642
651
|
const client = useCommunityClient();
|
|
643
652
|
const [data, setData] = useState11(null);
|
|
644
653
|
const [isLoading, setIsLoading] = useState11(true);
|
|
645
654
|
const [error, setError] = useState11(null);
|
|
646
|
-
const
|
|
647
|
-
const refresh =
|
|
655
|
+
const startCall = useLatestCall();
|
|
656
|
+
const refresh = useCallback11(async () => {
|
|
657
|
+
const isLatest = startCall();
|
|
648
658
|
setIsLoading(true);
|
|
649
659
|
setError(null);
|
|
650
660
|
try {
|
|
651
661
|
const result = await client.post(slug);
|
|
652
|
-
if (
|
|
662
|
+
if (isLatest()) {
|
|
653
663
|
setData(result);
|
|
654
664
|
}
|
|
655
665
|
} catch (err) {
|
|
656
|
-
if (
|
|
666
|
+
if (isLatest()) {
|
|
657
667
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
658
668
|
}
|
|
659
669
|
} finally {
|
|
660
|
-
if (
|
|
670
|
+
if (isLatest()) {
|
|
661
671
|
setIsLoading(false);
|
|
662
672
|
}
|
|
663
673
|
}
|
|
664
|
-
}, [client, slug]);
|
|
665
|
-
|
|
666
|
-
mountedRef.current = true;
|
|
674
|
+
}, [client, slug, startCall]);
|
|
675
|
+
useEffect13(() => {
|
|
667
676
|
refresh();
|
|
668
|
-
return () => {
|
|
669
|
-
mountedRef.current = false;
|
|
670
|
-
};
|
|
671
677
|
}, [refresh]);
|
|
672
678
|
return { data, isLoading, error, refresh };
|
|
673
679
|
}
|
|
674
680
|
|
|
675
681
|
// src/community/useCommunitySearch.ts
|
|
676
|
-
import { useState as useState12,
|
|
682
|
+
import { useState as useState12, useCallback as useCallback12 } from "react";
|
|
677
683
|
function useCommunitySearch() {
|
|
678
684
|
const client = useCommunityClient();
|
|
679
685
|
const [results, setResults] = useState12(null);
|
|
680
686
|
const [isLoading, setIsLoading] = useState12(false);
|
|
681
687
|
const [error, setError] = useState12(null);
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
mountedRef.current = true;
|
|
685
|
-
return () => {
|
|
686
|
-
mountedRef.current = false;
|
|
687
|
-
};
|
|
688
|
-
}, []);
|
|
689
|
-
const search = useCallback11(
|
|
688
|
+
const startCall = useLatestCall();
|
|
689
|
+
const search = useCallback12(
|
|
690
690
|
async (query) => {
|
|
691
|
+
const isLatest = startCall();
|
|
691
692
|
if (!query.trim()) {
|
|
692
693
|
setResults(null);
|
|
694
|
+
setIsLoading(false);
|
|
693
695
|
return;
|
|
694
696
|
}
|
|
695
697
|
setIsLoading(true);
|
|
696
698
|
setError(null);
|
|
697
699
|
try {
|
|
698
700
|
const data = await client.search(query);
|
|
699
|
-
if (
|
|
701
|
+
if (isLatest()) {
|
|
700
702
|
setResults(data);
|
|
701
703
|
}
|
|
702
704
|
} catch (err) {
|
|
703
|
-
if (
|
|
705
|
+
if (isLatest()) {
|
|
704
706
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
705
707
|
}
|
|
706
708
|
} finally {
|
|
707
|
-
if (
|
|
709
|
+
if (isLatest()) {
|
|
708
710
|
setIsLoading(false);
|
|
709
711
|
}
|
|
710
712
|
}
|
|
711
713
|
},
|
|
712
|
-
[client]
|
|
714
|
+
[client, startCall]
|
|
713
715
|
);
|
|
714
716
|
return { results, isLoading, error, search };
|
|
715
717
|
}
|
|
@@ -754,7 +756,7 @@ function useDashboardClient() {
|
|
|
754
756
|
}
|
|
755
757
|
|
|
756
758
|
// src/dashboard/useCStarQuery.ts
|
|
757
|
-
import { useState as useState13, useEffect as useEffect14, useRef as
|
|
759
|
+
import { useState as useState13, useEffect as useEffect14, useRef as useRef11, useCallback as useCallback13 } from "react";
|
|
758
760
|
import { CStarValidationError } from "@cstar.help/js";
|
|
759
761
|
function resolveResource(client, path) {
|
|
760
762
|
const parts = path.split(".");
|
|
@@ -776,7 +778,7 @@ function useCStarQuery(resource, params) {
|
|
|
776
778
|
const [data, setData] = useState13(null);
|
|
777
779
|
const [loading, setLoading] = useState13(true);
|
|
778
780
|
const [error, setError] = useState13(null);
|
|
779
|
-
const subscriptionRef =
|
|
781
|
+
const subscriptionRef = useRef11(null);
|
|
780
782
|
const paramsKey = params ? JSON.stringify(params) : "";
|
|
781
783
|
useEffect14(() => {
|
|
782
784
|
const resolved = resolveResource(client, resource);
|
|
@@ -801,7 +803,7 @@ function useCStarQuery(resource, params) {
|
|
|
801
803
|
subscriptionRef.current = null;
|
|
802
804
|
};
|
|
803
805
|
}, [client, resource, paramsKey]);
|
|
804
|
-
const refresh =
|
|
806
|
+
const refresh = useCallback13(async () => {
|
|
805
807
|
if (subscriptionRef.current) {
|
|
806
808
|
await subscriptionRef.current.refresh();
|
|
807
809
|
}
|
|
@@ -810,37 +812,38 @@ function useCStarQuery(resource, params) {
|
|
|
810
812
|
}
|
|
811
813
|
|
|
812
814
|
// src/dashboard/useCStarMutation.ts
|
|
813
|
-
import { useState as useState14, useCallback as
|
|
815
|
+
import { useState as useState14, useCallback as useCallback14 } from "react";
|
|
814
816
|
function resolveMutation(client, path) {
|
|
815
817
|
const parts = path.split(".");
|
|
816
818
|
if (parts.length < 2) return null;
|
|
817
|
-
const
|
|
818
|
-
const methodName =
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
if (typeof method !== "function") return null;
|
|
824
|
-
if (methodName === "update") {
|
|
825
|
-
return (params) => {
|
|
826
|
-
const p = params;
|
|
827
|
-
const { id, ...rest } = p;
|
|
828
|
-
return method.call(resource, id, rest);
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
if (methodName === "del" || methodName === "delete") {
|
|
832
|
-
return (params) => {
|
|
833
|
-
const p = params;
|
|
834
|
-
return method.call(resource, p.id);
|
|
835
|
-
};
|
|
819
|
+
const last = parts[parts.length - 1];
|
|
820
|
+
const methodName = last === "delete" ? "del" : last;
|
|
821
|
+
let resource = client;
|
|
822
|
+
for (const part of parts.slice(0, -1)) {
|
|
823
|
+
resource = resource?.[part];
|
|
824
|
+
if (!resource || typeof resource !== "object") return null;
|
|
836
825
|
}
|
|
837
|
-
|
|
826
|
+
const method = resource[methodName];
|
|
827
|
+
if (typeof method !== "function") return null;
|
|
828
|
+
const call = method;
|
|
829
|
+
const needsId = methodName === "del" || methodName === "update" && call.length >= 2;
|
|
830
|
+
return (params) => {
|
|
831
|
+
if (Array.isArray(params)) return call.apply(resource, params);
|
|
832
|
+
const { id, ...rest } = params ?? {};
|
|
833
|
+
if (typeof id === "string" && id) {
|
|
834
|
+
return Object.keys(rest).length > 0 ? call.call(resource, id, rest) : call.call(resource, id);
|
|
835
|
+
}
|
|
836
|
+
if (needsId) {
|
|
837
|
+
return Promise.reject(new Error(`Missing or invalid "id" for ${methodName} operation`));
|
|
838
|
+
}
|
|
839
|
+
return call.call(resource, params);
|
|
840
|
+
};
|
|
838
841
|
}
|
|
839
842
|
function useCStarMutation(resource) {
|
|
840
843
|
const client = useDashboardClient();
|
|
841
844
|
const [loading, setLoading] = useState14(false);
|
|
842
845
|
const [error, setError] = useState14(null);
|
|
843
|
-
const mutate =
|
|
846
|
+
const mutate = useCallback14(
|
|
844
847
|
async (params) => {
|
|
845
848
|
const fn = resolveMutation(client, resource);
|
|
846
849
|
if (!fn) {
|
|
@@ -904,13 +907,13 @@ function useCStarEvents(types) {
|
|
|
904
907
|
}
|
|
905
908
|
|
|
906
909
|
// src/dashboard/useBossBattle.ts
|
|
907
|
-
import { useState as useState16, useEffect as useEffect16, useRef as
|
|
910
|
+
import { useState as useState16, useEffect as useEffect16, useRef as useRef12, useCallback as useCallback15 } from "react";
|
|
908
911
|
function useBossBattle() {
|
|
909
912
|
const client = useDashboardClient();
|
|
910
913
|
const [boss, setBoss] = useState16(null);
|
|
911
914
|
const [loading, setLoading] = useState16(true);
|
|
912
915
|
const [error, setError] = useState16(null);
|
|
913
|
-
const subRef =
|
|
916
|
+
const subRef = useRef12(null);
|
|
914
917
|
useEffect16(() => {
|
|
915
918
|
const sub = client.game.subscribeBoss(client.realtime);
|
|
916
919
|
subRef.current = sub;
|
|
@@ -928,20 +931,20 @@ function useBossBattle() {
|
|
|
928
931
|
subRef.current = null;
|
|
929
932
|
};
|
|
930
933
|
}, [client]);
|
|
931
|
-
const refresh =
|
|
934
|
+
const refresh = useCallback15(async () => {
|
|
932
935
|
if (subRef.current) await subRef.current.refresh();
|
|
933
936
|
}, []);
|
|
934
|
-
return { boss, active: boss
|
|
937
|
+
return { boss, active: boss !== null, loading, error, refresh };
|
|
935
938
|
}
|
|
936
939
|
|
|
937
940
|
// src/dashboard/usePlayerStats.ts
|
|
938
|
-
import { useState as useState17, useEffect as useEffect17, useRef as
|
|
941
|
+
import { useState as useState17, useEffect as useEffect17, useRef as useRef13, useCallback as useCallback16 } from "react";
|
|
939
942
|
function usePlayerStats(memberId) {
|
|
940
943
|
const client = useDashboardClient();
|
|
941
944
|
const [player, setPlayer] = useState17(null);
|
|
942
945
|
const [loading, setLoading] = useState17(true);
|
|
943
946
|
const [error, setError] = useState17(null);
|
|
944
|
-
const subRef =
|
|
947
|
+
const subRef = useRef13(null);
|
|
945
948
|
useEffect17(() => {
|
|
946
949
|
const sub = client.game.subscribePlayer(client.realtime, memberId);
|
|
947
950
|
subRef.current = sub;
|
|
@@ -959,20 +962,20 @@ function usePlayerStats(memberId) {
|
|
|
959
962
|
subRef.current = null;
|
|
960
963
|
};
|
|
961
964
|
}, [client, memberId]);
|
|
962
|
-
const refresh =
|
|
965
|
+
const refresh = useCallback16(async () => {
|
|
963
966
|
if (subRef.current) await subRef.current.refresh();
|
|
964
967
|
}, []);
|
|
965
968
|
return { player, loading, error, refresh };
|
|
966
969
|
}
|
|
967
970
|
|
|
968
971
|
// src/dashboard/useLeaderboard.ts
|
|
969
|
-
import { useState as useState18, useEffect as useEffect18, useRef as
|
|
972
|
+
import { useState as useState18, useEffect as useEffect18, useRef as useRef14, useCallback as useCallback17 } from "react";
|
|
970
973
|
function useLeaderboard(period) {
|
|
971
974
|
const client = useDashboardClient();
|
|
972
975
|
const [entries, setEntries] = useState18([]);
|
|
973
976
|
const [loading, setLoading] = useState18(true);
|
|
974
977
|
const [error, setError] = useState18(null);
|
|
975
|
-
const subRef =
|
|
978
|
+
const subRef = useRef14(null);
|
|
976
979
|
useEffect18(() => {
|
|
977
980
|
const sub = client.game.subscribeLeaderboard(client.realtime, period ? { period } : void 0);
|
|
978
981
|
subRef.current = sub;
|
|
@@ -990,20 +993,20 @@ function useLeaderboard(period) {
|
|
|
990
993
|
subRef.current = null;
|
|
991
994
|
};
|
|
992
995
|
}, [client, period]);
|
|
993
|
-
const refresh =
|
|
996
|
+
const refresh = useCallback17(async () => {
|
|
994
997
|
if (subRef.current) await subRef.current.refresh();
|
|
995
998
|
}, []);
|
|
996
999
|
return { entries, loading, error, refresh };
|
|
997
1000
|
}
|
|
998
1001
|
|
|
999
1002
|
// src/dashboard/useGameActivity.ts
|
|
1000
|
-
import { useState as useState19, useEffect as useEffect19, useRef as
|
|
1003
|
+
import { useState as useState19, useEffect as useEffect19, useRef as useRef15, useCallback as useCallback18 } from "react";
|
|
1001
1004
|
function useGameActivity() {
|
|
1002
1005
|
const client = useDashboardClient();
|
|
1003
1006
|
const [events, setEvents] = useState19([]);
|
|
1004
1007
|
const [loading, setLoading] = useState19(true);
|
|
1005
1008
|
const [error, setError] = useState19(null);
|
|
1006
|
-
const subRef =
|
|
1009
|
+
const subRef = useRef15(null);
|
|
1007
1010
|
useEffect19(() => {
|
|
1008
1011
|
const sub = client.game.subscribeActivity(client.realtime);
|
|
1009
1012
|
subRef.current = sub;
|
|
@@ -1021,7 +1024,7 @@ function useGameActivity() {
|
|
|
1021
1024
|
subRef.current = null;
|
|
1022
1025
|
};
|
|
1023
1026
|
}, [client]);
|
|
1024
|
-
const refresh =
|
|
1027
|
+
const refresh = useCallback18(async () => {
|
|
1025
1028
|
if (subRef.current) await subRef.current.refresh();
|
|
1026
1029
|
}, []);
|
|
1027
1030
|
return { events, loading, error, refresh };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cstar.help/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "React hooks for the cStar customer support platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"react": ">=18.0.0",
|
|
33
|
-
"@cstar.help/js": "^0.
|
|
33
|
+
"@cstar.help/js": "^0.19.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"react": "^18.3.1",
|
|
37
37
|
"react-dom": "^18.3.1",
|
|
38
|
-
"@cstar.help/js": "^0.
|
|
38
|
+
"@cstar.help/js": "^0.19.0",
|
|
39
39
|
"@testing-library/react": "^16.1.0",
|
|
40
40
|
"@types/react": "^18.3.0",
|
|
41
41
|
"@types/react-dom": "^18.3.0",
|