feat: ability to view tasks in different categories

This commit is contained in:
2024-08-31 10:47:49 +02:00
parent 765e0a1770
commit 28143a7088
29 changed files with 1127 additions and 169 deletions

View File

@@ -1,45 +1,65 @@
use chrono::Duration;
use crate::models::category::{CalendarTime, Category};
use std::fmt::Display;
use crate::components::category_input::CategoryInput;
use crate::components::reoccurrence_input::ReoccurrenceIntervalInput;
use crate::models::category::{CalendarTime, Category, Reoccurrence, ReoccurrenceInterval};
use crate::models::task::NewTask;
use crate::server::projects::get_projects;
use crate::server::tasks::create_task;
use chrono::{Duration, NaiveDate};
use dioxus::core_macro::{component, rsx};
use dioxus::dioxus_core::Element;
use dioxus::prelude::*;
use crate::route::Route;
const REMINDER_OFFSETS: [Option<Duration>; 17] = [
None,
Some(Duration::days(1)),
Some(Duration::hours(12)),
Some(Duration::hours(11)),
Some(Duration::hours(10)),
Some(Duration::hours(9)),
Some(Duration::hours(8)),
Some(Duration::hours(7)),
Some(Duration::hours(6)),
Some(Duration::hours(5)),
Some(Duration::hours(4)),
Some(Duration::hours(3)),
Some(Duration::hours(2)),
Some(Duration::hours(1)),
Some(Duration::minutes(30)),
Some(Duration::minutes(10)),
Some(Duration::zero()),
];
#[component]
pub(crate) fn TaskForm() -> Element {
let categories = vec![
Category::Inbox,
Category::SomedayMaybe,
Category::WaitingFor(String::new()),
Category::NextSteps,
Category::Calendar {
date: chrono::Local::now().date_naive(),
reoccurance_interval: None,
time: None,
},
Category::LongTerm,
];
let projects = use_server_future(get_projects)?.unwrap().unwrap();
let mut selected_category_index = use_signal::<usize>(|| 0);
let mut category_calendar_is_reoccurring = use_signal::<bool>(|| false);
let mut category_calendar_has_time = use_signal::<bool>(|| false);
let mut category_calendar_has_reminder = use_signal::<bool>(|| false);
let route = use_route::<Route>();
let mut selected_category = use_signal(|| match route {
Route::CategorySomedayMaybePage => Category::SomedayMaybe,
Route::CategoryWaitingForPage => Category::WaitingFor(String::new()),
Route::CategoryNextStepsPage => Category::NextSteps,
Route::CategoryCalendarPage | Route::CategoryTodayPage => Category::Calendar {
date: NaiveDate::default(),
reoccurrence: None,
time: None,
},
Route::CategoryLongTermPage => Category::LongTerm,
_ => Category::Inbox,
});
let mut category_calendar_reoccurrence_interval = use_signal(|| None);
let mut category_calendar_has_time = use_signal(|| false);
let mut category_calendar_reminder_offset_index = use_signal(|| REMINDER_OFFSETS.len() - 1);
rsx! {
form {
onsubmit: move |event| {
let categories = categories.clone();
async move {
let new_task = NewTask::new(
event.values().get("title").unwrap().as_value(),
event.values().get("deadline").unwrap().as_value().parse().ok(),
match &categories[
event.values().get("category_index").unwrap()
.as_value().parse::<usize>().unwrap()
] {
match &selected_category() {
Category::WaitingFor(_) => Category::WaitingFor(
event.values().get("category_waiting_for").unwrap()
.as_value()
@@ -47,24 +67,24 @@ pub(crate) fn TaskForm() -> Element {
Category::Calendar { .. } => Category::Calendar {
date: event.values().get("category_calendar_date").unwrap()
.as_value().parse().unwrap(),
reoccurance_interval:
event.values().get("category_calendar_is_reoccurring").map(
|_| Duration::days(
event.values().get("category_calendar_reoccurance_interval")
reoccurrence: category_calendar_reoccurrence_interval().map(
|reoccurrence_interval| Reoccurrence::new(
event.values().get("category_calendar_date").unwrap()
.as_value().parse().unwrap(),
reoccurrence_interval,
event.values().get("category_calendar_reoccurrence_length")
.unwrap().as_value().parse().unwrap()
)
),
time: event.values().get("category_calendar_time").unwrap()
.as_value().parse().ok().map(|time|
.as_value().parse().ok().map(|time|
CalendarTime::new(
time,
event.values().get("category_calendar_has_reminder").map(
|_| Duration::minutes(
event.values()
.get("category_calendar_reminder_offset").unwrap()
.as_value().parse().unwrap()
)
)
REMINDER_OFFSETS[
event.values()
.get("category_calendar_reminder_offset_index").unwrap()
.as_value().parse::<usize>().unwrap()
]
)
)
},
@@ -77,145 +97,207 @@ pub(crate) fn TaskForm() -> Element {
}
},
class: "p-4 flex flex-col gap-4",
input {
r#type: "text",
name: "title",
required: true,
placeholder: "title",
class: "p-2 bg-neutral-700 rounded",
},
select {
name: "category_index",
oninput: move |event| {
selected_category_index.set(event.value().parse().unwrap());
},
class: "p-2 bg-neutral-700 rounded",
option {
value: 0,
"inbox"
},
option {
value: 1,
"someday maybe"
},
option {
value: 2,
"waiting for"
},
option {
value: 3,
"next steps"
},
option {
value: 4,
"calendar"
},
option {
value: 5,
"long term"
},
},
match categories[selected_category_index()] {
Category::WaitingFor(_) => rsx !{
input {
r#type: "text",
name: "category_waiting_for",
required: true,
class: "p-2 bg-neutral-700 rounded",
div {
class: "flex flex-row items-center gap-3",
label {
r#for: "input_title",
class: "min-w-6 text-center",
i {
class: "fa-solid fa-pen-clip text-zinc-400/50"
},
},
Category::Calendar { .. } => rsx !{
input {
r#type: "date",
name: "category_calendar_date",
required: true,
class: "p-2 bg-neutral-700 rounded",
input {
r#type: "text",
name: "title",
required: true,
class: "py-2 px-3 grow bg-zinc-800/50 rounded-lg",
id: "input_title"
},
},
div {
class: "flex flex-row items-center gap-3",
label {
r#for: "input_project",
class: "min-w-6 text-center",
i {
class: "fa-solid fa-list text-zinc-400/50"
}
},
select {
name: "project_id",
class: "px-3.5 py-2.5 bg-zinc-800/50 rounded-lg grow",
id: "input_project",
option {
value: 0,
"None"
},
for project in projects {
option {
value: project.id().to_string(),
{project.title()}
}
}
},
},
div {
class: "flex flex-row items-center gap-3",
label {
r#for: "input_deadline",
class: "min-w-6 text-center",
i {
class: "fa-solid fa-bomb text-zinc-400/50"
}
},
input {
r#type: "date",
name: "deadline",
class: "py-2 px-3 bg-zinc-800/50 rounded-lg grow basis-0",
id: "input_deadline"
}
},
div {
class: "flex flex-row items-center gap-3",
label {
class: "min-w-6 text-center",
i {
class: "fa-solid fa-layer-group text-zinc-400/50"
}
},
CategoryInput {
selected_category: selected_category.clone(),
class: "grow"
}
}
match selected_category() {
Category::WaitingFor(_) => rsx! {
div {
input {
r#type: "checkbox",
name: "category_calendar_is_reoccurring",
id: "category_calendar_is_reoccurring",
onchange: move |event| {
category_calendar_is_reoccurring.set(event.checked());
class: "flex flex-row items-center gap-3",
label {
r#for: "input_deadline",
class: "min-w-6 text-center",
i {
class: "fa-solid fa-hourglass-end text-zinc-400/50"
}
},
label {
r#for: "category_calendar_is_reoccurring",
" is reoccurring"
}
},
if category_calendar_is_reoccurring() {
input {
r#type: "number",
name: "category_calendar_reoccurance_interval",
r#type: "text",
name: "category_waiting_for",
required: true,
min: 1,
placeholder: "reoccurance interval (days)",
class: "p-2 bg-neutral-700 rounded",
class: "py-2 px-3 bg-zinc-800/50 rounded-lg grow",
id: "input_category_waiting_for"
},
}
},
Category::Calendar { .. } => rsx! {
div {
class: "flex flex-row items-center gap-3",
label {
r#for: "input_category_calendar_date",
class: "min-w-6 text-center",
i {
class: "fa-solid fa-clock text-zinc-400/50"
}
},
div {
class: "grow flex flex-row gap-2",
input {
r#type: "date",
name: "category_calendar_date",
required: true,
initial_value: chrono::Local::now().format("%Y-%m-%d").to_string(),
class: "py-2 px-3 bg-zinc-800/50 rounded-lg grow",
id: "input_category_calendar_date"
},
input {
r#type: "time",
name: "category_calendar_time",
class: "py-2 px-3 bg-zinc-800/50 rounded-lg grow",
id: "input_category_calendar_time",
oninput: move |event| {
category_calendar_has_time.set(!event.value().is_empty());
}
}
}
},
input {
r#type: "time",
name: "category_calendar_time",
class: "p-2 bg-neutral-700 rounded",
oninput: move |event| {
category_calendar_has_time.set(!event.value().is_empty());
div {
class: "flex flex-row items-center gap-3",
label {
r#for: "category_calendar_reoccurrence_length",
class: "min-w-6 text-center",
i {
class: "fa-solid fa-repeat text-zinc-400/50"
}
},
div {
class: "grow grid grid-cols-6 gap-2",
ReoccurrenceIntervalInput {
reoccurrence_interval: category_calendar_reoccurrence_interval
},
input {
r#type: "number",
inputmode: "numeric",
name: "category_calendar_reoccurrence_length",
disabled: category_calendar_reoccurrence_interval().is_none(),
required: true,
min: 1,
initial_value:
if category_calendar_reoccurrence_interval().is_none() { "" }
else { "1" },
class: "py-2 px-3 bg-zinc-800/50 rounded-lg col-span-2 text-right",
id: "category_calendar_reoccurrence_length"
}
}
},
if category_calendar_has_time() {
div {
class: "flex flex-row items-center gap-3",
label {
r#for: "category_calendar_reminder_offset_index",
class: "min-w-6 text-center",
i {
class: "fa-solid fa-bell text-zinc-400/50"
}
},
input {
r#type: "checkbox",
name: "category_calendar_has_reminder",
value: 0,
r#type: "range",
name: "category_calendar_reminder_offset_index",
min: 0,
max: REMINDER_OFFSETS.len() as i64 - 1,
initial_value: REMINDER_OFFSETS.len() as i64 - 1,
class: "grow input-range-reverse",
id: "category_calendar_has_reminder",
onchange: move |event| {
category_calendar_has_reminder.set(event.checked());
oninput: move |event| {
category_calendar_reminder_offset_index.set(
event.value().parse().unwrap()
);
}
},
label {
r#for: "category_calendar_has_reminder",
" set a reminder"
r#for: "category_calendar_reminder_offset_index",
class: "pr-3 min-w-16 text-right",
{REMINDER_OFFSETS[category_calendar_reminder_offset_index()].map(
|offset| if offset.num_hours() < 1 {
format!("{} min", offset.num_minutes())
} else {
format!("{} h", offset.num_hours())
}
).unwrap_or_else(|| "none".to_string())}
}
}
}
if category_calendar_has_reminder() {
input {
r#type: "number",
name: "category_calendar_reminder_offset",
required: true,
min: 0,
placeholder: "reminder offset (minutes)",
class: "p-2 bg-neutral-700 rounded",
}
}
},
_ => None
},
input {
r#type: "date",
name: "deadline",
class: "p-2 bg-neutral-700 rounded",
},
select {
name: "project_id",
class: "p-2 bg-neutral-700 rounded",
option {
value: 0,
"none"
},
for project in projects {
option {
value: project.id().to_string(),
{project.title()}
div {
class: "flex flex-row justify-end mt-auto",
button {
r#type: "submit",
class: "py-2 px-4 bg-zinc-300/50 rounded-lg",
i {
class: "fa-solid fa-floppy-disk"
}
}
},
button {
r#type: "submit",
"create"
}
}
}
}
}