convex-feedback-ui 0.1.8 → 0.2.0-beta.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.
Files changed (137) hide show
  1. package/README.md +30 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/native/expo/ExpoFeedbackBody.d.ts +1 -1
  4. package/dist/native/expo/ExpoFeedbackBody.d.ts.map +1 -1
  5. package/dist/native/expo/ExpoFeedbackBody.js +2 -2
  6. package/dist/native/expo/ExpoFeedbackBody.js.map +1 -1
  7. package/dist/native/expo/FeedbackRoutes.d.ts.map +1 -1
  8. package/dist/native/expo/FeedbackRoutes.js +17 -9
  9. package/dist/native/expo/FeedbackRoutes.js.map +1 -1
  10. package/dist/native/expo/FeedbackScreen.d.ts +1 -1
  11. package/dist/native/expo/FeedbackScreen.d.ts.map +1 -1
  12. package/dist/native/expo/FeedbackScreen.js +2 -2
  13. package/dist/native/expo/FeedbackScreen.js.map +1 -1
  14. package/dist/native/expo/FeedbackStack.d.ts +1 -1
  15. package/dist/native/expo/FeedbackStack.d.ts.map +1 -1
  16. package/dist/native/expo/FeedbackStack.js +15 -8
  17. package/dist/native/expo/FeedbackStack.js.map +1 -1
  18. package/dist/native/expo/FeedbackStackLayout.d.ts +1 -1
  19. package/dist/native/expo/FeedbackStackLayout.d.ts.map +1 -1
  20. package/dist/native/expo/FeedbackStackLayout.js +7 -2
  21. package/dist/native/expo/FeedbackStackLayout.js.map +1 -1
  22. package/dist/native/expo/index.d.ts +1 -0
  23. package/dist/native/expo/index.d.ts.map +1 -1
  24. package/dist/native/expo/index.js +1 -0
  25. package/dist/native/expo/index.js.map +1 -1
  26. package/dist/native/expo/types.d.ts +13 -0
  27. package/dist/native/expo/types.d.ts.map +1 -1
  28. package/dist/native/native/FeedbackScreen.d.ts +1 -1
  29. package/dist/native/native/FeedbackScreen.d.ts.map +1 -1
  30. package/dist/native/native/FeedbackScreen.js +2 -2
  31. package/dist/native/native/FeedbackScreen.js.map +1 -1
  32. package/dist/native/native/index.d.ts +1 -0
  33. package/dist/native/native/index.d.ts.map +1 -1
  34. package/dist/native/native/index.js +1 -0
  35. package/dist/native/native/index.js.map +1 -1
  36. package/dist/native/shared/helpers.d.ts +6 -1
  37. package/dist/native/shared/helpers.d.ts.map +1 -1
  38. package/dist/native/shared/helpers.js +33 -0
  39. package/dist/native/shared/helpers.js.map +1 -1
  40. package/dist/native/shared/ui/BodyContent.d.ts.map +1 -1
  41. package/dist/native/shared/ui/BodyContent.js +8 -2
  42. package/dist/native/shared/ui/BodyContent.js.map +1 -1
  43. package/dist/native/shared/ui/Button.d.ts +2 -1
  44. package/dist/native/shared/ui/Button.d.ts.map +1 -1
  45. package/dist/native/shared/ui/Button.js +3 -2
  46. package/dist/native/shared/ui/Button.js.map +1 -1
  47. package/dist/native/shared/ui/CommentBranch.d.ts.map +1 -1
  48. package/dist/native/shared/ui/CommentBranch.js +33 -11
  49. package/dist/native/shared/ui/CommentBranch.js.map +1 -1
  50. package/dist/native/shared/ui/EntryCard.d.ts.map +1 -1
  51. package/dist/native/shared/ui/EntryCard.js +13 -1
  52. package/dist/native/shared/ui/EntryCard.js.map +1 -1
  53. package/dist/native/shared/ui/EntryDetail.d.ts.map +1 -1
  54. package/dist/native/shared/ui/EntryDetail.js +23 -5
  55. package/dist/native/shared/ui/EntryDetail.js.map +1 -1
  56. package/dist/native/shared/ui/FeedbackScreenHeader.d.ts.map +1 -1
  57. package/dist/native/shared/ui/FeedbackScreenHeader.js +7 -2
  58. package/dist/native/shared/ui/FeedbackScreenHeader.js.map +1 -1
  59. package/dist/native/shared/ui/FeedbackScreenList.d.ts.map +1 -1
  60. package/dist/native/shared/ui/FeedbackScreenList.js +16 -8
  61. package/dist/native/shared/ui/FeedbackScreenList.js.map +1 -1
  62. package/dist/native/shared/ui/NewEntry.d.ts.map +1 -1
  63. package/dist/native/shared/ui/NewEntry.js +13 -11
  64. package/dist/native/shared/ui/NewEntry.js.map +1 -1
  65. package/dist/native/shared/ui/RoadmapScreen.d.ts +3 -0
  66. package/dist/native/shared/ui/RoadmapScreen.d.ts.map +1 -0
  67. package/dist/native/shared/ui/RoadmapScreen.js +73 -0
  68. package/dist/native/shared/ui/RoadmapScreen.js.map +1 -0
  69. package/dist/react/action.d.ts +14 -0
  70. package/dist/react/action.d.ts.map +1 -0
  71. package/dist/react/action.js +38 -0
  72. package/dist/react/action.js.map +1 -0
  73. package/dist/react/index.d.ts +1 -0
  74. package/dist/react/index.d.ts.map +1 -1
  75. package/dist/react/index.js +1 -0
  76. package/dist/react/index.js.map +1 -1
  77. package/dist/react/roadmap.d.ts +3 -0
  78. package/dist/react/roadmap.d.ts.map +1 -0
  79. package/dist/react/roadmap.js +59 -0
  80. package/dist/react/roadmap.js.map +1 -0
  81. package/dist/react/screen.d.ts +1 -1
  82. package/dist/react/screen.d.ts.map +1 -1
  83. package/dist/react/screen.js +99 -42
  84. package/dist/react/screen.js.map +1 -1
  85. package/dist/react/styles.css +42 -0
  86. package/dist/shared/context/FeedbackBodyProvider.d.ts +1 -1
  87. package/dist/shared/context/FeedbackBodyProvider.d.ts.map +1 -1
  88. package/dist/shared/context/FeedbackBodyProvider.js +8 -2
  89. package/dist/shared/context/FeedbackBodyProvider.js.map +1 -1
  90. package/dist/shared/helpers.d.ts +6 -0
  91. package/dist/shared/helpers.d.ts.map +1 -1
  92. package/dist/shared/helpers.js +12 -0
  93. package/dist/shared/helpers.js.map +1 -1
  94. package/dist/shared/types/index.d.ts +1 -0
  95. package/dist/shared/types/index.d.ts.map +1 -1
  96. package/dist/shared/types/messages.d.ts +1 -1
  97. package/dist/shared/types/messages.d.ts.map +1 -1
  98. package/dist/shared/types/roadmap.d.ts +17 -0
  99. package/dist/shared/types/roadmap.d.ts.map +1 -0
  100. package/dist/shared/types/roadmap.js +2 -0
  101. package/dist/shared/types/roadmap.js.map +1 -0
  102. package/dist/shared/types/screen.d.ts +10 -1
  103. package/dist/shared/types/screen.d.ts.map +1 -1
  104. package/package.json +2 -2
  105. package/src/native/expo/ExpoFeedbackBody.tsx +2 -0
  106. package/src/native/expo/FeedbackRoutes.tsx +54 -30
  107. package/src/native/expo/FeedbackScreen.tsx +2 -0
  108. package/src/native/expo/FeedbackStack.tsx +46 -27
  109. package/src/native/expo/FeedbackStackLayout.tsx +11 -1
  110. package/src/native/expo/README.md +15 -0
  111. package/src/native/expo/index.ts +1 -0
  112. package/src/native/expo/types.ts +12 -0
  113. package/src/native/native/FeedbackScreen.tsx +2 -0
  114. package/src/native/native/README.md +4 -0
  115. package/src/native/native/index.ts +1 -0
  116. package/src/native/shared/helpers.ts +38 -1
  117. package/src/native/shared/ui/BodyContent.tsx +15 -2
  118. package/src/native/shared/ui/Button.tsx +4 -0
  119. package/src/native/shared/ui/CommentBranch.tsx +58 -15
  120. package/src/native/shared/ui/EntryCard.tsx +21 -3
  121. package/src/native/shared/ui/EntryDetail.tsx +42 -8
  122. package/src/native/shared/ui/FeedbackScreenHeader.tsx +9 -1
  123. package/src/native/shared/ui/FeedbackScreenList.tsx +28 -13
  124. package/src/native/shared/ui/NewEntry.tsx +25 -12
  125. package/src/native/shared/ui/RoadmapScreen.tsx +345 -0
  126. package/src/react/README.md +1 -1
  127. package/src/react/action.tsx +56 -0
  128. package/src/react/index.ts +1 -0
  129. package/src/react/roadmap.tsx +303 -0
  130. package/src/react/screen.tsx +199 -75
  131. package/src/react/styles.css +42 -0
  132. package/src/shared/context/FeedbackBodyProvider.tsx +9 -1
  133. package/src/shared/helpers.ts +16 -0
  134. package/src/shared/types/index.ts +1 -0
  135. package/src/shared/types/messages.ts +1 -1
  136. package/src/shared/types/roadmap.ts +25 -0
  137. package/src/shared/types/screen.ts +12 -1
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { Pressable, ScrollView, Text, View } from "react-native";
4
+ import { FeedbackProvider, useFeedbackUi, } from "../../../shared/context/FeedbackProvider.js";
5
+ import { allowAuthenticatedAction } from "../../../shared/helpers.js";
6
+ import { useNativeAction } from "../helpers.js";
7
+ import { Button } from "./Button.js";
8
+ import { FeedbackBoard, FeedbackEntry } from "./primitives.js";
9
+ export function RoadmapScreen({ hooks, messages, theme, unstyled, onEntryOpen, onUnauthenticated, pageSize, entryPageSize, ...colors }) {
10
+ return (_jsx(FeedbackProvider, { messages: messages, theme: theme, unstyled: unstyled, children: _jsx(RoadmapScreenInner, { hooks: hooks, onEntryOpen: onEntryOpen, onUnauthenticated: onUnauthenticated, pageSize: pageSize ?? hooks.pageSizes.roadmap, entryPageSize: entryPageSize ?? hooks.pageSizes.entries, ...colors }) }));
11
+ }
12
+ function RoadmapScreenInner({ hooks, onEntryOpen, onUnauthenticated, pageSize, entryPageSize, ...colors }) {
13
+ const { messages, theme } = useFeedbackUi();
14
+ const [query, setQuery] = useState("");
15
+ const [selectedId, setSelectedId] = useState(null);
16
+ const roadmap = hooks.useRoadmap();
17
+ const search = hooks.useSearchRoadmap(query);
18
+ const searching = query.trim().length > 0;
19
+ const items = searching ? (search ?? []) : roadmap.results;
20
+ const selected = items.find((item) => item.id === selectedId) ?? null;
21
+ if (selected !== null) {
22
+ return (_jsx(FeedbackBoard.Root, { ...colors, children: _jsx(ScrollView, { contentContainerStyle: { gap: theme.spacing, padding: theme.spacing }, children: _jsx(RoadmapDetail, { item: selected, hooks: hooks, entryPageSize: entryPageSize, onEntryOpen: onEntryOpen, onUnauthenticated: onUnauthenticated, onBack: () => setSelectedId(null) }) }) }));
23
+ }
24
+ const loading = searching
25
+ ? search === undefined
26
+ : roadmap.status === "LoadingFirstPage";
27
+ return (_jsxs(FeedbackBoard.Root, { ...colors, children: [_jsxs(FeedbackBoard.Header, { style: { gap: theme.spacing, padding: theme.spacing }, children: [_jsx(FeedbackBoard.Title, { children: "Roadmap" }), _jsx(Text, { style: { color: theme.colors.mutedText }, children: "See what is planned, in progress, and shipped." }), _jsx(FeedbackBoard.Search, { value: query, onValueChange: setQuery, placeholder: "Search roadmap" })] }), loading ? (_jsx(FeedbackBoard.State, { children: _jsx(Text, { style: { color: theme.colors.mutedText }, children: messages.board.loading }) })) : items.length === 0 ? (_jsx(FeedbackBoard.State, { children: _jsx(Text, { style: { color: theme.colors.mutedText }, children: searching ? "No roadmap items found." : "No roadmap items yet." }) })) : (_jsx(FeedbackBoard.List, { contentContainerStyle: { padding: theme.spacing }, children: items.map((item) => (_jsx(RoadmapCard, { item: item, onOpen: () => setSelectedId(item.id) }, item.id))) })), !searching &&
28
+ (roadmap.status === "CanLoadMore" ||
29
+ roadmap.status === "LoadingMore") && (_jsx(Button, { label: messages.board.loadMore, disabled: roadmap.status === "LoadingMore", onPress: () => roadmap.loadMore(pageSize) }))] }));
30
+ }
31
+ function RoadmapCard({ item, onOpen, }) {
32
+ const { theme } = useFeedbackUi();
33
+ return (_jsxs(Pressable, { onPress: onOpen, style: { gap: 5, padding: 12 }, children: [_jsxs(View, { style: {
34
+ flexDirection: "row",
35
+ justifyContent: "space-between",
36
+ gap: 8,
37
+ }, children: [_jsx(Text, { style: {
38
+ color: theme.colors.mutedText,
39
+ fontSize: 12,
40
+ fontWeight: "600",
41
+ }, children: item.status.replaceAll("_", " ") }), _jsxs(Text, { style: { color: theme.colors.mutedText, fontSize: 12 }, children: [item.feedbackCount, " linked"] })] }), _jsx(Text, { style: { color: theme.colors.text, fontSize: 16, fontWeight: "700" }, children: item.title }), item.description && (_jsx(Text, { style: { color: theme.colors.mutedText, lineHeight: 20 }, children: item.description }))] }));
42
+ }
43
+ function RoadmapDetail({ item, hooks, entryPageSize, onEntryOpen, onUnauthenticated, onBack, }) {
44
+ const { messages, theme } = useFeedbackUi();
45
+ const feedback = hooks.useRoadmapFeedback(item.id);
46
+ return (_jsxs(View, { style: { gap: theme.spacing }, children: [_jsx(Button, { label: messages.entry.back, onPress: onBack }), _jsxs(View, { style: { gap: 6 }, children: [_jsxs(Text, { style: {
47
+ color: theme.colors.mutedText,
48
+ fontSize: 12,
49
+ fontWeight: "600",
50
+ }, children: [item.status.replaceAll("_", " "), " \u00B7 Position ", item.position] }), _jsx(Text, { style: { color: theme.colors.text, fontSize: 23, fontWeight: "700" }, children: item.title }), _jsx(Text, { style: { color: theme.colors.mutedText, lineHeight: 21 }, children: item.description ?? "No description." })] }), _jsxs(View, { style: { gap: 4 }, children: [_jsx(RoadmapField, { label: "ID", value: item.id }), _jsx(RoadmapField, { label: "Linked feedback", value: String(item.feedbackCount) }), _jsx(RoadmapField, { label: "Created", value: new Date(item.createdAt).toLocaleString() }), _jsx(RoadmapField, { label: "Updated", value: new Date(item.updatedAt).toLocaleString() }), _jsx(RoadmapField, { label: "Document created", value: new Date(item.creationTime).toLocaleString() })] }), _jsx(Text, { style: { color: theme.colors.text, fontSize: 18, fontWeight: "700" }, children: "Attached feedback" }), feedback.status === "LoadingFirstPage" ? (_jsx(Text, { style: { color: theme.colors.mutedText }, children: messages.board.loading })) : feedback.results.length === 0 ? (_jsx(Text, { style: { color: theme.colors.mutedText }, children: "No feedback attached." })) : (_jsx(View, { style: { gap: 8 }, children: feedback.results.map((entry) => (_jsx(RoadmapEntry, { entry: entry, hooks: hooks, onOpen: onEntryOpen, onUnauthenticated: onUnauthenticated }, entry.id))) })), (feedback.status === "CanLoadMore" ||
51
+ feedback.status === "LoadingMore") && (_jsx(Button, { label: messages.comments.loadMore, disabled: feedback.status === "LoadingMore", onPress: () => feedback.loadMore(entryPageSize) }))] }));
52
+ }
53
+ function RoadmapField({ label, value }) {
54
+ const { theme } = useFeedbackUi();
55
+ return (_jsxs(View, { style: { flexDirection: "row", gap: 8 }, children: [_jsxs(Text, { style: { color: theme.colors.mutedText, fontWeight: "600" }, children: [label, ":"] }), _jsx(Text, { style: { flex: 1, color: theme.colors.text }, children: value })] }));
56
+ }
57
+ function RoadmapEntry({ entry, hooks, onOpen, onUnauthenticated, }) {
58
+ const { isAuthenticated } = useFeedbackAuth(hooks);
59
+ const setUpvote = hooks.useSetEntryUpvote();
60
+ const action = useNativeAction();
61
+ const toggle = (desiredState) => {
62
+ if (!allowAuthenticatedAction(isAuthenticated, onUnauthenticated) ||
63
+ action.pending) {
64
+ return;
65
+ }
66
+ void action.run(() => setUpvote({ entryId: entry.id, desiredState }), "Could not update vote");
67
+ };
68
+ return (_jsxs(FeedbackEntry.Root, { entry: entry, children: [_jsx(FeedbackEntry.Upvote, { disabled: isAuthenticated === undefined || action.pending, onToggle: toggle }), _jsx(Pressable, { onPress: onOpen === undefined ? undefined : () => onOpen(entry.id), accessibilityRole: onOpen === undefined ? undefined : "button", style: { flex: 1, minWidth: 0 }, children: _jsx(FeedbackEntry.Content, { children: _jsxs(View, { style: { gap: 5 }, children: [_jsxs(View, { style: { flexDirection: "row", gap: 8 }, children: [_jsx(FeedbackEntry.Kind, {}), _jsx(FeedbackEntry.Status, {})] }), _jsx(FeedbackEntry.Title, {}), _jsx(FeedbackEntry.Body, {}), _jsx(FeedbackEntry.CommentCount, {})] }) }) })] }));
69
+ }
70
+ function useFeedbackAuth(hooks) {
71
+ return { isAuthenticated: hooks.useIsAuthenticated() };
72
+ }
73
+ //# sourceMappingURL=RoadmapScreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoadmapScreen.js","sourceRoot":"","sources":["../../../../src/native/shared/ui/RoadmapScreen.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface FeedbackActionFailure {
2
+ message: string;
3
+ retry: () => void;
4
+ }
5
+ /** Runs a UI mutation and exposes a single retryable failure state. */
6
+ export declare function useFeedbackAction(): {
7
+ pending: boolean;
8
+ failure: FeedbackActionFailure | null;
9
+ run: <T>(action: () => Promise<T>, retryAction?: () => Promise<unknown>) => Promise<T | undefined>;
10
+ };
11
+ export declare function FeedbackActionError({ failure, }: {
12
+ failure: FeedbackActionFailure | null;
13
+ }): import("react").JSX.Element | null;
14
+ //# sourceMappingURL=action.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/react/action.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAMD,uEAAuE;AACvE,wBAAgB,iBAAiB;;;UAIZ,CAAC,UACV,MAAM,OAAO,CAAC,CAAC,CAAC,gBACX,MAAM,OAAO,CAAC,OAAO,CAAC,KAClC,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;EAoB1B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,GACR,EAAE;IACD,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACvC,sCAUA"}
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ function messageForError(error) {
4
+ return error instanceof Error ? error.message : "Something went wrong.";
5
+ }
6
+ /** Runs a UI mutation and exposes a single retryable failure state. */
7
+ export function useFeedbackAction() {
8
+ const [pending, setPending] = useState(false);
9
+ const [failure, setFailure] = useState(null);
10
+ const run = async (action, retryAction = action) => {
11
+ if (pending)
12
+ return undefined;
13
+ setPending(true);
14
+ setFailure(null);
15
+ try {
16
+ return await action();
17
+ }
18
+ catch (error) {
19
+ setFailure({
20
+ message: messageForError(error),
21
+ retry: () => {
22
+ void run(retryAction, retryAction);
23
+ },
24
+ });
25
+ return undefined;
26
+ }
27
+ finally {
28
+ setPending(false);
29
+ }
30
+ };
31
+ return { pending, failure, run };
32
+ }
33
+ export function FeedbackActionError({ failure, }) {
34
+ if (failure === null)
35
+ return null;
36
+ return (_jsxs("div", { className: "cf-action-error", role: "alert", children: [_jsx("span", { children: failure.message }), _jsx("button", { type: "button", className: "cf-button", onClick: failure.retry, children: "Retry" })] }));
37
+ }
38
+ //# sourceMappingURL=action.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.js","sourceRoot":"","sources":["../../src/react/action.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAOjC,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;AAC1E,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,iBAAiB;IAC/B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAA+B,IAAI,CAAC,CAAC;IAE3E,MAAM,GAAG,GAAG,KAAK,EACf,MAAwB,EACxB,cAAsC,MAAM,EACpB,EAAE;QAC1B,IAAI,OAAO;YAAE,OAAO,SAAS,CAAC;QAC9B,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC;YACH,OAAO,MAAM,MAAM,EAAE,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC;gBACT,OAAO,EAAE,eAAe,CAAC,KAAK,CAAC;gBAC/B,KAAK,EAAE,GAAG,EAAE;oBACV,KAAK,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;gBACrC,CAAC;aACF,CAAC,CAAC;YACH,OAAO,SAAS,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,EAClC,OAAO,GAGR;IACC,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAClC,OAAO,CACL,eAAK,SAAS,EAAC,iBAAiB,EAAC,IAAI,EAAC,OAAO,aAC3C,yBAAO,OAAO,CAAC,OAAO,GAAQ,EAC9B,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,WAAW,EAAC,OAAO,EAAE,OAAO,CAAC,KAAK,sBAEzD,IACL,CACP,CAAC;AACJ,CAAC"}
@@ -5,5 +5,6 @@ export type * from "../shared/types";
5
5
  export * from "./css.js";
