convex-feedback-ui 0.1.2 → 0.1.4
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/README.md +119 -18
- package/dist/.tsbuildinfo +1 -1
- package/dist/native/expo/ExpoFeedbackBody.d.ts +4 -0
- package/dist/native/expo/ExpoFeedbackBody.d.ts.map +1 -0
- package/dist/native/expo/ExpoFeedbackBody.js +26 -0
- package/dist/native/expo/ExpoFeedbackBody.js.map +1 -0
- package/dist/native/expo/FeedbackScreen.d.ts +3 -0
- package/dist/native/expo/FeedbackScreen.d.ts.map +1 -0
- package/dist/native/expo/FeedbackScreen.js +9 -0
- package/dist/native/expo/FeedbackScreen.js.map +1 -0
- package/dist/native/expo/FeedbackStack.d.ts +3 -0
- package/dist/native/expo/FeedbackStack.d.ts.map +1 -0
- package/dist/native/expo/FeedbackStack.js +41 -0
- package/dist/native/expo/FeedbackStack.js.map +1 -0
- package/dist/native/expo/index.d.ts +9 -0
- package/dist/native/expo/index.d.ts.map +1 -0
- package/dist/native/expo/index.js +7 -0
- package/dist/native/expo/index.js.map +1 -0
- package/dist/native/expo/types.d.ts +20 -0
- package/dist/native/expo/types.d.ts.map +1 -0
- package/dist/native/expo/types.js +2 -0
- package/dist/native/expo/types.js.map +1 -0
- package/dist/native/native/FeedbackScreen.d.ts +3 -0
- package/dist/native/native/FeedbackScreen.d.ts.map +1 -0
- package/dist/native/native/FeedbackScreen.js +9 -0
- package/dist/native/native/FeedbackScreen.js.map +1 -0
- package/dist/native/native/index.d.ts +8 -0
- package/dist/native/native/index.d.ts.map +1 -0
- package/dist/native/native/index.js +7 -0
- package/dist/native/native/index.js.map +1 -0
- package/dist/native/shared/helpers.d.ts +3 -0
- package/dist/native/shared/helpers.d.ts.map +1 -0
- package/dist/native/shared/helpers.js +4 -0
- package/dist/native/shared/helpers.js.map +1 -0
- package/dist/native/shared/ui/BodyContent.d.ts +3 -0
- package/dist/native/shared/ui/BodyContent.d.ts.map +1 -0
- package/dist/native/shared/ui/BodyContent.js +18 -0
- package/dist/native/shared/ui/BodyContent.js.map +1 -0
- package/dist/native/shared/ui/Button.d.ts +5 -0
- package/dist/native/shared/ui/Button.d.ts.map +1 -0
- package/dist/native/shared/ui/Button.js +15 -0
- package/dist/native/shared/ui/Button.js.map +1 -0
- package/dist/native/shared/ui/CommentBranch.d.ts +5 -0
- package/dist/native/shared/ui/CommentBranch.d.ts.map +1 -0
- package/dist/native/shared/ui/CommentBranch.js +45 -0
- package/dist/native/shared/ui/CommentBranch.js.map +1 -0
- package/dist/native/shared/ui/EntryCard.d.ts +3 -0
- package/dist/native/shared/ui/EntryCard.d.ts.map +1 -0
- package/dist/native/shared/ui/EntryCard.js +13 -0
- package/dist/native/shared/ui/EntryCard.js.map +1 -0
- package/dist/native/shared/ui/EntryDetail.d.ts +3 -0
- package/dist/native/shared/ui/EntryDetail.d.ts.map +1 -0
- package/dist/native/shared/ui/EntryDetail.js +37 -0
- package/dist/native/shared/ui/EntryDetail.js.map +1 -0
- package/dist/native/shared/ui/FeedbackScreenHeader.d.ts +2 -0
- package/dist/native/shared/ui/FeedbackScreenHeader.d.ts.map +1 -0
- package/dist/native/shared/ui/FeedbackScreenHeader.js +22 -0
- package/dist/native/shared/ui/FeedbackScreenHeader.js.map +1 -0
- package/dist/native/shared/ui/FeedbackScreenList.d.ts +3 -0
- package/dist/native/shared/ui/FeedbackScreenList.d.ts.map +1 -0
- package/dist/native/shared/ui/FeedbackScreenList.js +19 -0
- package/dist/native/shared/ui/FeedbackScreenList.js.map +1 -0
- package/dist/native/shared/ui/NewEntry.d.ts +5 -0
- package/dist/native/shared/ui/NewEntry.d.ts.map +1 -0
- package/dist/native/shared/ui/NewEntry.js +158 -0
- package/dist/native/shared/ui/NewEntry.js.map +1 -0
- package/dist/native/shared/ui/ReplyList.d.ts +3 -0
- package/dist/native/shared/ui/ReplyList.d.ts.map +1 -0
- package/dist/native/shared/ui/ReplyList.js +19 -0
- package/dist/native/shared/ui/ReplyList.js.map +1 -0
- package/dist/native/{primitives.d.ts → shared/ui/primitives.d.ts} +10 -12
- package/dist/native/shared/ui/primitives.d.ts.map +1 -0
- package/dist/native/{primitives.js → shared/ui/primitives.js} +19 -25
- package/dist/native/shared/ui/primitives.js.map +1 -0
- package/dist/react/{context.d.ts → css.d.ts} +2 -4
- package/dist/react/css.d.ts.map +1 -0
- package/dist/react/css.js +18 -0
- package/dist/react/css.js.map +1 -0
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/primitives.d.ts.map +1 -1
- package/dist/react/primitives.js +2 -1
- package/dist/react/primitives.js.map +1 -1
- package/dist/react/screen.d.ts +3 -3
- package/dist/react/screen.d.ts.map +1 -1
- package/dist/react/screen.js +25 -22
- package/dist/react/screen.js.map +1 -1
- package/dist/shared/context/FeedbackBodyProvider.d.ts +5 -0
- package/dist/shared/context/FeedbackBodyProvider.d.ts.map +1 -0
- package/dist/shared/context/FeedbackBodyProvider.js +43 -0
- package/dist/shared/context/FeedbackBodyProvider.js.map +1 -0
- package/dist/{native/context.d.ts → shared/context/FeedbackProvider.d.ts} +2 -2
- package/dist/shared/context/FeedbackProvider.d.ts.map +1 -0
- package/dist/{native/context.js → shared/context/FeedbackProvider.js} +3 -3
- package/dist/shared/context/FeedbackProvider.js.map +1 -0
- package/dist/shared/helpers.d.ts +7 -0
- package/dist/shared/helpers.d.ts.map +1 -0
- package/dist/shared/helpers.js +24 -0
- package/dist/shared/helpers.js.map +1 -0
- package/dist/shared/messages.d.ts.map +1 -1
- package/dist/shared/messages.js +23 -14
- package/dist/shared/messages.js.map +1 -1
- package/dist/shared/theme.d.ts.map +1 -1
- package/dist/shared/theme.js +1 -0
- package/dist/shared/theme.js.map +1 -1
- package/dist/shared/types/context.d.ts +4 -0
- package/dist/shared/types/context.d.ts.map +1 -1
- package/dist/shared/types/messages.d.ts +12 -1
- package/dist/shared/types/messages.d.ts.map +1 -1
- package/dist/shared/types/screen.d.ts +55 -18
- package/dist/shared/types/screen.d.ts.map +1 -1
- package/dist/shared/types/theme.d.ts +4 -0
- package/dist/shared/types/theme.d.ts.map +1 -1
- package/package.json +27 -12
- package/src/native/expo/ExpoFeedbackBody.tsx +48 -0
- package/src/native/expo/FeedbackScreen.tsx +37 -0
- package/src/native/expo/FeedbackStack.tsx +99 -0
- package/src/native/expo/README.md +17 -0
- package/src/native/expo/index.ts +8 -0
- package/src/native/expo/types.ts +23 -0
- package/src/native/native/FeedbackScreen.tsx +37 -0
- package/src/native/native/index.ts +7 -0
- package/src/native/shared/helpers.ts +9 -0
- package/src/native/shared/ui/BodyContent.tsx +43 -0
- package/src/native/shared/ui/Button.tsx +29 -0
- package/src/native/shared/ui/CommentBranch.tsx +122 -0
- package/src/native/shared/ui/EntryCard.tsx +37 -0
- package/src/native/shared/ui/EntryDetail.tsx +103 -0
- package/src/native/shared/ui/FeedbackScreenHeader.tsx +42 -0
- package/src/native/shared/ui/FeedbackScreenList.tsx +61 -0
- package/src/native/shared/ui/NewEntry.tsx +375 -0
- package/src/native/{primitives.tsx → shared/ui/primitives.tsx} +84 -92
- package/src/react/{context.tsx → css.tsx} +2 -44
- package/src/react/index.ts +1 -1
- package/src/react/primitives.tsx +2 -1
- package/src/react/screen.tsx +67 -123
- package/src/shared/context/FeedbackBodyProvider.tsx +82 -0
- package/src/{native/context.tsx → shared/context/FeedbackProvider.tsx} +3 -3
- package/src/shared/helpers.ts +33 -0
- package/src/shared/messages.ts +23 -22
- package/src/shared/theme.ts +1 -0
- package/src/shared/types/context.ts +5 -0
- package/src/shared/types/messages.ts +16 -1
- package/src/shared/types/screen.ts +69 -23
- package/src/shared/types/theme.ts +5 -0
- package/dist/native/context.d.ts.map +0 -1
- package/dist/native/context.js.map +0 -1
- package/dist/native/index.d.ts +0 -7
- package/dist/native/index.d.ts.map +0 -1
- package/dist/native/index.js +0 -6
- package/dist/native/index.js.map +0 -1
- package/dist/native/primitives.d.ts.map +0 -1
- package/dist/native/primitives.js.map +0 -1
- package/dist/native/screen.d.ts +0 -3
- package/dist/native/screen.d.ts.map +0 -1
- package/dist/native/screen.js +0 -284
- package/dist/native/screen.js.map +0 -1
- package/dist/react/context.d.ts.map +0 -1
- package/dist/react/context.js +0 -41
- package/dist/react/context.js.map +0 -1
- package/src/native/index.ts +0 -6
- package/src/native/screen.tsx +0 -831
- /package/src/native/{README.md → native/README.md} +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import { Text, View } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { useFeedbackBody } from "../../../shared/context/FeedbackBodyProvider.js";
|
|
5
|
+
import { useFeedbackUi } from "../../../shared/context/FeedbackProvider.js";
|
|
6
|
+
import type { FeedbackScreenCommentBranchProps } from "../../../shared/types";
|
|
7
|
+
import { Button } from "./Button";
|
|
8
|
+
import { Comment, FeedbackForm } from "./primitives.js";
|
|
9
|
+
|
|
10
|
+
import type { FeedbackScreenReplyListProps } from "../../../shared/types";
|
|
11
|
+
|
|
12
|
+
export function ReplyList({
|
|
13
|
+
entryId,
|
|
14
|
+
parentCommentId,
|
|
15
|
+
}: FeedbackScreenReplyListProps) {
|
|
16
|
+
const { hooks, commentSort, transformComments } = useFeedbackBody();
|
|
17
|
+
const { messages } = useFeedbackUi();
|
|
18
|
+
|
|
19
|
+
const replies = hooks.useComments({
|
|
20
|
+
entryId,
|
|
21
|
+
parentCommentId,
|
|
22
|
+
sort: commentSort,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const visible = useMemo(
|
|
26
|
+
() => transformComments?.(replies.results) ?? replies.results,
|
|
27
|
+
[replies.results, transformComments],
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Comment.Children>
|
|
32
|
+
{visible.map((reply) => (
|
|
33
|
+
<CommentBranch key={reply.id} comment={reply} entryId={entryId} />
|
|
34
|
+
))}
|
|
35
|
+
{replies.status === "CanLoadMore" && (
|
|
36
|
+
<Button
|
|
37
|
+
label={messages.comments.loadMore}
|
|
38
|
+
onPress={() => replies.loadMore(hooks.pageSizes.replies)}
|
|
39
|
+
/>
|
|
40
|
+
)}
|
|
41
|
+
</Comment.Children>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function CommentBranch({
|
|
46
|
+
comment,
|
|
47
|
+
entryId,
|
|
48
|
+
}: FeedbackScreenCommentBranchProps) {
|
|
49
|
+
const { hooks, maxCommentDepth, renderActor } = useFeedbackBody();
|
|
50
|
+
const { messages, theme } = useFeedbackUi();
|
|
51
|
+
const [expanded, setExpanded] = useState(false);
|
|
52
|
+
const [replying, setReplying] = useState(false);
|
|
53
|
+
const [replyBody, setReplyBody] = useState("");
|
|
54
|
+
const setLike = hooks.useSetCommentLike();
|
|
55
|
+
const createComment = hooks.useCreateComment();
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Comment.Root comment={comment}>
|
|
59
|
+
{renderActor === undefined ? null : (
|
|
60
|
+
<View>{renderActor(comment.actorId)}</View>
|
|
61
|
+
)}
|
|
62
|
+
<Comment.Body />
|
|
63
|
+
<View
|
|
64
|
+
style={{
|
|
65
|
+
flexDirection: "row",
|
|
66
|
+
flexWrap: "wrap",
|
|
67
|
+
alignItems: "center",
|
|
68
|
+
gap: 4,
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
<Comment.Like
|
|
72
|
+
onToggle={(active) =>
|
|
73
|
+
void setLike({ commentId: comment.id, desiredState: active })
|
|
74
|
+
}
|
|
75
|
+
/>
|
|
76
|
+
{comment.body !== null && comment.depth < maxCommentDepth ? (
|
|
77
|
+
<Comment.Reply onActivate={() => setReplying((value) => !value)} />
|
|
78
|
+
) : null}
|
|
79
|
+
<Comment.RepliesButton
|
|
80
|
+
expanded={expanded}
|
|
81
|
+
onExpandedChange={setExpanded}
|
|
82
|
+
/>
|
|
83
|
+
</View>
|
|
84
|
+
{replying ? (
|
|
85
|
+
<FeedbackForm.Root>
|
|
86
|
+
<FeedbackForm.Textarea
|
|
87
|
+
value={replyBody}
|
|
88
|
+
onChangeText={setReplyBody}
|
|
89
|
+
placeholder={messages.comments.placeholder}
|
|
90
|
+
/>
|
|
91
|
+
<FeedbackForm.Submit
|
|
92
|
+
onPress={async () => {
|
|
93
|
+
if (replyBody.trim().length === 0) return;
|
|
94
|
+
await createComment({
|
|
95
|
+
entryId,
|
|
96
|
+
parentCommentId: comment.id,
|
|
97
|
+
body: replyBody,
|
|
98
|
+
});
|
|
99
|
+
setReplyBody("");
|
|
100
|
+
setReplying(false);
|
|
101
|
+
setExpanded(true);
|
|
102
|
+
}}
|
|
103
|
+
>
|
|
104
|
+
{messages.comments.reply}
|
|
105
|
+
</FeedbackForm.Submit>
|
|
106
|
+
<Button
|
|
107
|
+
label={messages.comments.cancelReply}
|
|
108
|
+
onPress={() => setReplying(false)}
|
|
109
|
+
/>
|
|
110
|
+
</FeedbackForm.Root>
|
|
111
|
+
) : null}
|
|
112
|
+
{expanded ? (
|
|
113
|
+
<ReplyList entryId={entryId} parentCommentId={comment.id} />
|
|
114
|
+
) : null}
|
|
115
|
+
{comment.deletedAt !== undefined ? (
|
|
116
|
+
<Text style={{ color: theme.colors.mutedText, fontSize: 11 }}>
|
|
117
|
+
{messages.comments.deleted}
|
|
118
|
+
</Text>
|
|
119
|
+
) : null}
|
|
120
|
+
</Comment.Root>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Pressable, View } from "react-native";
|
|
2
|
+
|
|
3
|
+
import type { FeedbackScreenEntryCardProps } from "../../../shared/types";
|
|
4
|
+
import { FeedbackEntry } from "./primitives";
|
|
5
|
+
|
|
6
|
+
export function EntryCard({
|
|
7
|
+
entry,
|
|
8
|
+
hooks,
|
|
9
|
+
onOpen,
|
|
10
|
+
}: FeedbackScreenEntryCardProps) {
|
|
11
|
+
const setUpvote = hooks.useSetEntryUpvote();
|
|
12
|
+
return (
|
|
13
|
+
<FeedbackEntry.Root entry={entry}>
|
|
14
|
+
<FeedbackEntry.Upvote
|
|
15
|
+
onToggle={(active) =>
|
|
16
|
+
void setUpvote({ entryId: entry.id, desiredState: active })
|
|
17
|
+
}
|
|
18
|
+
/>
|
|
19
|
+
<Pressable onPress={onOpen} style={{ flex: 1, gap: 4 }}>
|
|
20
|
+
<View
|
|
21
|
+
style={{
|
|
22
|
+
flexDirection: "row",
|
|
23
|
+
alignItems: "center",
|
|
24
|
+
justifyContent: "space-between",
|
|
25
|
+
gap: 8,
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
<FeedbackEntry.Kind />
|
|
29
|
+
<FeedbackEntry.Status />
|
|
30
|
+
</View>
|
|
31
|
+
<FeedbackEntry.Title />
|
|
32
|
+
<FeedbackEntry.Body numberOfLines={3} />
|
|
33
|
+
<FeedbackEntry.CommentCount />
|
|
34
|
+
</Pressable>
|
|
35
|
+
</FeedbackEntry.Root>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import { ActivityIndicator, Text, View } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { useFeedbackBody } from "../../../shared/context/FeedbackBodyProvider";
|
|
5
|
+
import { useFeedbackUi } from "../../../shared/context/FeedbackProvider";
|
|
6
|
+
import type { FeedbackScreenEntryDetailProps } from "../../../shared/types";
|
|
7
|
+
import { Button } from "./Button";
|
|
8
|
+
import { CommentBranch } from "./CommentBranch";
|
|
9
|
+
import { FeedbackEntry, FeedbackForm } from "./primitives";
|
|
10
|
+
|
|
11
|
+
export function EntryDetail({
|
|
12
|
+
entryId,
|
|
13
|
+
onBack,
|
|
14
|
+
hideBackButton,
|
|
15
|
+
}: FeedbackScreenEntryDetailProps) {
|
|
16
|
+
const { hooks, commentSort, transformComments } = useFeedbackBody();
|
|
17
|
+
|
|
18
|
+
const { messages, theme } = useFeedbackUi();
|
|
19
|
+
const entry = hooks.useEntry(entryId);
|
|
20
|
+
const comments = hooks.useComments({ entryId, sort: commentSort });
|
|
21
|
+
const setUpvote = hooks.useSetEntryUpvote();
|
|
22
|
+
const createComment = hooks.useCreateComment();
|
|
23
|
+
const [body, setBody] = useState("");
|
|
24
|
+
const visible = useMemo(
|
|
25
|
+
() => transformComments?.(comments.results) ?? comments.results,
|
|
26
|
+
[comments.results, transformComments],
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
if (entry === undefined)
|
|
30
|
+
return (
|
|
31
|
+
<View
|
|
32
|
+
style={{
|
|
33
|
+
flex: 1,
|
|
34
|
+
gap: 8,
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
justifyContent: "center",
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
<ActivityIndicator size="large" />
|
|
40
|
+
<Text style={{ color: theme.colors.mutedText }}>
|
|
41
|
+
{messages.board.loading}
|
|
42
|
+
</Text>
|
|
43
|
+
</View>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (entry === null) {
|
|
47
|
+
if (hideBackButton) return;
|
|
48
|
+
return <Button label={messages.entry.back} onPress={onBack} />;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<View style={{ gap: 12 }}>
|
|
53
|
+
{!hideBackButton && (
|
|
54
|
+
<Button label={messages.entry.back} onPress={onBack} />
|
|
55
|
+
)}
|
|
56
|
+
<FeedbackEntry.Root entry={entry}>
|
|
57
|
+
<FeedbackEntry.Upvote
|
|
58
|
+
onToggle={(active) =>
|
|
59
|
+
void setUpvote({ entryId, desiredState: active })
|
|
60
|
+
}
|
|
61
|
+
/>
|
|
62
|
+
<FeedbackEntry.Content style={{ gap: 5 }}>
|
|
63
|
+
<FeedbackEntry.Status />
|
|
64
|
+
<FeedbackEntry.Title />
|
|
65
|
+
<FeedbackEntry.Body />
|
|
66
|
+
<FeedbackEntry.CommentCount />
|
|
67
|
+
</FeedbackEntry.Content>
|
|
68
|
+
</FeedbackEntry.Root>
|
|
69
|
+
<Text
|
|
70
|
+
style={{ color: theme.colors.text, fontSize: 18, fontWeight: "700" }}
|
|
71
|
+
>
|
|
72
|
+
{messages.comments.title}
|
|
73
|
+
</Text>
|
|
74
|
+
<FeedbackForm.Root>
|
|
75
|
+
<FeedbackForm.Textarea
|
|
76
|
+
value={body}
|
|
77
|
+
onChangeText={setBody}
|
|
78
|
+
placeholder={messages.comments.placeholder}
|
|
79
|
+
/>
|
|
80
|
+
<FeedbackForm.Submit
|
|
81
|
+
onPress={async () => {
|
|
82
|
+
if (body.trim().length === 0) return;
|
|
83
|
+
await createComment({ entryId, body });
|
|
84
|
+
setBody("");
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
{messages.comments.submit}
|
|
88
|
+
</FeedbackForm.Submit>
|
|
89
|
+
</FeedbackForm.Root>
|
|
90
|
+
<View style={{ gap: 8 }}>
|
|
91
|
+
{visible.map((comment) => (
|
|
92
|
+
<CommentBranch key={comment.id} comment={comment} entryId={entryId} />
|
|
93
|
+
))}
|
|
94
|
+
</View>
|
|
95
|
+
{comments.status === "CanLoadMore" && (
|
|
96
|
+
<Button
|
|
97
|
+
label={messages.comments.loadMore}
|
|
98
|
+
onPress={() => comments.loadMore(hooks.pageSizes.comments)}
|
|
99
|
+
/>
|
|
100
|
+
)}
|
|
101
|
+
</View>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Pressable, Text } from "react-native";
|
|
2
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
3
|
+
import { useFeedbackBody } from "../../../shared/context/FeedbackBodyProvider";
|
|
4
|
+
import { useFeedbackUi } from "../../../shared/context/FeedbackProvider";
|
|
5
|
+
import { FeedbackBoard } from "./primitives";
|
|
6
|
+
|
|
7
|
+
export function FeedbackScreenHeader() {
|
|
8
|
+
const { query, setShowForm, setQuery, enabledKinds } = useFeedbackBody();
|
|
9
|
+
const { messages, theme } = useFeedbackUi();
|
|
10
|
+
const { top } = useSafeAreaInsets();
|
|
11
|
+
|
|
12
|
+
const pageTitle =
|
|
13
|
+
enabledKinds.length === 1
|
|
14
|
+
? messages.kindsPlural[enabledKinds.at(0)!]
|
|
15
|
+
: messages.board.title;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<FeedbackBoard.Header style={{ padding: theme.spacing, paddingTop: top }}>
|
|
19
|
+
<FeedbackBoard.Title>{pageTitle}</FeedbackBoard.Title>
|
|
20
|
+
<Text style={{ color: theme.colors.mutedText }}>
|
|
21
|
+
{messages.board.subtitle}
|
|
22
|
+
</Text>
|
|
23
|
+
<Pressable
|
|
24
|
+
onPress={() => setShowForm(true)}
|
|
25
|
+
style={{
|
|
26
|
+
alignSelf: "flex-start",
|
|
27
|
+
paddingVertical: 9,
|
|
28
|
+
paddingHorizontal: 12,
|
|
29
|
+
borderRadius: 9,
|
|
30
|
+
backgroundColor: theme.colors.primary,
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
<Text
|
|
34
|
+
style={{ color: theme.colors.primaryForeground, fontWeight: "700" }}
|
|
35
|
+
>
|
|
36
|
+
{messages.board.createEntry}
|
|
37
|
+
</Text>
|
|
38
|
+
</Pressable>
|
|
39
|
+
<FeedbackBoard.Search value={query} onValueChange={(q) => setQuery(q)} />
|
|
40
|
+
</FeedbackBoard.Header>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useFeedbackBody } from "../../../shared/context/FeedbackBodyProvider.js";
|
|
2
|
+
import { useFeedbackUi } from "../../../shared/context/FeedbackProvider.js";
|
|
3
|
+
import type { FeedbackScreenListProps } from "../../../shared/types/index.js";
|
|
4
|
+
import { Button } from "./Button.js";
|
|
5
|
+
import { EntryCard } from "./EntryCard.js";
|
|
6
|
+
import { EntryDetail } from "./EntryDetail.js";
|
|
7
|
+
import { FeedbackBoard } from "./primitives.js";
|
|
8
|
+
|
|
9
|
+
export function FeedbackScreenList({
|
|
10
|
+
hideBackButton = false,
|
|
11
|
+
onEntryOpen,
|
|
12
|
+
}: FeedbackScreenListProps) {
|
|
13
|
+
const {
|
|
14
|
+
hooks,
|
|
15
|
+
entrySort,
|
|
16
|
+
isSearching,
|
|
17
|
+
enabledKinds,
|
|
18
|
+
selectedEntryId,
|
|
19
|
+
debouncedQuery,
|
|
20
|
+
setSelectedEntryId,
|
|
21
|
+
} = useFeedbackBody();
|
|
22
|
+
const { messages, theme } = useFeedbackUi();
|
|
23
|
+
|
|
24
|
+
const list = hooks.useEntries({ sort: entrySort, kinds: enabledKinds });
|
|
25
|
+
const search = hooks.useSearchEntries({
|
|
26
|
+
searchQuery: debouncedQuery,
|
|
27
|
+
kinds: enabledKinds,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const entries = isSearching ? search : list.results;
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<FeedbackBoard.List style={{ padding: theme.spacing }}>
|
|
35
|
+
{selectedEntryId ? (
|
|
36
|
+
<EntryDetail
|
|
37
|
+
entryId={selectedEntryId}
|
|
38
|
+
hideBackButton={hideBackButton}
|
|
39
|
+
onBack={() => setSelectedEntryId(null)}
|
|
40
|
+
/>
|
|
41
|
+
) : (
|
|
42
|
+
(entries ?? []).map((entry) => (
|
|
43
|
+
<EntryCard
|
|
44
|
+
key={entry.id}
|
|
45
|
+
entry={entry}
|
|
46
|
+
hooks={hooks}
|
|
47
|
+
onOpen={() => onEntryOpen(entry.id)}
|
|
48
|
+
/>
|
|
49
|
+
))
|
|
50
|
+
)}
|
|
51
|
+
</FeedbackBoard.List>
|
|
52
|
+
|
|
53
|
+
{!isSearching && list.status === "CanLoadMore" && (
|
|
54
|
+
<Button
|
|
55
|
+
label={messages.board.loadMore}
|
|
56
|
+
onPress={() => list.loadMore(hooks.pageSizes.entries)}
|
|
57
|
+
/>
|
|
58
|
+
)}
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
}
|