@@ -447,6 +447,57 @@ fn handle_budget_view_key(app: &mut App, key: KeyEvent) -> Result<()> {
447447 app. open_dialog ( ActiveDialog :: AddGroup ) ;
448448 }
449449
450+ // Edit category group (Shift+E)
451+ KeyCode :: Char ( 'E' ) => {
452+ if let Some ( cat) = categories. get ( app. selected_category_index ) {
453+ app. open_dialog ( ActiveDialog :: EditGroup ( cat. group_id ) ) ;
454+ }
455+ }
456+
457+ // Delete category group (Shift+D)
458+ KeyCode :: Char ( 'D' ) => {
459+ if let Some ( cat) = categories. get ( app. selected_category_index ) {
460+ if let Ok ( Some ( group) ) = app. storage . categories . get_group ( cat. group_id ) {
461+ let group_categories = app
462+ . storage
463+ . categories
464+ . get_categories_in_group ( group. id )
465+ . unwrap_or_default ( ) ;
466+ let warning = if group_categories. is_empty ( ) {
467+ format ! ( "Delete group '{}'?" , group. name)
468+ } else {
469+ format ! (
470+ "Delete group '{}' and its {} categories?" ,
471+ group. name,
472+ group_categories. len( )
473+ )
474+ } ;
475+ app. open_dialog ( ActiveDialog :: Confirm ( warning) ) ;
476+ }
477+ }
478+ }
479+
480+ // Edit category
481+ KeyCode :: Char ( 'e' ) => {
482+ if let Some ( cat) = categories. get ( app. selected_category_index ) {
483+ app. selected_category = Some ( cat. id ) ;
484+ app. open_dialog ( ActiveDialog :: EditCategory ( cat. id ) ) ;
485+ }
486+ }
487+
488+ // Delete category
489+ KeyCode :: Char ( 'd' ) => {
490+ if let Some ( cat) = categories. get ( app. selected_category_index ) {
491+ app. selected_category = Some ( cat. id ) ;
492+ if let Ok ( Some ( category) ) = app. storage . categories . get_category ( cat. id ) {
493+ app. open_dialog ( ActiveDialog :: Confirm ( format ! (
494+ "Delete category '{}'?" ,
495+ category. name
496+ ) ) ) ;
497+ }
498+ }
499+ }
500+
450501 // Open unified budget dialog (period budget + target)
451502 KeyCode :: Enter | KeyCode :: Char ( 'b' ) | KeyCode :: Char ( 't' ) => {
452503 if let Some ( cat) = categories. get ( app. selected_category_index ) {
@@ -705,6 +756,43 @@ fn execute_command_action(app: &mut App, action: CommandAction) -> Result<()> {
705756 app. set_status ( "No category selected" . to_string ( ) ) ;
706757 }
707758 }
759+ CommandAction :: EditGroup => {
760+ // Edit the group of the currently selected category
761+ if let Some ( category_id) = app. selected_category {
762+ if let Ok ( Some ( category) ) = app. storage . categories . get_category ( category_id) {
763+ app. open_dialog ( ActiveDialog :: EditGroup ( category. group_id ) ) ;
764+ }
765+ } else {
766+ app. set_status ( "No category selected. Switch to Budget view first." . to_string ( ) ) ;
767+ }
768+ }
769+ CommandAction :: DeleteGroup => {
770+ // Delete the group of the currently selected category with confirmation
771+ if let Some ( category_id) = app. selected_category {
772+ if let Ok ( Some ( category) ) = app. storage . categories . get_category ( category_id) {
773+ if let Ok ( Some ( group) ) = app. storage . categories . get_group ( category. group_id ) {
774+ // Check if group has categories
775+ let categories = app
776+ . storage
777+ . categories
778+ . get_categories_in_group ( group. id )
779+ . unwrap_or_default ( ) ;
780+ let warning = if categories. is_empty ( ) {
781+ format ! ( "Delete group '{}'?" , group. name)
782+ } else {
783+ format ! (
784+ "Delete group '{}' and its {} categories?" ,
785+ group. name,
786+ categories. len( )
787+ )
788+ } ;
789+ app. open_dialog ( ActiveDialog :: Confirm ( warning) ) ;
790+ }
791+ }
792+ } else {
793+ app. set_status ( "No category selected" . to_string ( ) ) ;
794+ }
795+ }
708796
709797 // General
710798 CommandAction :: Help => {
@@ -844,7 +932,7 @@ fn handle_dialog_key(app: &mut App, key: KeyEvent) -> Result<()> {
844932 ActiveDialog :: AddCategory | ActiveDialog :: EditCategory ( _) => {
845933 super :: dialogs:: category:: handle_key ( app, key) ;
846934 }
847- ActiveDialog :: AddGroup => {
935+ ActiveDialog :: AddGroup | ActiveDialog :: EditGroup ( _ ) => {
848936 super :: dialogs:: group:: handle_key ( app, key) ;
849937 }
850938 ActiveDialog :: None => { }
@@ -933,6 +1021,27 @@ fn execute_confirmed_action(app: &mut App, message: &str) -> Result<()> {
9331021 }
9341022 }
9351023 }
1024+ // Delete group
1025+ else if message. contains ( "Delete group" ) {
1026+ if let Some ( category_id) = app. selected_category {
1027+ use crate :: services:: CategoryService ;
1028+ if let Ok ( Some ( category) ) = app. storage . categories . get_category ( category_id) {
1029+ let group_id = category. group_id ;
1030+ let category_service = CategoryService :: new ( app. storage ) ;
1031+ // force_delete_categories = true since user confirmed
1032+ match category_service. delete_group ( group_id, true ) {
1033+ Ok ( ( ) ) => {
1034+ app. set_status ( "Category group deleted" . to_string ( ) ) ;
1035+ app. selected_category = None ;
1036+ app. selected_category_index = 0 ;
1037+ }
1038+ Err ( e) => {
1039+ app. set_status ( format ! ( "Failed to delete: {}" , e) ) ;
1040+ }
1041+ }
1042+ }
1043+ }
1044+ }
9361045
9371046 Ok ( ( ) )
9381047}
0 commit comments