1use tracing::warn;
7
8use crate::api::ApiClient;
9use crate::cache::CacheManager;
10use crate::cache::offline::CacheProgress;
11use crate::models::{
12 Adult, AdvancementDashboard, Commissioner, Event, Key3Leaders,
13 OrgProfile, Parent, Patrol, UnitInfo, Youth,
14};
15
16pub struct RefreshResult {
18 pub youth: Option<Vec<Youth>>,
19 pub adults: Option<Vec<Adult>>,
20 pub events: Option<Vec<Event>>,
21 pub patrols: Option<Vec<Patrol>>,
22 pub unit_info: Option<UnitInfo>,
23 pub key3: Option<Key3Leaders>,
24 pub commissioners: Option<Vec<Commissioner>>,
25 pub org_profile: Option<OrgProfile>,
26 pub parents: Option<Vec<Parent>>,
27 pub advancement: Option<AdvancementDashboard>,
28 pub errors: Vec<String>,
29 pub successes: u32,
30}
31
32pub async fn refresh_base_data(
37 api: &ApiClient,
38 cache: &CacheManager,
39 org_guid: &str,
40 user_id: i64,
41 on_progress: impl Fn(CacheProgress),
42) -> RefreshResult {
43 let total = 10u32;
44 let mut errors: Vec<String> = Vec::new();
45 let mut successes = 0u32;
46
47 on_progress(CacheProgress {
48 current: 0,
49 total,
50 description: "Refreshing data...".into(),
51 });
52
53 let (
55 youth_res, adults_res, events_res, patrols_res, unit_info_res,
56 key3_res, commissioners_res, org_profile_res, parents_res, advancement_res,
57 ) = tokio::join!(
58 api.fetch_youth(org_guid),
59 api.fetch_adults(org_guid),
60 api.fetch_events(user_id),
61 api.fetch_patrols(org_guid),
62 api.fetch_unit_pin(org_guid),
63 api.fetch_key3(org_guid),
64 api.fetch_commissioners(org_guid),
65 api.fetch_org_profile(org_guid),
66 api.fetch_parents(org_guid),
67 api.fetch_advancement_dashboard(org_guid),
68 );
69
70 macro_rules! process {
72 ($label:expr, $step:expr, $result:expr, $save:expr) => {{
73 on_progress(CacheProgress {
74 current: $step,
75 total,
76 description: format!("Processing {}...", $label),
77 });
78 match $result {
79 Ok(data) => {
80 let _ = $save(&data);
81 successes += 1;
82 Some(data)
83 }
84 Err(e) => {
85 let msg = format!("{}: {}", $label, e);
86 warn!("{}", msg);
87 errors.push(msg);
88 None
89 }
90 }
91 }};
92 }
93
94 let youth = process!("scouts", 1, youth_res, |d: &Vec<Youth>| cache.save_youth(d));
95
96 let adults = {
98 on_progress(CacheProgress {
99 current: 2,
100 total,
101 description: "Processing adults...".into(),
102 });
103 match adults_res {
104 Ok(data) => {
105 let deduped = Adult::deduplicate(data);
106 if let Err(e) = cache.save_adults(&deduped) {
107 warn!("Failed to save adults to cache: {e}");
108 }
109 successes += 1;
110 Some(deduped)
111 }
112 Err(e) => {
113 let msg = format!("adults: {}", e);
114 warn!("{}", msg);
115 errors.push(msg);
116 None
117 }
118 }
119 };
120
121 let events = process!("events", 3, events_res, |d: &Vec<Event>| cache.save_events(d));
122 let patrols = process!("patrols", 4, patrols_res, |d: &Vec<Patrol>| cache.save_patrols(d));
123 let unit_info = process!("unit info", 5, unit_info_res, |d: &UnitInfo| cache.save_unit_info(d));
124 let key3 = process!("Key 3", 6, key3_res, |d: &Key3Leaders| cache.save_key3(d));
125 let commissioners = process!("commissioners", 7, commissioners_res, |d: &Vec<Commissioner>| cache.save_commissioners(d));
126 let org_profile = process!("org profile", 8, org_profile_res, |d: &OrgProfile| cache.save_org_profile(d));
127 let parents = process!("parents", 9, parents_res, |d: &Vec<Parent>| cache.save_parents(d));
128 let advancement = process!("advancement", 10, advancement_res, |d: &AdvancementDashboard| cache.save_advancement_dashboard(d));
129
130 on_progress(CacheProgress {
131 current: total,
132 total,
133 description: "Refresh complete".into(),
134 });
135
136 RefreshResult {
137 youth,
138 adults,
139 events,
140 patrols,
141 unit_info,
142 key3,
143 commissioners,
144 org_profile,
145 parents,
146 advancement,
147 errors,
148 successes,
149 }
150}