From 7ec23699a8ce4ac4548e5de923ebc735a543d37c Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Mon, 12 Aug 2024 16:05:57 +0200
Subject: [PATCH] feat: adds some Navigator actions

---
 src/navigator.rs | 174 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 127 insertions(+), 47 deletions(-)

diff --git a/src/navigator.rs b/src/navigator.rs
index 5ca2d23..5bb58cf 100644
--- a/src/navigator.rs
+++ b/src/navigator.rs
@@ -1,39 +1,64 @@
-use anyhow::{anyhow, Result, Context, Ok};
+use anyhow::{anyhow, Context, Ok, Result};
 use std::rc::Rc;
 
-use crate::{ui::{Page, HomePage, EpicDetail, StoryDetail, Prompts}, db::JiraDatabase, models::Action};
+use crate::{
+    db::JiraDatabase,
+    models::Action,
+    ui::{EpicDetail, HomePage, Page, Prompts, StoryDetail},
+};
 
 pub struct Navigator {
     pages: Vec<Box<dyn Page>>,
     prompts: Prompts,
-    db: Rc<JiraDatabase>
+    db: Rc<JiraDatabase>,
 }
 
 impl Navigator {
     pub fn new(db: Rc<JiraDatabase>) -> Self {
-        todo!()
+        Self {
+            pages: vec![],
+            prompts: Prompts::new(),
+            db,
+        }
     }
 
     pub fn get_current_page(&self) -> Option<&Box<dyn Page>> {
-        todo!() // this should always return the last element in the pages vector
+        self.pages.last()
     }
 
     pub fn handle_action(&mut self, action: Action) -> Result<()> {
         match action {
             Action::NavigateToEpicDetail { epic_id } => {
-                todo!() // create a new EpicDetail instance and add it to the pages vector
+                // create a new EpicDetail instance and add it to the pages vector
+                self.pages.push(Box::new(EpicDetail {
+                    epic_id,
+                    db: Rc::clone(&self.db),
+                }));
             }
             Action::NavigateToStoryDetail { epic_id, story_id } => {
-                todo!() // create a new StoryDetail instance and add it to the pages vector
+                // create a new StoryDetail instance and add it to the pages vector
+                self.pages.push(Box::new(StoryDetail {
+                    epic_id,
+                    story_id,
+                    db: Rc::clone(&self.db),
+                }));
             }
             Action::NavigateToPreviousPage => {
-                todo!() // remove the last page from the pages vector
+                // remove the last page from the pages vector
+                let _ = self.pages.pop();
             }
             Action::CreateEpic => {
-                todo!() // prompt the user to create a new epic and persist it in the database
+                // prompt the user to create a new epic and persist it in the database
+                self.db.create_epic((self.prompts.create_epic)());
             }
             Action::UpdateEpicStatus { epic_id } => {
-                todo!() // prompt the user to update status and persist it in the database
+                todo!(); // prompt the user to update status and persist it in the database
+                         // let status = (self.prompts.update_status)().(|| {
+                         //     return Err(anyhow!("failed to update epic status")
+                         //         .context(format!("invalid status given")));
+                         // });
+                self.db
+                    .update_epic_status(epic_id, crate::models::Status::Open);
             }
             Action::DeleteEpic { epic_id } => {
                 todo!() // prompt the user to delete the epic and persist it in the database
@@ -48,8 +73,9 @@ impl Navigator {
                 todo!() // prompt the user to delete the story and persist it in the database
             }
             Action::Exit => {
-                todo!() // remove all pages from the pages vector
-            },
+                // remove all pages from the pages vector
+                self.pages.clear();
+            }
         }
 
         Ok(())
@@ -68,12 +94,17 @@ impl Navigator {
 
 #[cfg(test)]
 mod tests {
-    use crate::{db::test_utils::MockDB, models::{Epic, Status, Story}};
     use super::*;
+    use crate::{
+        db::test_utils::MockDB,
+        models::{Epic, Status, Story},
+    };
 
     #[test]
     fn should_start_on_home_page() {
-        let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) });
+        let db = Rc::new(JiraDatabase {
+            database: Box::new(MockDB::new()),
+        });
         let nav = Navigator::new(db);
 
         assert_eq!(nav.get_page_count(), 1);
@@ -86,18 +117,25 @@ mod tests {
 
     #[test]
     fn handle_action_should_navigate_pages() {
-        let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) });
+        let db = Rc::new(JiraDatabase {
+            database: Box::new(MockDB::new()),
+        });
 
         let mut nav = Navigator::new(db);
-        
-        nav.handle_action(Action::NavigateToEpicDetail { epic_id: 1 }).unwrap();
+
+        nav.handle_action(Action::NavigateToEpicDetail { epic_id: 1 })
+            .unwrap();
         assert_eq!(nav.get_page_count(), 2);
 
         let current_page = nav.get_current_page().unwrap();
         let epic_detail_page = current_page.as_any().downcast_ref::<EpicDetail>();
         assert_eq!(epic_detail_page.is_some(), true);
 
-        nav.handle_action(Action::NavigateToStoryDetail { epic_id: 1, story_id: 2 }).unwrap();
+        nav.handle_action(Action::NavigateToStoryDetail {
+            epic_id: 1,
+            story_id: 2,
+        })
+        .unwrap();
         assert_eq!(nav.get_page_count(), 3);
 
         let current_page = nav.get_current_page().unwrap();
@@ -127,12 +165,19 @@ mod tests {
 
     #[test]
     fn handle_action_should_clear_pages_on_exit() {
-        let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) });
+        let db = Rc::new(JiraDatabase {
+            database: Box::new(MockDB::new()),
+        });
 
         let mut nav = Navigator::new(db);
