Skip to main content

max / makenotwork

3.0 KB · 103 lines History Blame Raw
1 //! The Askama entry point for the two described promo-code deletes.
2 //!
3 //! Shape 8 (`b279b9eb`), through the glue-module ruling `27d5e5b8`. Both
4 //! destroy and both ask; what differs is what they act on, which is what the
5 //! two prompts are for.
6 //!
7 //! `DELETE /api/promo-codes{,/id}` is a plain API route the description layer
8 //! does not serve. It answers the whole list rebuilt, so the control says where
9 //! that lands. See [`Action::replaces`].
10 //!
11 //! Ids arrive as `impl Display` rather than `&str`: the caller is Askama and
12 //! the server's ids are typed newtypes over `Uuid`, so asking for a string
13 //! would push a `to_string()` into every call site to say what `format!`
14 //! already says here.
15
16 use std::fmt;
17
18 use makeover_layout::Tone;
19 use quasi_router::screen::Act;
20 use quasi_router::{Action, Node};
21
22 /// The list both acts redraw.
23 const REGION: &str = "promo-codes-list";
24
25 /// Delete one code.
26 #[must_use]
27 pub fn html(code_id: impl fmt::Display) -> String {
28 fragment(
29 Act::new(
30 "Delete",
31 Action::delete(format!("/api/promo-codes/{code_id}")).replacing(REGION),
32 )
33 .tone(Tone::Danger)
34 .confirm("Delete this code? It will no longer be usable."),
35 )
36 }
37
38 /// Delete every code that has already run out.
39 ///
40 /// Its own act rather than the row act under a different address: it asks about
41 /// a set nobody has named on screen, and the prompt is the only place the
42 /// reader learns how much goes.
43 #[must_use]
44 pub fn expired_html() -> String {
45 fragment(
46 Act::new(
47 "Delete all expired",
48 Action::delete("/api/promo-codes/expired").replacing(REGION),
49 )
50 .tone(Tone::Danger)
51 .confirm("Delete all expired promo codes?"),
52 )
53 }
54
55 /// No shell and no region: this lands inside a document Askama has already
56 /// built, which is what every glue module here does.
57 fn fragment(act: Act) -> String {
58 use quasi_axum::Serves as _;
59
60 quasi_webview::Webview::new().fragment(&Node::Act(act))
61 }
62
63 #[cfg(test)]
64 mod tests {
65 #[test]
66 fn deleting_one_code_names_its_route_its_region_and_its_prompt() {
67 let html = super::html("11");
68
69 assert!(
70 html.contains(r#"hx-delete="/api/promo-codes/11""#),
71 "{html}"
72 );
73 assert!(
74 html.contains(r##"hx-target="#promo-codes-list""##),
75 "{html}"
76 );
77 assert!(
78 html.contains(r#"hx-confirm="Delete this code? It will no longer be usable.""#),
79 "{html}"
80 );
81 }
82
83 #[test]
84 fn the_bulk_delete_asks_about_the_set_it_acts_on() {
85 let html = super::expired_html();
86
87 assert!(
88 html.contains(r#"hx-delete="/api/promo-codes/expired""#),
89 "{html}"
90 );
91 assert!(
92 html.contains(r#"hx-confirm="Delete all expired promo codes?""#),
93 "{html}"
94 );
95 }
96
97 #[test]
98 fn both_deletes_say_they_are_dangerous() {
99 assert!(super::html("11").contains(r#"data-tone="danger""#));
100 assert!(super::expired_html().contains(r#"data-tone="danger""#));
101 }
102 }
103