The submit closure mixed pure decision logic (what should the form show after subscribe_feed resolves) with Dioxus signal orchestration. Splits out resolve_submit_outcome(Result<usize, String>) -> SubmitOutcome, so the success/failure mapping is unit-tested without a Dioxus runtime; the component now just applies the resulting outcome to its signals. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
77 lines
2.4 KiB
Rust
77 lines
2.4 KiB
Rust
/// Trims a feed URL entered by the user, returning `None` when it's blank
|
|
/// so the submit handler can bail out before making a request.
|
|
pub fn normalize_feed_url(input: &str) -> Option<String> {
|
|
let trimmed = input.trim();
|
|
if trimmed.is_empty() {
|
|
None
|
|
} else {
|
|
Some(trimmed.to_string())
|
|
}
|
|
}
|
|
|
|
/// Success message shown after a feed subscription pulls in new articles.
|
|
fn subscribed_message(article_count: usize) -> String {
|
|
format!("Subscribed — pulled in {article_count} article(s).")
|
|
}
|
|
|
|
/// What the form should show, and whether the URL input should be cleared,
|
|
/// after a subscription attempt resolves.
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum SubmitOutcome {
|
|
/// The subscription succeeded: show `message` and clear the input.
|
|
Success { message: String },
|
|
/// The subscription failed: show `message` and leave the input as-is,
|
|
/// so the reader can fix it up and retry.
|
|
Failure { message: String },
|
|
}
|
|
|
|
/// Maps a `subscribe_feed` result to what the form should do next.
|
|
pub fn resolve_submit_outcome(result: Result<usize, String>) -> SubmitOutcome {
|
|
match result {
|
|
Ok(count) => SubmitOutcome::Success {
|
|
message: subscribed_message(count),
|
|
},
|
|
Err(message) => SubmitOutcome::Failure { message },
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn blank_input_normalizes_to_none() {
|
|
assert_eq!(normalize_feed_url(""), None);
|
|
assert_eq!(normalize_feed_url(" "), None);
|
|
}
|
|
|
|
#[test]
|
|
fn surrounding_whitespace_is_trimmed() {
|
|
assert_eq!(
|
|
normalize_feed_url(" https://example.com/feed.xml "),
|
|
Some("https://example.com/feed.xml".to_string())
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn success_reports_the_article_count_and_clears_the_input() {
|
|
assert_eq!(
|
|
resolve_submit_outcome(Ok(3)),
|
|
SubmitOutcome::Success {
|
|
message: "Subscribed — pulled in 3 article(s).".to_string()
|
|
}
|
|
);
|
|
}
|
|
|
|
/// A failed attempt should surface the error but leave the input alone
|
|
/// so the reader doesn't have to retype the URL to fix it.
|
|
#[test]
|
|
fn failure_surfaces_the_error_message() {
|
|
assert_eq!(
|
|
resolve_submit_outcome(Err("feed unreachable".to_string())),
|
|
SubmitOutcome::Failure {
|
|
message: "feed unreachable".to_string()
|
|
}
|
|
);
|
|
}
|
|
}
|