-        
-        nav.handle_action(Action::NavigateToEpicDetail { epic_id: 1 }).unwrap();
-        nav.handle_action(Action::NavigateToStoryDetail { epic_id: 1, story_id: 2 }).unwrap();
+
+        nav.handle_action(Action::NavigateToEpicDetail { epic_id: 1 })
+            .unwrap();
+        nav.handle_action(Action::NavigateToStoryDetail {
+            epic_id: 1,
+            story_id: 2,
+        })
+        .unwrap();
         nav.handle_action(Action::Exit).unwrap();
 
         assert_eq!(nav.get_page_count(), 0);
@@ -140,7 +185,9 @@ mod tests {
 
     #[test]
     fn handle_action_should_handle_create_epic() {
-        let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) });
+        let db = Rc::new(JiraDatabase {
+            database: Box::new(MockDB::new()),
+        });
 
         let mut nav = Navigator::new(Rc::clone(&db));
 
@@ -148,7 +195,7 @@ mod tests {
         prompts.create_epic = Box::new(|| Epic::new("name".to_owned(), "description".to_owned()));
 
         nav.set_prompts(prompts);
-        
+
         nav.handle_action(Action::CreateEpic).unwrap();
 
         let db_state = db.read_db().unwrap();
@@ -161,8 +208,12 @@ mod tests {
 
     #[test]
     fn handle_action_should_handle_update_epic() {
-        let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) });
-        let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap();
+        let db = Rc::new(JiraDatabase {
+            database: Box::new(MockDB::new()),
+        });
+        let epic_id = db
+            .create_epic(Epic::new("".to_owned(), "".to_owned()))
+            .unwrap();
 
         let mut nav = Navigator::new(Rc::clone(&db));
 
@@ -170,17 +221,25 @@ mod tests {
         prompts.update_status = Box::new(|| Some(Status::InProgress));
 
         nav.set_prompts(prompts);
-        
-        nav.handle_action(Action::UpdateEpicStatus { epic_id }).unwrap();
+
+        nav.handle_action(Action::UpdateEpicStatus { epic_id })
+            .unwrap();
 
         let db_state = db.read_db().unwrap();
-        assert_eq!(db_state.epics.get(&epic_id).unwrap().status, Status::InProgress);
+        assert_eq!(
+            db_state.epics.get(&epic_id).unwrap().status,
+            Status::InProgress
+        );
     }
 
     #[test]
     fn handle_action_should_handle_delete_epic() {
-        let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) });
-        let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap();
+        let db = Rc::new(JiraDatabase {
+            database: Box::new(MockDB::new()),
+        });
+        let epic_id = db
+            .create_epic(Epic::new("".to_owned(), "".to_owned()))
+            .unwrap();
 
         let mut nav = Navigator::new(Rc::clone(&db));
 
