yggdrasil/components/comments/
list.rs1use dioxus::prelude::*;
6
7use crate::components::comments::item::CommentItem;
8use crate::components::comments::pending_item::PendingCommentItem;
9use crate::models::comment::PublicComment;
10use crate::utils::comment_storage::PendingComment;
11
12#[derive(Clone)]
14enum MergedComment {
15 Approved(PublicComment),
16 Pending(PendingComment),
17}
18
19fn merge_and_treeify(
27 approved: Vec<PublicComment>,
28 pending: Vec<PendingComment>,
29) -> Vec<MergedComment> {
30 use std::collections::{HashMap, HashSet};
31
32 let all: Vec<MergedComment> = approved
33 .into_iter()
34 .map(MergedComment::Approved)
35 .chain(pending.into_iter().map(MergedComment::Pending))
36 .collect();
37
38 let all_ids: HashSet<i64> = all
39 .iter()
40 .map(|c| match c {
41 MergedComment::Approved(c) => c.id,
42 MergedComment::Pending(c) => c.id,
43 })
44 .collect();
45
46 let mut children_map: HashMap<Option<i64>, Vec<MergedComment>> = HashMap::new();
48 for comment in all {
49 let parent_id = match &comment {
50 MergedComment::Approved(c) => c.parent_id,
51 MergedComment::Pending(c) => c.parent_id,
52 };
53 let effective_parent = match parent_id {
54 Some(pid) if !all_ids.contains(&pid) => None,
55 _ => parent_id,
56 };
57 children_map
58 .entry(effective_parent)
59 .or_default()
60 .push(comment);
61 }
62
63 for children in children_map.values_mut() {
65 children.sort_by(|a, b| {
66 let time_a = match a {
67 MergedComment::Approved(c) => c.created_at_iso.as_str(),
68 MergedComment::Pending(c) => c.created_at.as_str(),
69 };
70 let time_b = match b {
71 MergedComment::Approved(c) => c.created_at_iso.as_str(),
72 MergedComment::Pending(c) => c.created_at.as_str(),
73 };
74 time_a.cmp(time_b)
75 });
76 }
77
78 fn dfs(
80 parent_id: Option<i64>,
81 children_map: &HashMap<Option<i64>, Vec<MergedComment>>,
82 result: &mut Vec<MergedComment>,
83 ) {
84 if let Some(children) = children_map.get(&parent_id) {
85 for child in children {
86 result.push(child.clone());
87 let child_id = match child {
88 MergedComment::Approved(c) => Some(c.id),
89 MergedComment::Pending(c) => Some(c.id),
90 };
91 dfs(child_id, children_map, result);
92 }
93 }
94 }
95
96 let mut result = Vec::new();
97 dfs(None, &children_map, &mut result);
98 result
99}
100
101#[component]
110pub fn CommentList(
111 comments: Vec<PublicComment>,
112 pending: Vec<PendingComment>,
113 post_id: i32,
114) -> Element {
115 let merged = merge_and_treeify(comments, pending);
116
117 rsx! {
118 div { class: "space-y-0 divide-y divide-gray-100 dark:divide-gray-700",
119 for item in merged {
120 match item {
121 MergedComment::Approved(comment) => rsx! {
122 CommentItem { key: "{comment.id}", comment, post_id }
123 },
124 MergedComment::Pending(comment) => rsx! {
125 PendingCommentItem { key: "{comment.id}", comment, post_id }
126 },
127 }
128 }
129 }
130 }
131}