6
6
  export * from "./metadata.js";
7
7
  export * from "./primitives.js";
8
+ export * from "./roadmap.js";
8
9
  export * from "./screen.js";
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,mBAAmB,iBAAiB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,mBAAmB,iBAAiB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
@@ -4,5 +4,6 @@ export * from "../shared/theme.js";
4
4
  export * from "./css.js";
5
5
  export * from "./metadata.js";
6
6
  export * from "./primitives.js";
7
+ export * from "./roadmap.js";
7
8
  export * from "./screen.js";
8
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AAEnC,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AAEnC,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { RoadmapScreenProps } from "../shared/types/index.js";
2
+ export declare function RoadmapScreen({ hooks, messages, theme, unstyled, onEntryOpen, onUnauthenticated, pageSize, entryPageSize, ...colors }: RoadmapScreenProps): import("react").JSX.Element;
3
+ //# sourceMappingURL=roadmap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roadmap.d.ts","sourceRoot":"","sources":["../../src/react/roadmap.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAInE,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,aAAa,EACb,GAAG,MAAM,EACV,EAAE,kBAAkB,+BAepB"}
@@ -0,0 +1,59 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { FeedbackProvider, useFeedbackUi, } from "../shared/context/FeedbackProvider.js";
5
+ import { allowAuthenticatedAction } from "../shared/helpers.js";
6
+ import { FeedbackActionError, useFeedbackAction } from "./action.js";
7
+ import { FeedbackBoard, FeedbackEntry } from "./primitives.js";
8
+ export function RoadmapScreen({ hooks, messages, theme, unstyled, onEntryOpen, onUnauthenticated, pageSize, entryPageSize, ...colors }) {
9
+ const resolvedPageSize = pageSize ?? hooks.pageSizes.roadmap;
10
+ const resolvedEntryPageSize = entryPageSize ?? hooks.pageSizes.entries;
11
+ return (_jsx(FeedbackProvider, { messages: messages, theme: theme, unstyled: unstyled, children: _jsx(RoadmapScreenInner, { hooks: hooks, onEntryOpen: onEntryOpen, onUnauthenticated: onUnauthenticated, pageSize: resolvedPageSize, entryPageSize: resolvedEntryPageSize, ...colors }) }));
12
+ }
13
+ function RoadmapScreenInner({ hooks, onEntryOpen, onUnauthenticated, pageSize, entryPageSize, ...colors }) {
14
+ const { messages } = useFeedbackUi();
15
+ const [query, setQuery] = useState("");
16
+ const [selectedId, setSelectedId] = useState(null);
17
+ const roadmap = hooks.useRoadmap();
18
+ const search = hooks.useSearchRoadmap(query);
19
+ const searching = query.trim().length > 0;
20
+ const items = searching ? (search ?? []) : roadmap.results;
21
+ const selected = items.find((item) => item.id === selectedId) ?? null;
22
+ if (selected !== null) {
23
+ return (_jsx(FeedbackBoard.Root, { ...colors, children: _jsx(RoadmapDetail, { item: selected, hooks: hooks, entryPageSize: entryPageSize, onEntryOpen: onEntryOpen, onUnauthenticated: onUnauthenticated, onBack: () => setSelectedId(null) }) }));
24
+ }
25
+ const loading = searching
26
+ ? search === undefined
27
+ : roadmap.status === "LoadingFirstPage";
28
+ return (_jsxs(FeedbackBoard.Root, { ...colors, children: [_jsx(FeedbackBoard.Header, { children: _jsxs("div", { children: [_jsx(FeedbackBoard.Title, { children: "Roadmap" }), _jsx("p", { className: "cf-board__subtitle", children: "See what is planned, in progress, and shipped." })] }) }), _jsx(FeedbackBoard.Search, { value: query, onValueChange: setQuery, placeholder: "Search roadmap\u2026" }), loading ? (_jsx(FeedbackBoard.State, { children: messages.board.loading })) : items.length === 0 ? (_jsx(FeedbackBoard.State, { children: searching ? "No roadmap items found." : "No roadmap items yet." })) : (_jsx(FeedbackBoard.List, { children: items.map((item) => (_jsx(RoadmapCard, { item: item, onOpen: () => setSelectedId(item.id) }, item.id))) })), !searching &&
29
+ (roadmap.status === "CanLoadMore" ||
30
+ roadmap.status === "LoadingMore") && (_jsx("button", { type: "button", className: "cf-button", disabled: roadmap.status === "LoadingMore", onClick: () => roadmap.loadMore(pageSize), children: messages.board.loadMore }))] }));
31
+ }
32
+ function RoadmapCard({ item, onOpen, }) {
33
+ return (_jsx("button", { type: "button", className: "cf-entry cf-roadmap-card", onClick: onOpen, children: _jsxs("span", { className: "cf-entry__content", children: [_jsxs("span", { className: "cf-entry__meta", children: [_jsx("span", { className: "cf-entry__kind", children: item.status.replaceAll("_", " ") }), _jsxs("span", { className: "cf-status", children: [item.feedbackCount, " linked"] })] }), _jsx("strong", { className: "cf-entry__title", children: item.title }), item.description && (_jsx("span", { className: "cf-entry__body", children: item.description }))] }) }));
34
+ }
35
+ function RoadmapDetail({ item, hooks, entryPageSize, onEntryOpen, onUnauthenticated, onBack, }) {
36
+ const { messages } = useFeedbackUi();
37
+ const feedback = hooks.useRoadmapFeedback(item.id);
38
+ return (_jsxs("div", { className: "cf-detail", children: [_jsx("button", { type: "button", className: "cf-button cf-button--link", onClick: onBack, children: messages.entry.back }), _jsxs("header", { children: [_jsxs("div", { className: "cf-entry__meta", children: [_jsx("span", { className: "cf-entry__kind", children: item.status.replaceAll("_", " ") }), _jsxs("span", { className: "cf-status", children: ["Position ", item.position] })] }), _jsx("h2", { className: "cf-board__title", children: item.title }), _jsx("p", { className: "cf-entry__body", children: item.description ?? "No description." })] }), _jsxs("dl", { className: "cf-roadmap-meta", children: [_jsxs("div", { children: [_jsx("dt", { children: "ID" }), _jsx("dd", { children: item.id })] }), _jsxs("div", { children: [_jsx("dt", { children: "Linked feedback" }), _jsx("dd", { children: item.feedbackCount })] }), _jsxs("div", { children: [_jsx("dt", { children: "Created" }), _jsx("dd", { children: new Date(item.createdAt).toLocaleString() })] }), _jsxs("div", { children: [_jsx("dt", { children: "Updated" }), _jsx("dd", { children: new Date(item.updatedAt).toLocaleString() })] }), _jsxs("div", { children: [_jsx("dt", { children: "Document created" }), _jsx("dd", { children: new Date(item.creationTime).toLocaleString() })] })] }), _jsxs("section", { className: "cf-discussion", children: [_jsx("h3", { children: "Attached feedback" }), feedback.status === "LoadingFirstPage" ? (_jsx("p", { className: "cf-state", children: messages.board.loading })) : feedback.results.length === 0 ? (_jsx("p", { className: "cf-state", children: "No feedback attached." })) : (_jsx("div", { className: "cf-comments", children: feedback.results.map((entry) => (_jsx(RoadmapEntry, { entry: entry, hooks: hooks, onOpen: onEntryOpen, onUnauthenticated: onUnauthenticated }, entry.id))) })), (feedback.status === "CanLoadMore" ||
39
+ feedback.status === "LoadingMore") && (_jsx("button", { type: "button", className: "cf-button", disabled: feedback.status === "LoadingMore", onClick: () => feedback.loadMore(entryPageSize), children: messages.comments.loadMore }))] })] }));
40
+ }
41
+ function RoadmapEntry({ entry, hooks, onOpen, onUnauthenticated, }) {
42
+ const isAuthenticated = hooks.useIsAuthenticated();
43
+ const setUpvote = hooks.useSetEntryUpvote();
44
+ const action = useFeedbackAction();
45
+ const toggle = (desiredState) => {
46
+ if (!allowAuthenticatedAction(isAuthenticated, onUnauthenticated) ||
47
+ action.pending) {
48
+ return;
49
+ }
50
+ void action.run(() => setUpvote({ entryId: entry.id, desiredState }));
51
+ };
52
+ return (_jsxs(_Fragment, { children: [_jsxs(FeedbackEntry.Root, { entry: entry, children: [_jsx(FeedbackEntry.Upvote, { disabled: isAuthenticated === undefined || action.pending, onToggle: toggle }), _jsxs(FeedbackEntry.Content, { onClick: () => onOpen?.(entry.id), onKeyDown: (event) => {
53
+ if (event.key === "Enter" || event.key === " ") {
54
+ event.preventDefault();
55
+ onOpen?.(entry.id);
56
+ }
57
+ }, role: onOpen === undefined ? undefined : "button", tabIndex: onOpen === undefined ? undefined : 0, children: [_jsxs("div", { className: "cf-entry__meta", children: [_jsx(FeedbackEntry.Kind, {}), _jsx(FeedbackEntry.Status, {}), _jsx(FeedbackEntry.CommentCount, {})] }), _jsx(FeedbackEntry.Title, {}), _jsx(FeedbackEntry.Body, {})] })] }), _jsx(FeedbackActionError, { failure: action.failure })] }));
58
+ }
59
+ //# sourceMappingURL=roadmap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roadmap.js","sourceRoot":"","sources":["../../src/react/roadmap.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,OAAO,EACL,gBAAgB,EAChB,aAAa,GACd,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE/D,MAAM,UAAU,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,aAAa,EACb,GAAG,MAAM,EACU;IACnB,MAAM,gBAAgB,GAAG,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC;IAC7D,MAAM,qBAAqB,GAAG,aAAa,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC;IACvE,OAAO,CACL,KAAC,gBAAgB,IAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,YACpE,KAAC,kBAAkB,IACjB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,iBAAiB,EACpC,QAAQ,EAAE,gBAAgB,EAC1B,aAAa,EAAE,qBAAqB,KAChC,MAAM,GACV,GACe,CACpB,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,EAC1B,KAAK,EACL,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,aAAa,EACb,GAAG,MAAM,EAIV;IACC,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,EAAE,CAAC;IACrC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,UAAU,CAAC,IAAI,IAAI,CAAC;IAEtE,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,CACL,KAAC,aAAa,CAAC,IAAI,OAAK,MAAM,YAC5B,KAAC,aAAa,IACZ,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,KAAK,EACZ,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,iBAAiB,EACpC,MAAM,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,GACjC,GACiB,CACtB,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,SAAS;QACvB,CAAC,CAAC,MAAM,KAAK,SAAS;QACtB,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,kBAAkB,CAAC;IAE1C,OAAO,CACL,MAAC,aAAa,CAAC,IAAI,OAAK,MAAM,aAC5B,KAAC,aAAa,CAAC,MAAM,cACnB,0BACE,KAAC,aAAa,CAAC,KAAK,0BAA8B,EAClD,YAAG,SAAS,EAAC,oBAAoB,+DAE7B,IACA,GACe,EACvB,KAAC,aAAa,CAAC,MAAM,IACnB,KAAK,EAAE,KAAK,EACZ,aAAa,EAAE,QAAQ,EACvB,WAAW,EAAC,sBAAiB,GAC7B,EACD,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,aAAa,CAAC,KAAK,cAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,GAAuB,CACpE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACvB,KAAC,aAAa,CAAC,KAAK,cACjB,SAAS,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,uBAAuB,GAC5C,CACvB,CAAC,CAAC,CAAC,CACF,KAAC,aAAa,CAAC,IAAI,cAChB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,KAAC,WAAW,IAEV,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,IAF/B,IAAI,CAAC,EAAE,CAGZ,CACH,CAAC,GACiB,CACtB,EACA,CAAC,SAAS;gBACT,CAAC,OAAO,CAAC,MAAM,KAAK,aAAa;oBAC/B,OAAO,CAAC,MAAM,KAAK,aAAa,CAAC,IAAI,CACrC,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,WAAW,EACrB,QAAQ,EAAE,OAAO,CAAC,MAAM,KAAK,aAAa,EAC1C,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAExC,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACjB,CACV,IACgB,CACtB,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,EACnB,IAAI,EACJ,MAAM,GAIP;IACC,OAAO,CACL,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,0BAA0B,EAAC,OAAO,EAAE,MAAM,YACxE,gBAAM,SAAS,EAAC,mBAAmB,aACjC,gBAAM,SAAS,EAAC,gBAAgB,aAC9B,eAAM,SAAS,EAAC,gBAAgB,YAC7B,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,GAC5B,EACP,gBAAM,SAAS,EAAC,WAAW,aAAE,IAAI,CAAC,aAAa,eAAe,IACzD,EACP,iBAAQ,SAAS,EAAC,iBAAiB,YAAE,IAAI,CAAC,KAAK,GAAU,EACxD,IAAI,CAAC,WAAW,IAAI,CACnB,eAAM,SAAS,EAAC,gBAAgB,YAAE,IAAI,CAAC,WAAW,GAAQ,CAC3D,IACI,GACA,CACV,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,EACrB,IAAI,EACJ,KAAK,EACL,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,MAAM,GAQP;IACC,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnD,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aACxB,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,2BAA2B,EACrC,OAAO,EAAE,MAAM,YAEd,QAAQ,CAAC,KAAK,CAAC,IAAI,GACb,EACT,6BACE,eAAK,SAAS,EAAC,gBAAgB,aAC7B,eAAM,SAAS,EAAC,gBAAgB,YAC7B,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,GAC5B,EACP,gBAAM,SAAS,EAAC,WAAW,0BAAW,IAAI,CAAC,QAAQ,IAAQ,IACvD,EACN,aAAI,SAAS,EAAC,iBAAiB,YAAE,IAAI,CAAC,KAAK,GAAM,EACjD,YAAG,SAAS,EAAC,gBAAgB,YAC1B,IAAI,CAAC,WAAW,IAAI,iBAAiB,GACpC,IACG,EACT,cAAI,SAAS,EAAC,iBAAiB,aAC7B,0BACE,8BAAW,EACX,uBAAK,IAAI,CAAC,EAAE,GAAM,IACd,EACN,0BACE,2CAAwB,EACxB,uBAAK,IAAI,CAAC,aAAa,GAAM,IACzB,EACN,0BACE,mCAAgB,EAChB,uBAAK,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,GAAM,IAChD,EACN,0BACE,mCAAgB,EAChB,uBAAK,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,GAAM,IAChD,EACN,0BACE,4CAAyB,EACzB,uBAAK,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,cAAc,EAAE,GAAM,IACnD,IACH,EACL,mBAAS,SAAS,EAAC,eAAe,aAChC,6CAA0B,EACzB,QAAQ,CAAC,MAAM,KAAK,kBAAkB,CAAC,CAAC,CAAC,CACxC,YAAG,SAAS,EAAC,UAAU,YAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,GAAK,CACrD,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAClC,YAAG,SAAS,EAAC,UAAU,sCAA0B,CAClD,CAAC,CAAC,CAAC,CACF,cAAK,SAAS,EAAC,aAAa,YACzB,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC/B,KAAC,YAAY,IAEX,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,WAAW,EACnB,iBAAiB,EAAE,iBAAiB,IAJ/B,KAAK,CAAC,EAAE,CAKb,CACH,CAAC,GACE,CACP,EACA,CAAC,QAAQ,CAAC,MAAM,KAAK,aAAa;wBACjC,QAAQ,CAAC,MAAM,KAAK,aAAa,CAAC,IAAI,CACtC,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,WAAW,EACrB,QAAQ,EAAE,QAAQ,CAAC,MAAM,KAAK,aAAa,EAC3C,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,YAE9C,QAAQ,CAAC,QAAQ,CAAC,QAAQ,GACpB,CACV,IACO,IACN,CACP,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,EACpB,KAAK,EACL,KAAK,EACL,MAAM,EACN,iBAAiB,GAMlB;IACC,MAAM,eAAe,GAAG,KAAK,CAAC,kBAAkB,EAAE,CAAC;IACnD,MAAM,SAAS,GAAG,KAAK,CAAC,iBAAiB,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,CAAC,YAAqB,EAAE,EAAE;QACvC,IACE,CAAC,wBAAwB,CAAC,eAAe,EAAE,iBAAiB,CAAC;YAC7D,MAAM,CAAC,OAAO,EACd,CAAC;YACD,OAAO;QACT,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC;IAEF,OAAO,CACL,8BACE,MAAC,aAAa,CAAC,IAAI,IAAC,KAAK,EAAE,KAAK,aAC9B,KAAC,aAAa,CAAC,MAAM,IACnB,QAAQ,EAAE,eAAe,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,EACzD,QAAQ,EAAE,MAAM,GAChB,EACF,MAAC,aAAa,CAAC,OAAO,IACpB,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EACjC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;4BACnB,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gCAC/C,KAAK,CAAC,cAAc,EAAE,CAAC;gCACvB,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;4BACrB,CAAC;wBACH,CAAC,EACD,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EACjD,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,aAE9C,eAAK,SAAS,EAAC,gBAAgB,aAC7B,KAAC,aAAa,CAAC,IAAI,KAAG,EACtB,KAAC,aAAa,CAAC,MAAM,KAAG,EACxB,KAAC,aAAa,CAAC,YAAY,KAAG,IAC1B,EACN,KAAC,aAAa,CAAC,KAAK,KAAG,EACvB,KAAC,aAAa,CAAC,IAAI,KAAG,IACA,IACL,EACrB,KAAC,mBAAmB,IAAC,OAAO,EAAE,MAAM,CAAC,OAAO,GAAI,IAC/C,CACJ,CAAC;AACJ,CAAC"}
@@ -2,5 +2,5 @@ import type { FeedbackScreenRootProps } from "../shared/types/";
2
2
  export interface FeedbackScreenProps extends FeedbackScreenRootProps {
3
3
  className?: string | undefined;
4
4
  }
