Skip to main content

things3_cloud/ui/views/
logbook.rs

1use crate::common::{ICONS, fmt_date_local};
2use crate::store::{Task, ThingsStore};
3use crate::ui::components::empty_text::EmptyText;
4use crate::ui::components::tasks::{TaskList, TaskOptions};
5use iocraft::prelude::*;
6use std::sync::Arc;
7
8const LIST_INDENT: u32 = 4;
9
10#[derive(Default, Props)]
11pub struct LogbookViewProps<'a> {
12    pub items: Option<&'a Vec<Task>>,
13    pub detailed: bool,
14}
15
16#[component]
17pub fn LogbookView<'a>(hooks: Hooks, props: &LogbookViewProps<'a>) -> impl Into<AnyElement<'a>> {
18    let store = hooks.use_context::<Arc<ThingsStore>>().clone();
19    let Some(items) = props.items else {
20        return element! { Text(content: "") }.into_any();
21    };
22
23    if items.is_empty() {
24        return element! { EmptyText(content: "Logbook is empty.") }.into_any();
25    }
26
27    let mut groups: Vec<(String, Vec<&Task>)> = Vec::new();
28    for task in items {
29        let day = fmt_date_local(task.stop_date);
30        if let Some((current_day, day_tasks)) = groups.last_mut()
31            && *current_day == day
32        {
33            day_tasks.push(task);
34        } else {
35            groups.push((day, vec![task]));
36        }
37    }
38
39    let options = TaskOptions {
40        detailed: props.detailed,
41        show_project: true,
42        show_area: false,
43        show_today_markers: false,
44        show_staged_today_marker: false,
45    };
46
47    let id_prefix_len =
48        store.unique_prefix_length(&items.iter().map(|t| t.uuid.clone()).collect::<Vec<_>>());
49    let mut sections: Vec<AnyElement<'a>> = Vec::new();
50    for (idx, (day, day_items)) in groups.into_iter().enumerate() {
51        if idx > 0 {
52            sections.push(element! { Text(content: "", wrap: TextWrap::NoWrap) }.into_any());
53        }
54        sections.push(
55            element! {
56                View(flex_direction: FlexDirection::Column) {
57                    Text(content: format!("  {}", day), wrap: TextWrap::NoWrap, weight: Weight::Bold)
58                    View(flex_direction: FlexDirection::Column, padding_left: LIST_INDENT) {
59                        TaskList(items: day_items, id_prefix_len: id_prefix_len, options)
60                    }
61                }
62            }
63            .into_any(),
64        );
65    }
66
67    element! {
68        View(flex_direction: FlexDirection::Column) {
69            Text(
70                content: format!("{} Logbook  ({} tasks)", ICONS.done, items.len()),
71                wrap: TextWrap::NoWrap,
72                color: Color::Green,
73                weight: Weight::Bold,
74            )
75            Text(content: "", wrap: TextWrap::NoWrap)
76            #(sections)
77        }
78    }
79    .into_any()
80}