1use crate::block::Block;
4use crate::field::{Field, Select, TextInput};
5use crate::validation::rules::Pattern;
6
7const US_STATES: &[(&str, &str)] = &[
9 ("AL", "Alabama"),
10 ("AK", "Alaska"),
11 ("AZ", "Arizona"),
12 ("AR", "Arkansas"),
13 ("CA", "California"),
14 ("CO", "Colorado"),
15 ("CT", "Connecticut"),
16 ("DE", "Delaware"),
17 ("FL", "Florida"),
18 ("GA", "Georgia"),
19 ("HI", "Hawaii"),
20 ("ID", "Idaho"),
21 ("IL", "Illinois"),
22 ("IN", "Indiana"),
23 ("IA", "Iowa"),
24 ("KS", "Kansas"),
25 ("KY", "Kentucky"),
26 ("LA", "Louisiana"),
27 ("ME", "Maine"),
28 ("MD", "Maryland"),
29 ("MA", "Massachusetts"),
30 ("MI", "Michigan"),
31 ("MN", "Minnesota"),
32 ("MS", "Mississippi"),
33 ("MO", "Missouri"),
34 ("MT", "Montana"),
35 ("NE", "Nebraska"),
36 ("NV", "Nevada"),
37 ("NH", "New Hampshire"),
38 ("NJ", "New Jersey"),
39 ("NM", "New Mexico"),
40 ("NY", "New York"),
41 ("NC", "North Carolina"),
42 ("ND", "North Dakota"),
43 ("OH", "Ohio"),
44 ("OK", "Oklahoma"),
45 ("OR", "Oregon"),
46 ("PA", "Pennsylvania"),
47 ("RI", "Rhode Island"),
48 ("SC", "South Carolina"),
49 ("SD", "South Dakota"),
50 ("TN", "Tennessee"),
51 ("TX", "Texas"),
52 ("UT", "Utah"),
53 ("VT", "Vermont"),
54 ("VA", "Virginia"),
55 ("WA", "Washington"),
56 ("WV", "West Virginia"),
57 ("WI", "Wisconsin"),
58 ("WY", "Wyoming"),
59 ("DC", "District of Columbia"),
60];
61
62pub struct AddressBlock {
64 prefix: String,
65 title: Option<String>,
66 required: bool,
67}
68
69impl AddressBlock {
70 pub fn new(prefix: impl Into<String>) -> Self {
72 Self {
73 prefix: prefix.into(),
74 title: None,
75 required: false,
76 }
77 }
78
79 pub fn title(mut self, title: impl Into<String>) -> Self {
81 self.title = Some(title.into());
82 self
83 }
84
85 pub fn required(mut self) -> Self {
87 self.required = true;
88 self
89 }
90
91 fn field_id(&self, name: &str) -> String {
92 format!("{}_{}", self.prefix, name)
93 }
94}
95
96impl Block for AddressBlock {
97 fn prefix(&self) -> &str {
98 &self.prefix
99 }
100
101 fn title(&self) -> Option<&str> {
102 self.title.as_deref()
103 }
104
105 fn fields(&self) -> Vec<Box<dyn Field>> {
106 let mut fields: Vec<Box<dyn Field>> = Vec::new();
107
108 let mut street1 = TextInput::new(self.field_id("street1"), "Street Address")
110 .placeholder("123 Main St");
111 if self.required {
112 street1 = street1.required();
113 }
114 fields.push(Box::new(street1));
115
116 let street2 = TextInput::new(self.field_id("street2"), "Address Line 2")
118 .placeholder("Apt, Suite, Unit, etc. (optional)");
119 fields.push(Box::new(street2));
120
121 let mut city = TextInput::new(self.field_id("city"), "City")
123 .placeholder("City");
124 if self.required {
125 city = city.required();
126 }
127 fields.push(Box::new(city));
128
129 let mut state = Select::new(self.field_id("state"), "State");
131 for (abbr, name) in US_STATES {
132 state = state.option(*abbr, format!("{} ({})", name, abbr));
133 }
134 if self.required {
135 state = state.required();
136 }
137 fields.push(Box::new(state));
138
139 let mut zip = TextInput::new(self.field_id("zip"), "ZIP Code")
141 .placeholder("12345 or 12345-6789")
142 .validator(Box::new(Pattern::zip_code()));
143 if self.required {
144 zip = zip.required();
145 }
146 fields.push(Box::new(zip));
147
148 fields
149 }
150}