5
- export declare function FeedbackScreen({ hooks, messages, theme, unstyled, entrySort, commentSort, enabledKinds, maxCommentDepth, transformComments, renderActor, debounceDuration, collectMetadata, emptyState, loading, ...props }: FeedbackScreenProps): import("react").JSX.Element;
5
+ export declare function FeedbackScreen({ hooks, messages, theme, unstyled, entrySort, commentSort, enabledKinds, maxCommentDepth, transformComments, renderActor, onUnauthenticated, debounceDuration, collectMetadata, emptyState, loading, ...props }: FeedbackScreenProps): import("react").JSX.Element;
6
6
  //# sourceMappingURL=screen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/react/screen.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAOV,uBAAuB,EACxB,MAAM,kBAAkB,CAAC;AAiB1B,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IAClE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,SAAiB,EACjB,WAAmB,EACnB,YAAyB,EACzB,eAAmB,EACnB,iBAAiB,EACjB,WAAW,EACX,gBAAsB,EACtB,eAAe,EACf,UAAU,EACV,OAAO,EACP,GAAG,KAAK,EACT,EAAE,mBAAmB,+BAqBrB"}
1
+ {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/react/screen.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAOV,uBAAuB,EACxB,MAAM,kBAAkB,CAAC;AAkB1B,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IAClE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,SAAiB,EACjB,WAAmB,EACnB,YAAyB,EACzB,eAAmB,EACnB,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,gBAAsB,EACtB,eAAe,EACf,UAAU,EACV,OAAO,EACP,GAAG,KAAK,EACT,EAAE,mBAAmB,+BAsBrB"}
@@ -1,10 +1,11 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useMemo, useState } from "react";
4
4
  import { FeedbackBodyProvider, useFeedbackBody, } from "../shared/context/FeedbackBodyProvider.js";
