app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 321e528d8fd11eb64296cd22f36bc5015f5af560
parent 64c17a7134590e43b8c2a4ddfc403403b5eb8c81
Author: triesap <tyson@radroots.org>
Date:   Sat,  6 Jun 2026 22:44:08 -0700

app: reopen focused order details

Diffstat:
Mcrates/desktop/src/window.rs | 191++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 165 insertions(+), 26 deletions(-)

diff --git a/crates/desktop/src/window.rs b/crates/desktop/src/window.rs @@ -155,6 +155,43 @@ enum HomeFocusedView { BuyerReceiptIssue(OrderId), } +fn buyer_order_detail_focus_after_open( + runtime_changed: bool, + runtime: &DesktopAppRuntimeSummary, + order_id: OrderId, +) -> Option<HomeFocusedView> { + if runtime_changed + || runtime + .personal_projection + .orders + .detail + .as_ref() + .is_some_and(|detail| detail.order_id == order_id) + { + Some(HomeFocusedView::BuyerOrderDetail(order_id)) + } else { + None + } +} + +fn farmer_order_detail_focus_after_open( + runtime_changed: bool, + runtime: &DesktopAppRuntimeSummary, + order_id: OrderId, +) -> Option<HomeFocusedView> { + if runtime_changed + || runtime + .orders_projection + .detail + .as_ref() + .is_some_and(|detail| detail.order_id == order_id) + { + Some(HomeFocusedView::FarmerOrderDetail(order_id)) + } else { + None + } +} + pub fn home_window_options(cx: &mut App) -> WindowOptions { let (launch_width_px, launch_height_px) = home_window_launch_size_px(); let (minimum_width_px, minimum_height_px) = home_window_minimum_size_px(); @@ -1709,7 +1746,14 @@ impl HomeView { fn open_personal_order_detail(&mut self, order_id: OrderId, cx: &mut Context<Self>) { match self.runtime.open_personal_order_detail(order_id) { - Ok(true) => { + Ok(runtime_changed) => { + let Some(focused_view) = buyer_order_detail_focus_after_open( + runtime_changed, + &self.runtime.summary(), + order_id, + ) else { + return; + }; if self .buyer_receipt_issue_form .as_ref() @@ -1717,10 +1761,9 @@ impl HomeView { { self.buyer_receipt_issue_form = None; } - self.focused_view = Some(HomeFocusedView::BuyerOrderDetail(order_id)); + self.focused_view = Some(focused_view); cx.notify(); } - Ok(false) => {} Err(runtime_error) => { error!( target: "buyer", @@ -2117,13 +2160,19 @@ impl HomeView { fn open_order_detail(&mut self, order_id: OrderId, cx: &mut Context<Self>) { match self.runtime.open_order_detail(order_id) { - Ok(true) => { + Ok(runtime_changed) => { + let Some(focused_view) = farmer_order_detail_focus_after_open( + runtime_changed, + &self.runtime.summary(), + order_id, + ) else { + return; + }; self.products_stock_editor = None; self.product_editor_form = None; - self.focused_view = Some(HomeFocusedView::FarmerOrderDetail(order_id)); + self.focused_view = Some(focused_view); cx.notify(); } - Ok(false) => {} Err(runtime_error) => { error!( target: "orders", @@ -13735,7 +13784,7 @@ fn home_farm_order_method_label_key(method: FarmOrderMethod) -> AppTextKey { mod tests { use super::{ APP_UI_THEME, AppTextKey, BuyerWorkspaceNotice, FarmerHomeFarmState, HomeAutoFocusState, - HomeAutoFocusTarget, HomeStage, HomeView, LabelValueRow, + HomeAutoFocusTarget, HomeFocusedView, HomeStage, HomeView, LabelValueRow, PackDayBatchPrintActionPresentation, PackDayBatchPrintStatusPresentation, PackDayExportStatusPresentation, PackDayHostHandoffActionPresentation, PackDayHostHandoffStatusPresentation, PackDayPrintActionPresentation, @@ -13745,25 +13794,27 @@ mod tests { StartupSignerConnectState, about_conflict_action_specs, about_conflict_aggregate_text, about_conflict_detail_rows, about_conflict_review_body_key, about_manual_refresh_enabled, about_runtime_rows, about_status_rows, app_text, - buyer_order_coordination_notice_forces_redraw, buyer_orders_retry_action_visible, - buyer_receipt_status_key, farm_setup_onboarding_card_spec, farmer_home_farm_state, - farmer_pack_day_available, home_auto_focus_target, home_content_scroll_id, home_saved_farm, - home_sidebar_navigation_sections, home_stage, home_window_launch_size_px, - home_window_minimum_size_px, pack_day_batch_print_action_presentation, - pack_day_batch_print_status_presentation, pack_day_export_action_enabled, - pack_day_export_action_label_key, pack_day_export_artifact_names, - pack_day_export_detail_rows, pack_day_export_status_presentation, - pack_day_host_handoff_action_presentations, pack_day_host_handoff_status_presentation, - pack_day_print_action_presentations, pack_day_print_status_presentation, - parse_optional_product_editor_stock_input, parse_product_editor_price_input, - presented_farmer_reminder, product_display_title, reminder_action_target, - reminder_deadline_text, reminder_delivery_state_key, reminder_urgency_color, - reminder_urgency_key, settings_auto_focus_target, startup_home_surface, - startup_issue_summary_text, startup_notice_text, startup_signer_preview_summary, - startup_signer_preview_summary_for_connect_state, startup_signer_source_input_is_editable, - startup_signer_status_spec, startup_signer_transport_failure_requires_notice, - trade_agreement_status_key, trade_fulfillment_status_key, trade_inventory_status_key, - trade_payment_display_status_key, trade_revision_status_key, trade_workflow_source_key, + buyer_order_coordination_notice_forces_redraw, buyer_order_detail_focus_after_open, + buyer_orders_retry_action_visible, buyer_receipt_status_key, + farm_setup_onboarding_card_spec, farmer_home_farm_state, + farmer_order_detail_focus_after_open, farmer_pack_day_available, home_auto_focus_target, + home_content_scroll_id, home_saved_farm, home_sidebar_navigation_sections, home_stage, + home_window_launch_size_px, home_window_minimum_size_px, + pack_day_batch_print_action_presentation, pack_day_batch_print_status_presentation, + pack_day_export_action_enabled, pack_day_export_action_label_key, + pack_day_export_artifact_names, pack_day_export_detail_rows, + pack_day_export_status_presentation, pack_day_host_handoff_action_presentations, + pack_day_host_handoff_status_presentation, pack_day_print_action_presentations, + pack_day_print_status_presentation, parse_optional_product_editor_stock_input, + parse_product_editor_price_input, presented_farmer_reminder, product_display_title, + reminder_action_target, reminder_deadline_text, reminder_delivery_state_key, + reminder_urgency_color, reminder_urgency_key, settings_auto_focus_target, + startup_home_surface, startup_issue_summary_text, startup_notice_text, + startup_signer_preview_summary, startup_signer_preview_summary_for_connect_state, + startup_signer_source_input_is_editable, startup_signer_status_spec, + startup_signer_transport_failure_requires_notice, trade_agreement_status_key, + trade_fulfillment_status_key, trade_inventory_status_key, trade_payment_display_status_key, + trade_revision_status_key, trade_workflow_source_key, }; use crate::runtime::{ DesktopAppRuntimeMetadataSummary, DesktopAppRuntimeSummary, DesktopAppSyncConflictSummary, @@ -13933,6 +13984,94 @@ mod tests { } #[test] + fn buyer_order_detail_focus_reopens_same_selected_detail() { + let order_id = OrderId::new(); + let farm_id = FarmId::new(); + let mut runtime = summary( + HomeRoute::Personal, + TodayAgendaProjection::default(), + FarmSetupProjection::default(), + ); + + assert_eq!( + buyer_order_detail_focus_after_open(false, &runtime, order_id), + None + ); + + runtime.personal_projection.orders.detail = Some(BuyerOrderDetailProjection { + order_id, + farm_id, + order_number: String::new(), + farm_display_name: String::new(), + fulfillment_summary: String::new(), + status: BuyerOrderStatus::Placed, + items: Vec::new(), + economics: TradeEconomicsProjection::default(), + payment: TradePaymentDisplayStatus::NotRecorded, + workflow: TradeWorkflowProjection::from_buyer_order_status( + order_id, + BuyerOrderStatus::Placed, + ), + validation_receipts: Vec::new(), + order_note: None, + repeat_demand: None, + }); + + assert_eq!( + buyer_order_detail_focus_after_open(false, &runtime, order_id), + Some(HomeFocusedView::BuyerOrderDetail(order_id)) + ); + assert_eq!( + buyer_order_detail_focus_after_open(false, &runtime, OrderId::new()), + None + ); + } + + #[test] + fn farmer_order_detail_focus_reopens_same_selected_detail() { + let order_id = OrderId::new(); + let farm_id = FarmId::new(); + let mut runtime = summary( + HomeRoute::Today, + TodayAgendaProjection::default(), + FarmSetupProjection::default(), + ); + + assert_eq!( + farmer_order_detail_focus_after_open(false, &runtime, order_id), + None + ); + + runtime.orders_projection.detail = Some(OrderDetailProjection { + order_id, + farm_id, + order_number: String::new(), + customer_display_name: String::new(), + status: OrderStatus::Scheduled, + fulfillment_window_id: None, + fulfillment_window_label: None, + pickup_location_label: None, + items: Vec::new(), + economics: TradeEconomicsProjection::default(), + payment: TradePaymentDisplayStatus::NotRecorded, + workflow: TradeWorkflowProjection::from_order_status(order_id, OrderStatus::Scheduled), + validation_receipts: Vec::new(), + primary_action: Some(OrderPrimaryAction::PublishPreparing), + fulfillment_actions: OrderFulfillmentAction::ALL.to_vec(), + recoveries: Vec::new(), + }); + + assert_eq!( + farmer_order_detail_focus_after_open(false, &runtime, order_id), + Some(HomeFocusedView::FarmerOrderDetail(order_id)) + ); + assert_eq!( + farmer_order_detail_focus_after_open(false, &runtime, OrderId::new()), + None + ); + } + + #[test] fn buyer_browse_refresh_failure_uses_typed_visible_notice() { let (mut view, paths, home_dir) = test_home_view("buyer_notice"); block_shared_local_events_database(&paths);