@@ -188,7 +247,7 @@ mod tests {
         prompts.delete_epic = Box::new(|| true);
 
         nav.set_prompts(prompts);
-        
+
         nav.handle_action(Action::DeleteEpic { epic_id }).unwrap();
 
         let db_state = db.read_db().unwrap();
@@ -197,8 +256,12 @@ mod tests {
 
     #[test]
     fn handle_action_should_handle_create_story() {
-        let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) });
-        let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap();
+        let db = Rc::new(JiraDatabase {
+            database: Box::new(MockDB::new()),
+        });
+        let epic_id = db
+            .create_epic(Epic::new("".to_owned(), "".to_owned()))
+            .unwrap();
 
         let mut nav = Navigator::new(Rc::clone(&db));
 
@@ -206,7 +269,7 @@ mod tests {
         prompts.create_story = Box::new(|| Story::new("name".to_owned(), "description".to_owned()));
 
         nav.set_prompts(prompts);
-        
+
         nav.handle_action(Action::CreateStory { epic_id }).unwrap();
 
         let db_state = db.read_db().unwrap();
@@ -219,9 +282,15 @@ mod tests {
 
     #[test]
     fn handle_action_should_handle_update_story() {
-        let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) });
-        let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap();
-        let story_id = db.create_story(Story::new("".to_owned(), "".to_owned()), epic_id).unwrap();
+        let db = Rc::new(JiraDatabase {
+            database: Box::new(MockDB::new()),
+        });
+        let epic_id = db
+            .create_epic(Epic::new("".to_owned(), "".to_owned()))
+            .unwrap();
+        let story_id = db
+            .create_story(Story::new("".to_owned(), "".to_owned()), epic_id)
+            .unwrap();
 
         let mut nav = Navigator::new(Rc::clone(&db));
 
@@ -229,18 +298,28 @@ mod tests {
         prompts.update_status = Box::new(|| Some(Status::InProgress));
 
         nav.set_prompts(prompts);
-        
-        nav.handle_action(Action::UpdateStoryStatus { story_id }).unwrap();
+
+        nav.handle_action(Action::UpdateStoryStatus { story_id })
+            .unwrap();
 
         let db_state = db.read_db().unwrap();
-        assert_eq!(db_state.stories.get(&story_id).unwrap().status, Status::InProgress);
+        assert_eq!(
+            db_state.stories.get(&story_id).unwrap().status,
+            Status::InProgress
+        );
     }
 
     #[test]
     fn handle_action_should_handle_delete_story() {
-        let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) });
-        let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap();
-        let story_id = db.create_story(Story::new("".to_owned(), "".to_owned()), epic_id).unwrap();
+        let db = Rc::new(JiraDatabase {
+            database: Box::new(MockDB::new()),
+        });
+        let epic_id = db
+            .create_epic(Epic::new("".to_owned(), "".to_owned()))
+            .unwrap();
+        let story_id = db
+            .create_story(Story::new("".to_owned(), "".to_owned()), epic_id)
+            .unwrap();
 
         let mut nav = Navigator::new(Rc::clone(&db));
 
@@ -248,10 +327,11 @@ mod tests {
         prompts.delete_story = Box::new(|| true);
 
         nav.set_prompts(prompts);
-        
-        nav.handle_action(Action::DeleteStory { epic_id, story_id }).unwrap();
+
+        nav.handle_action(Action::DeleteStory { epic_id, story_id })
+            .unwrap();
 
         let db_state = db.read_db().unwrap();
         assert_eq!(db_state.stories.len(), 0);
     }
-}
\ No newline at end of file
+}