5
5
  import { FeedbackProvider, useFeedbackUi, } from "../shared/context/FeedbackProvider";
6
- import { createEntryLabel, entryStatusChoices } from "../shared/helpers.js";
6
+ import { allowAuthenticatedAction, createEntryLabel, entryStatusChoices, } from "../shared/helpers.js";
7
7
  import { Comment, ChoiceChips, FeedbackBoard, FeedbackEntry, FeedbackForm, } from "./primitives.js";
8
+ import { FeedbackActionError, useFeedbackAction } from "./action.js";
8
9
  import { collectWebMetadata } from "./metadata.js";
9
10
  import { collectEntryMetadata, formatMetadataKey } from "../shared/metadata.js";
10
11
  const entryKinds = [
@@ -12,11 +13,11 @@ const entryKinds = [
12
13
  "feature_request",
13
14
  "bug_report",
14
15
  ];
15
- export function FeedbackScreen({ hooks, messages, theme, unstyled, entrySort = "top", commentSort = "top", enabledKinds = entryKinds, maxCommentDepth = 5, transformComments, renderActor, debounceDuration = 300, collectMetadata, emptyState, loading, ...props }) {
16
- return (_jsx(FeedbackProvider, { messages: messages, theme: theme, unstyled: unstyled, children: _jsx(FeedbackBodyProvider, { hooks: hooks, entrySort: entrySort, commentSort: commentSort, enabledKinds: enabledKinds, maxCommentDepth: maxCommentDepth, debounceDuration: debounceDuration, collectMetadata: collectMetadata, emptyState: emptyState, loading: loading, collectStandardMetadata: collectWebMetadata, transformComments: transformComments, renderActor: renderActor, children: _jsx(FeedbackScreenInner, { ...props }) }) }));
16
+ export function FeedbackScreen({ hooks, messages, theme, unstyled, entrySort = "top", commentSort = "top", enabledKinds = entryKinds, maxCommentDepth = 5, transformComments, renderActor, onUnauthenticated, debounceDuration = 300, collectMetadata, emptyState, loading, ...props }) {
17
+ return (_jsx(FeedbackProvider, { messages: messages, theme: theme, unstyled: unstyled, children: _jsx(FeedbackBodyProvider, { hooks: hooks, entrySort: entrySort, commentSort: commentSort, enabledKinds: enabledKinds, maxCommentDepth: maxCommentDepth, debounceDuration: debounceDuration, collectMetadata: collectMetadata, emptyState: emptyState, loading: loading, collectStandardMetadata: collectWebMetadata, transformComments: transformComments, renderActor: renderActor, onUnauthenticated: onUnauthenticated, children: _jsx(FeedbackScreenInner, { ...props }) }) }));
17
18
  }
18
19
  function FeedbackScreenInner({ className, ...colors }) {
19
- const { hooks, entrySort, enabledKinds, showForm, setShowForm, setSelectedEntryId, selectedEntryId, statusFilter, setStatusFilter, query, setQuery, debouncedQuery, emptyState, loading: loadingIndicator, } = useFeedbackBody();
20
+ const { hooks, entrySort, enabledKinds, showForm, setShowForm, setSelectedEntryId, selectedEntryId, statusFilter, setStatusFilter, query, setQuery, debouncedQuery, emptyState, loading: loadingIndicator, isAuthenticated, onUnauthenticated, } = useFeedbackBody();
20
21
  const { messages } = useFeedbackUi();
21
22
  const list = hooks.useEntries({
22
23
  sort: entrySort,
@@ -31,37 +32,59 @@ function FeedbackScreenInner({ className, ...colors }) {
31
32
  if (selectedEntryId !== null) {
32
33
  return (_jsx(FeedbackBoard.Root, { className: className, ...colors, children: _jsx(EntryDetail, { entryId: selectedEntryId, onBack: () => setSelectedEntryId(null) }) }));
33
34
  }
34
- const searching = query.trim().length > 0;
35
+ const normalizedQuery = query.trim();
36
+ const normalizedDebouncedQuery = debouncedQuery.trim();
37
+ const searching = normalizedQuery.length > 0;
35
38
  const entries = searching ? searchResults : list.results;
36
39
  const isLoading = searching
37
- ? searchResults === undefined
40
+ ? normalizedQuery !== normalizedDebouncedQuery ||
41
+ searchResults === undefined
38
42
  : list.status === "LoadingFirstPage";
39
- return (_jsxs(FeedbackBoard.Root, { className: className, ...colors, children: [_jsxs(FeedbackBoard.Header, { children: [_jsxs("div", { children: [_jsx(FeedbackBoard.Title, {}), _jsx("p", { className: "cf-board__subtitle", children: messages.board.subtitle }), _jsx(ChoiceChips, { "aria-label": messages.board.statusFilter, options: entryStatusChoices(messages), value: statusFilter, onValueChange: setStatusFilter })] }), _jsx("button", { type: "button", className: "cf-button cf-button--primary", onClick: () => setShowForm((current) => !current), children: showForm
43
+ return (_jsxs(FeedbackBoard.Root, { className: className, ...colors, children: [_jsxs(FeedbackBoard.Header, { children: [_jsxs("div", { children: [_jsx(FeedbackBoard.Title, {}), _jsx("p", { className: "cf-board__subtitle", children: messages.board.subtitle }), _jsx(ChoiceChips, { "aria-label": messages.board.statusFilter, options: entryStatusChoices(messages), value: statusFilter, onValueChange: setStatusFilter })] }), _jsx("button", { type: "button", className: "cf-button cf-button--primary", disabled: isAuthenticated === undefined, onClick: () => {
44
+ if (!allowAuthenticatedAction(isAuthenticated, onUnauthenticated)) {
45
+ return;
46
+ }
47
+ setShowForm((current) => !current);
48
+ }, children: showForm
40
49
  ? messages.form.cancel
41
50
  : createEntryLabel(enabledKinds, messages) })] }), showForm && (_jsx(CreateEntryForm, { onCreated: (entryId) => {
42
51
  setShowForm(false);
43
52
  setSelectedEntryId(entryId);
44
53
  } })), _jsx(FeedbackBoard.Search, { value: query, onValueChange: setQuery }), isLoading ? (_jsx(FeedbackBoard.State, { children: loadingIndicator ?? (_jsx("span", { className: "cf-state__message", children: messages.board.loading })) })) : entries !== undefined && entries.length === 0 ? (_jsxs(FeedbackBoard.State, { children: [emptyState, _jsx("span", { className: "cf-state__message", children: searching
45
54
  ? messages.board.noSearchResults
46
- : messages.board.noEntries }), _jsx("button", { type: "button", className: "cf-button cf-button--primary", onClick: () => setShowForm(true), children: createEntryLabel(enabledKinds, messages) })] })) : (_jsx(FeedbackBoard.List, { children: (entries ?? []).map((entry) => (_jsx(EntryCard, { entry: entry, hooks: hooks, onOpen: () => setSelectedEntryId(entry.id) }, entry.id))) })), !searching && list.status === "CanLoadMore" && (_jsx("button", { type: "button", className: "cf-button", onClick: () => list.loadMore(hooks.pageSizes.entries), children: messages.board.loadMore }))] }));
55
+ : messages.board.noEntries }), _jsx("button", { type: "button", className: "cf-button cf-button--primary", disabled: isAuthenticated === undefined, onClick: () => {
56
+ if (allowAuthenticatedAction(isAuthenticated, onUnauthenticated)) {
57
+ setShowForm(true);
58
+ }
59
+ }, children: createEntryLabel(enabledKinds, messages) })] })) : (_jsx(FeedbackBoard.List, { children: (entries ?? []).map((entry) => (_jsx(EntryCard, { entry: entry, hooks: hooks, onOpen: () => setSelectedEntryId(entry.id) }, entry.id))) })), !searching &&
60
+ (list.status === "CanLoadMore" || list.status === "LoadingMore") && (_jsx("button", { type: "button", className: "cf-button", disabled: list.status === "LoadingMore", onClick: () => list.loadMore(hooks.pageSizes.entries), children: messages.board.loadMore }))] }));
47
61
  }
48
62
  function EntryCard({ entry, hooks, onOpen }) {
63
+ const { isAuthenticated, onUnauthenticated } = useFeedbackBody();
49
64
  const setUpvote = hooks.useSetEntryUpvote();
50
- return (_jsxs(FeedbackEntry.Root, { entry: entry, children: [_jsx(FeedbackEntry.Upvote, { onToggle: (active) => void setUpvote({ entryId: entry.id, desiredState: active }) }), _jsxs(FeedbackEntry.Content, { onClick: onOpen, onKeyDown: (event) => {
51
- if (event.key === "Enter" || event.key === " ") {
52
- event.preventDefault();
53
- onOpen();
54
- }
55
- }, role: "button", tabIndex: 0, children: [_jsxs("div", { className: "cf-entry__meta", children: [_jsx(FeedbackEntry.Kind, {}), _jsx(FeedbackEntry.Status, {}), _jsx(FeedbackEntry.CommentCount, {})] }), _jsx(FeedbackEntry.Title, {}), _jsx(FeedbackEntry.Body, {})] })] }));
65
+ const action = useFeedbackAction();
66
+ const toggleUpvote = (desiredState) => {
67
+ if (!allowAuthenticatedAction(isAuthenticated, onUnauthenticated) ||
68
+ action.pending) {
69
+ return;
70
+ }
71
+ void action.run(() => setUpvote({ entryId: entry.id, desiredState }));
72
+ };
73
+ return (_jsxs(_Fragment, { children: [_jsxs(FeedbackEntry.Root, { entry: entry, children: [_jsx(FeedbackEntry.Upvote, { disabled: isAuthenticated === undefined || action.pending, onToggle: toggleUpvote }), _jsxs(FeedbackEntry.Content, { onClick: onOpen, onKeyDown: (event) => {
74
+ if (event.key === "Enter" || event.key === " ") {
75
+ event.preventDefault();
76
+ onOpen();
77
+ }
78
+ }, role: "button", tabIndex: 0, children: [_jsxs("div", { className: "cf-entry__meta", children: [_jsx(FeedbackEntry.Kind, {}), _jsx(FeedbackEntry.Status, {}), _jsx(FeedbackEntry.CommentCount, {})] }), _jsx(FeedbackEntry.Title, {}), _jsx(FeedbackEntry.Body, {})] })] }), _jsx(FeedbackActionError, { failure: action.failure })] }));
56
79
  }
57
80
  function CreateEntryForm({ onCreated }) {
58
- const { hooks, enabledKinds, collectMetadata, collectStandardMetadata } = useFeedbackBody();
81
+ const { hooks, enabledKinds, collectMetadata, collectStandardMetadata, isAuthenticated, onUnauthenticated, } = useFeedbackBody();
59
82
  const { messages } = useFeedbackUi();
60
83
  const [kind, setKind] = useState(enabledKinds[0] ?? "feedback");
61
84
  const [title, setTitle] = useState("");
62
85
  const [body, setBody] = useState("");
63
- const [submitting, setSubmitting] = useState(false);
64
86
  const createEntry = hooks.useCreateEntry();
87
+ const action = useFeedbackAction();
65
88
  const similar = hooks.useSimilarEntries({ title, body, kind });
66
89
  const [confirmingDuplicate, setConfirmingDuplicate] = useState(false);
67
90
  const submit = (event) => {
@@ -78,10 +101,11 @@ function CreateEntryForm({ onCreated }) {
78
101
  void create();
79
102
  };
80
103
  const create = async () => {
81
- if (submitting)
104
+ if (action.pending)
82
105
  return;
83
- setSubmitting(true);
84
- try {
106
+ if (!allowAuthenticatedAction(isAuthenticated, onUnauthenticated))
107
+ return;
108
+ await action.run(async () => {
85
109
  const metadata = await collectEntryMetadata(collectMetadata, kind, collectStandardMetadata);
86
110
  const entryId = await createEntry({
87
111
  kind,
@@ -90,10 +114,7 @@ function CreateEntryForm({ onCreated }) {
90
114
  ...(metadata === undefined ? {} : { metadata }),
91
115
  });
92
116
  onCreated(entryId);
93
- }
94
- finally {
95
- setSubmitting(false);
96
- }
117
+ });
97
118
  };
98
119
  const suggestions = useMemo(() => {
99
120
  if (similar === undefined)
@@ -105,7 +126,7 @@ function CreateEntryForm({ onCreated }) {
105
126
  label: messages.kinds[value],
106
127
  })), value: kind, onValueChange: setKind })] })), _jsxs("label", { className: "cf-field", children: [_jsx("span", { children: messages.form.title }), _jsx(FeedbackForm.Input, { value: title, onChange: (event) => setTitle(event.currentTarget.value), placeholder: messages.form.titlePlaceholder, required: true })] }), _jsxs("label", { className: "cf-field", children: [_jsx("span", { children: messages.form.body }), _jsx(FeedbackForm.Textarea, { value: body, onChange: (event) => setBody(event.currentTarget.value), placeholder: messages.form.bodyPlaceholder, rows: 5, required: true })] }), suggestions.length > 0 && (_jsxs("aside", { className: "cf-duplicates", children: [_jsx("strong", { children: similar?.exact.length
107
128
  ? messages.form.exactDuplicate
108
- : messages.form.possibleDuplicates }), _jsx("div", { className: "cf-duplicates__list", children: suggestions.map((entry) => (_jsxs("div", { className: "cf-duplicate", children: [_jsxs("div", { className: "cf-entry__meta", children: [_jsx("span", { className: "cf-entry__kind", children: messages.kinds[entry.kind] }), _jsx("span", { className: "cf-status", children: messages.statuses[entry.status] })] }), _jsx("strong", { children: entry.title }), _jsx("span", { className: "cf-duplicate__body", children: entry.body }), _jsxs("span", { className: "cf-duplicate__meta", children: ["\u25B2 ", entry.upvoteCount, " \u00B7", " ", messages.entry.comments(entry.commentCount)] })] }, entry.id))) })] })), _jsx(FeedbackForm.Submit, { submitting: submitting, disabled: confirmingDuplicate || submitting }), confirmingDuplicate && (_jsx("div", { className: "cf-confirm-backdrop", children: _jsxs("div", { className: "cf-confirm", role: "alertdialog", "aria-modal": "true", "aria-labelledby": "cf-duplicate-confirm-title", children: [_jsx("strong", { id: "cf-duplicate-confirm-title", children: similar?.exact.length
129
+ : messages.form.possibleDuplicates }), _jsx("div", { className: "cf-duplicates__list", children: suggestions.map((entry) => (_jsxs("div", { className: "cf-duplicate", children: [_jsxs("div", { className: "cf-entry__meta", children: [_jsx("span", { className: "cf-entry__kind", children: messages.kinds[entry.kind] }), _jsx("span", { className: "cf-status", children: messages.statuses[entry.status] })] }), _jsx("strong", { children: entry.title }), _jsx("span", { className: "cf-duplicate__body", children: entry.body }), _jsxs("span", { className: "cf-duplicate__meta", children: ["\u25B2 ", entry.upvoteCount, " \u00B7", " ", messages.entry.comments(entry.commentCount)] })] }, entry.id))) })] })), _jsx(FeedbackForm.Submit, { submitting: action.pending, disabled: confirmingDuplicate || action.pending || isAuthenticated === undefined }), _jsx(FeedbackActionError, { failure: action.failure }), confirmingDuplicate && (_jsx("div", { className: "cf-confirm-backdrop", children: _jsxs("div", { className: "cf-confirm", role: "alertdialog", "aria-modal": "true", "aria-labelledby": "cf-duplicate-confirm-title", children: [_jsx("strong", { id: "cf-duplicate-confirm-title", children: similar?.exact.length
109
130
  ? messages.form.exactDuplicate
110
131
  : messages.form.possibleDuplicates }), _jsx("p", { children: messages.form.duplicateWarning }), _jsxs("div", { className: "cf-inline-actions", children: [_jsx("button", { type: "button", className: "cf-button", onClick: () => setConfirmingDuplicate(false), children: messages.form.cancel }), _jsx("button", { type: "button", className: "cf-button cf-button--primary", onClick: () => {
111
132
  setConfirmingDuplicate(false);
@@ -113,7 +134,7 @@ function CreateEntryForm({ onCreated }) {
113
134
  }, children: messages.form.submitAnyway })] })] }) }))] }));
114
135
  }
115
136
  function EntryDetail({ entryId, onBack }) {
116
- const { hooks, commentSort, transformComments } = useFeedbackBody();
137
+ const { hooks, commentSort, transformComments, isAuthenticated, onUnauthenticated, } = useFeedbackBody();
117
138
  const { messages } = useFeedbackUi();
118
139
  const entry = hooks.useEntry(entryId);
119
140
  const setUpvote = hooks.useSetEntryUpvote();
@@ -121,19 +142,35 @@ function EntryDetail({ entryId, onBack }) {
121
142
  const createComment = hooks.useCreateComment();
122
143
  const [body, setBody] = useState("");
123
144
  const [showMetadata, setShowMetadata] = useState(false);
145
+ const upvoteAction = useFeedbackAction();
146
+ const commentAction = useFeedbackAction();
147
+ const toggleUpvote = (desiredState) => {
148
+ if (!allowAuthenticatedAction(isAuthenticated, onUnauthenticated) ||
149
+ upvoteAction.pending) {
150
+ return;
151
+ }
152
+ void upvoteAction.run(() => setUpvote({ entryId, desiredState }));
153
+ };
124
154
  const visibleComments = useMemo(() => transformComments?.(comments.results) ?? comments.results, [comments.results, transformComments]);
125
155
  if (entry === undefined)
126
156
  return _jsx("p", { className: "cf-state", children: messages.board.loading });
127
157
  if (entry === null)
128
158
  return (_jsx("button", { type: "button", className: "cf-button", onClick: onBack, children: messages.entry.back }));
129
- return (_jsxs("div", { className: "cf-detail", children: [_jsx("button", { type: "button", className: "cf-button cf-button--link", onClick: onBack, children: messages.entry.back }), _jsxs(FeedbackEntry.Root, { entry: entry, children: [_jsx(FeedbackEntry.Upvote, { onToggle: (active) => void setUpvote({ entryId, desiredState: active }) }), _jsxs(FeedbackEntry.Content, { children: [_jsxs("div", { className: "cf-entry__meta", children: [_jsx(FeedbackEntry.Status, {}), _jsx(FeedbackEntry.CommentCount, {})] }), _jsx(FeedbackEntry.Title, {}), _jsx(FeedbackEntry.Body, {})] })] }), entry.metadata !== undefined && (_jsx("div", { children: _jsx("button", { type: "button", className: "cf-button", onClick: () => setShowMetadata(true), children: messages.metadata.view }) })), showMetadata && entry.metadata !== undefined && (_jsx(MetadataDialog, { metadata: entry.metadata, onClose: () => setShowMetadata(false) })), _jsxs("section", { className: "cf-discussion", children: [_jsx("h3", { children: messages.comments.title }), _jsxs(FeedbackForm.Root, { onSubmit: async (event) => {
159
+ return (_jsxs("div", { className: "cf-detail", children: [_jsx("button", { type: "button", className: "cf-button cf-button--link", onClick: onBack, children: messages.entry.back }), _jsxs(FeedbackEntry.Root, { entry: entry, children: [_jsx(FeedbackEntry.Upvote, { disabled: isAuthenticated === undefined || upvoteAction.pending, onToggle: toggleUpvote }), _jsxs(FeedbackEntry.Content, { children: [_jsxs("div", { className: "cf-entry__meta", children: [_jsx(FeedbackEntry.Status, {}), _jsx(FeedbackEntry.CommentCount, {})] }), _jsx(FeedbackEntry.Title, {}), _jsx(FeedbackEntry.Body, {})] })] }), _jsx(FeedbackActionError, { failure: upvoteAction.failure }), entry.metadata !== undefined && (_jsx("div", { children: _jsx("button", { type: "button", className: "cf-button", onClick: () => setShowMetadata(true), children: messages.metadata.view }) })), showMetadata && entry.metadata !== undefined && (_jsx(MetadataDialog, { metadata: entry.metadata, onClose: () => setShowMetadata(false) })), _jsxs("section", { className: "cf-discussion", children: [_jsx("h3", { children: messages.comments.title }), _jsxs(FeedbackForm.Root, { onSubmit: (event) => {
130
160
  event.preventDefault();
131
161
  if (body.trim().length === 0)
132
162
  return;
133
- await createComment({ entryId, body });
134
- setBody("");
135
- }, children: [_jsx(FeedbackForm.Textarea, { value: body, onChange: (event) => setBody(event.currentTarget.value), placeholder: messages.comments.placeholder, rows: 3 }), _jsx("button", { type: "submit", className: "cf-button cf-button--primary", children: messages.comments.submit })] }), comments.status === "LoadingFirstPage" && (_jsx("p", { className: "cf-state", children: messages.board.loading })), comments.status !== "LoadingFirstPage" &&
136
- visibleComments.length === 0 && (_jsx("p", { className: "cf-state", children: messages.comments.noComments })), _jsx("div", { className: "cf-comments", children: visibleComments.map((comment) => (_jsx(CommentBranch, { comment: comment, entryId: entryId }, comment.id))) }), comments.status === "CanLoadMore" && (_jsx("button", { type: "button", className: "cf-button", onClick: () => comments.loadMore(hooks.pageSizes.comments), children: messages.comments.loadMore }))] })] }));
163
+ if (!allowAuthenticatedAction(isAuthenticated, onUnauthenticated) ||
164
+ commentAction.pending) {
165
+ return;
166
+ }
167
+ void commentAction.run(async () => {
168
+ await createComment({ entryId, body });
169
+ setBody("");
170
+ });
171
+ }, children: [_jsx(FeedbackForm.Textarea, { value: body, onChange: (event) => setBody(event.currentTarget.value), placeholder: messages.comments.placeholder, rows: 3 }), _jsx("button", { type: "submit", className: "cf-button cf-button--primary", disabled: isAuthenticated === undefined || commentAction.pending, children: messages.comments.submit })] }), _jsx(FeedbackActionError, { failure: commentAction.failure }), comments.status === "LoadingFirstPage" && (_jsx("p", { className: "cf-state", children: messages.board.loading })), comments.status !== "LoadingFirstPage" &&
172
+ visibleComments.length === 0 && (_jsx("p", { className: "cf-state", children: messages.comments.noComments })), _jsx("div", { className: "cf-comments", children: visibleComments.map((comment) => (_jsx(CommentBranch, { comment: comment, entryId: entryId }, comment.id))) }), (comments.status === "CanLoadMore" ||
173
+ comments.status === "LoadingMore") && (_jsx("button", { type: "button", className: "cf-button", disabled: comments.status === "LoadingMore", onClick: () => comments.loadMore(hooks.pageSizes.comments), children: messages.comments.loadMore }))] })] }));
137
174
  }
138
175
  function MetadataDialog({ metadata, onClose, }) {
139
176
  const { messages } = useFeedbackUi();
@@ -145,26 +182,45 @@ function MetadataDialog({ metadata, onClose, }) {
145
182
  return (_jsx("div", { className: "cf-confirm-backdrop", onMouseDown: onClose, children: _jsxs("div", { className: "cf-confirm cf-metadata-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": "cf-metadata-title", onMouseDown: (event) => event.stopPropagation(), children: [_jsx("h3", { id: "cf-metadata-title", children: messages.metadata.title }), hasValues ? (sections.map(([label, values]) => values === undefined || Object.keys(values).length === 0 ? null : (_jsxs("section", { className: "cf-metadata-section", children: [_jsx("h4", { children: label }), _jsx("dl", { children: Object.entries(values).map(([key, value]) => (_jsxs("div", { className: "cf-metadata-row", children: [_jsx("dt", { children: formatMetadataKey(key) }), _jsx("dd", { children: String(value) })] }, key))) })] }, label)))) : (_jsx("p", { children: messages.metadata.empty })), _jsx("div", { className: "cf-inline-actions", children: _jsx("button", { type: "button", className: "cf-button", onClick: onClose, children: messages.metadata.close }) })] }) }));
146
183
  }
147
184
  function CommentBranch({ comment, entryId }) {
148
- const { hooks, maxCommentDepth, renderActor } = useFeedbackBody();
185
+ const { hooks, maxCommentDepth, renderActor, isAuthenticated, onUnauthenticated, } = useFeedbackBody();
149
186
  const { messages } = useFeedbackUi();
150
187
  const [expanded, setExpanded] = useState(false);
151
188
  const [replying, setReplying] = useState(false);
152
189
  const [replyBody, setReplyBody] = useState("");
153
190
  const setLike = hooks.useSetCommentLike();
154
191
  const createComment = hooks.useCreateComment();
155
- return (_jsxs(Comment.Root, { comment: comment, children: [renderActor === undefined ? null : (_jsx("div", { className: "cf-comment__author", children: renderActor(comment.actorId) })), _jsx(Comment.Body, {}), _jsxs("div", { className: "cf-comment__toolbar", children: [_jsx(Comment.Like, { onToggle: (active) => void setLike({ commentId: comment.id, desiredState: active }) }), comment.body !== null && comment.depth < maxCommentDepth && (_jsx(Comment.Reply, { onActivate: () => setReplying((value) => !value) })), _jsx(Comment.RepliesButton, { expanded: expanded, onExpandedChange: setExpanded })] }), replying && (_jsxs(FeedbackForm.Root, { onSubmit: async (event) => {
192
+ const likeAction = useFeedbackAction();
193
+ const replyAction = useFeedbackAction();
194
+ const toggleLike = (desiredState) => {
195
+ if (!allowAuthenticatedAction(isAuthenticated, onUnauthenticated) ||
196
+ likeAction.pending) {
197
+ return;
198
+ }
199
+ void likeAction.run(() => setLike({ commentId: comment.id, desiredState }));
200
+ };
201
+ return (_jsxs(Comment.Root, { comment: comment, children: [renderActor === undefined ? null : (_jsx("div", { className: "cf-comment__author", children: renderActor(comment.actorId) })), _jsx(Comment.Body, {}), _jsxs("div", { className: "cf-comment__toolbar", children: [_jsx(Comment.Like, { disabled: isAuthenticated === undefined || likeAction.pending, onToggle: toggleLike }), comment.body !== null && comment.depth < maxCommentDepth && (_jsx(Comment.Reply, { disabled: isAuthenticated === undefined || replyAction.pending, onActivate: () => {
202
+ if (allowAuthenticatedAction(isAuthenticated, onUnauthenticated)) {
203
+ setReplying((value) => !value);
204
+ }
205
+ } })), _jsx(Comment.RepliesButton, { expanded: expanded, onExpandedChange: setExpanded })] }), _jsx(FeedbackActionError, { failure: likeAction.failure }), replying && (_jsxs(FeedbackForm.Root, { onSubmit: (event) => {
156
206
  event.preventDefault();
157
207
  if (replyBody.trim().length === 0)
158
208
  return;
159
- await createComment({
160
- entryId,
161
- parentCommentId: comment.id,
162
- body: replyBody,
209
+ if (!allowAuthenticatedAction(isAuthenticated, onUnauthenticated) ||
210
+ replyAction.pending) {
211
+ return;
212
+ }
213
+ void replyAction.run(async () => {
214
+ await createComment({
215
+ entryId,
216
+ parentCommentId: comment.id,
217
+ body: replyBody,
218
+ });
219
+ setReplyBody("");
220
+ setReplying(false);
221
+ setExpanded(true);
163
222
  });
164
- setReplyBody("");
165
- setReplying(false);
166
- setExpanded(true);
167
- }, children: [_jsx(FeedbackForm.Textarea, { value: replyBody, onChange: (event) => setReplyBody(event.currentTarget.value), placeholder: messages.comments.placeholder, rows: 2 }), _jsxs("div", { className: "cf-inline-actions", children: [_jsx("button", { type: "submit", className: "cf-button cf-button--primary", children: messages.comments.reply }), _jsx("button", { type: "button", className: "cf-button", onClick: () => setReplying(false), children: messages.comments.cancelReply })] })] })), expanded && _jsx(ReplyList, { entryId: entryId, parentCommentId: comment.id })] }));
223
+ }, children: [_jsx(FeedbackForm.Textarea, { value: replyBody, onChange: (event) => setReplyBody(event.currentTarget.value), placeholder: messages.comments.placeholder, rows: 2 }), _jsxs("div", { className: "cf-inline-actions", children: [_jsx("button", { type: "submit", className: "cf-button cf-button--primary", disabled: isAuthenticated === undefined || replyAction.pending, children: messages.comments.reply }), _jsx("button", { type: "button", className: "cf-button", onClick: () => setReplying(false), children: messages.comments.cancelReply })] })] })), _jsx(FeedbackActionError, { failure: replyAction.failure }), expanded && _jsx(ReplyList, { entryId: entryId, parentCommentId: comment.id })] }));
168
224
  }
169
225
  function ReplyList({ entryId, parentCommentId }) {
170
226
  const { hooks, commentSort, transformComments } = useFeedbackBody();
@@ -175,6 +231,7 @@ function ReplyList({ entryId, parentCommentId }) {
175
231
  sort: commentSort,
176
232
  });
177
233
  const visibleReplies = useMemo(() => transformComments?.(replies.results) ?? replies.results, [replies.results, transformComments]);
178
- return (_jsxs(Comment.Children, { children: [replies.status === "LoadingFirstPage" && (_jsx("p", { className: "cf-state", children: messages.board.loading })), visibleReplies.map((reply) => (_jsx(CommentBranch, { comment: reply, entryId: entryId }, reply.id))), replies.status === "CanLoadMore" && (_jsx("button", { type: "button", className: "cf-button", onClick: () => replies.loadMore(hooks.pageSizes.replies), children: messages.comments.loadMore }))] }));
234
+ return (_jsxs(Comment.Children, { children: [replies.status === "LoadingFirstPage" && (_jsx("p", { className: "cf-state", children: messages.board.loading })), visibleReplies.map((reply) => (_jsx(CommentBranch, { comment: reply, entryId: entryId }, reply.id))), (replies.status === "CanLoadMore" ||
235
+ replies.status === "LoadingMore") && (_jsx("button", { type: "button", className: "cf-button", disabled: replies.status === "LoadingMore", onClick: () => replies.loadMore(hooks.pageSizes.replies), children: messages.comments.loadMore }))] }));
179
236
  }
180
237
  //# sourceMappingURL=screen.js.map