slack_blocks/elems/date_picker.rs
1//! # Date Picker Element
2//!
3//! An element which lets users easily select a date from a calendar style UI.
4//!
5//! [slack api docs 🔗]
6//!
7//! Works in [blocks 🔗]: Section, Actions, Input
8//!
9//! [slack api docs 🔗]: https://api.slack.com/reference/block-kit/block-elements#datepicker
10//! [blocks 🔗]: https://api.slack.com/reference/block-kit/blocks
11
12use std::borrow::Cow;
13
14use serde::{Deserialize as De, Serialize as Ser};
15#[cfg(feature = "validation")]
16use validator::Validate;
17
18#[cfg(feature = "validation")]
19use crate::val_helpr::*;
20use crate::{compose::Confirm, text};
21
22/// # Date Picker Element
23///
24/// An element which lets users easily select a date from a calendar style UI.
25///
26/// [slack api docs 🔗]
27///
28/// Works in [blocks 🔗]: Section, Actions, Input
29///
30/// [slack api docs 🔗]: https://api.slack.com/reference/block-kit/block-elements#datepicker
31/// [blocks 🔗]: https://api.slack.com/reference/block-kit/blocks
32#[derive(Clone, Debug, Hash, PartialEq, Ser, De)]
33#[cfg_attr(feature = "validation", derive(Validate))]
34pub struct DatePicker<'a> {
35 #[cfg_attr(feature = "validation", validate(length(max = 255)))]
36 action_id: Cow<'a, str>,
37
38 #[cfg_attr(feature = "validation",
39 validate(custom = "validate_placeholder"))]
40 #[serde(skip_serializing_if = "Option::is_none")]
41 placeholder: Option<text::Text>,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
44 initial_date: Option<String>,
45
46 #[cfg_attr(feature = "validation", validate)]
47 #[serde(skip_serializing_if = "Option::is_none")]
48 confirm: Option<Confirm>,
49}
50
51#[cfg(feature = "validation")]
52fn validate_placeholder(p: &text::Text) -> ValidatorResult {
53 below_len("DatePicker.placeholder", 150, p)
54}
55
56impl<'a> DatePicker<'a> {
57 /// Build a new Date picker element.
58 ///
59 /// # Example
60 /// see example for `build::DatePickerBuilder`.
61 pub fn builder() -> build::DatePickerBuilderInit<'a> {
62 build::DatePickerBuilderInit::new()
63 }
64
65 /// Validate that this image element agrees with Slack's model requirements.
66 ///
67 /// No rules are specified in the Slack docs at the time of writing so this will always succeed.
68 #[cfg(feature = "validation")]
69 #[cfg_attr(docsrs, doc(cfg(feature = "validation")))]
70 pub fn validate(&self) -> ValidationResult {
71 Validate::validate(self)
72 }
73}
74
75/// Date picker builder
76pub mod build {
77 use std::marker::PhantomData;
78
79 use super::*;
80 use crate::build::*;
81
82 /// Required builder methods
83 #[allow(non_camel_case_types)]
84 pub mod method {
85 /// DatePickerBuilder.action_id
86 #[derive(Copy, Clone, Debug)]
87 pub struct action_id;
88 }
89
90 /// Initial state for Date picker
91 pub type DatePickerBuilderInit<'a> =
92 DatePickerBuilder<'a, RequiredMethodNotCalled<method::action_id>>;
93
94 /// Date Picker builder
95 ///
96 /// Allows you to construct safely, with compile-time checks
97 /// on required setter methods.
98 ///
99 /// # Required Methods
100 /// `DatePickerBuilder::build()` is only available if these methods have been called:
101 /// - `action_id`
102 ///
103 /// # Example
104 /// ```
105 /// use std::convert::TryFrom;
106 ///
107 /// use slack_blocks::{blocks::{Actions, Block},
108 /// elems::{BlockElement, DatePicker}};
109 ///
110 /// let picker = DatePicker::builder().action_id("foo").build();
111 ///
112 /// let block: Block = Actions::builder().element(picker).build().into();
113 ///
114 /// // <send block to slack API>
115 /// ```
116 #[derive(Debug)]
117 pub struct DatePickerBuilder<'a, A> {
118 action_id: Option<Cow<'a, str>>,
119 placeholder: Option<text::Text>,
120 initial_date: Option<String>,
121 confirm: Option<Confirm>,
122 state: PhantomData<A>,
123 }
124
125 impl<'a, A> DatePickerBuilder<'a, A> {
126 /// Create a new builder
127 pub fn new() -> Self {
128 Self { action_id: None,
129 placeholder: None,
130 initial_date: None,
131 confirm: None,
132 state: PhantomData::<_> }
133 }
134
135 /// Set `action_id` (Optional)
136 ///
137 /// An identifier for the action triggered when a menu option is selected.
138 ///
139 /// You can use this when you receive an interaction payload to [identify the source of the action 🔗].
140 ///
141 /// Should be unique among all other `action_id`s in the containing block.
142 ///
143 /// Maximum length for this field is 255 characters.
144 ///
145 /// [identify the source of the action 🔗]: https://api.slack.com/interactivity/handling#payloads
146 pub fn action_id<S>(self,
147 action_id: S)
148 -> DatePickerBuilder<'a, Set<method::action_id>>
149 where S: Into<Cow<'a, str>>
150 {
151 DatePickerBuilder { action_id: Some(action_id.into()),
152 placeholder: self.placeholder,
153 initial_date: self.initial_date,
154 confirm: self.confirm,
155 state: PhantomData::<_> }
156 }
157
158 /// Set `placeholder` (Optional)
159 ///
160 /// A [`plain_text` only text object 🔗] that defines the placeholder text shown on the datepicker.
161 ///
162 /// Maximum length for the `text` in this field is 150 characters.
163 ///
164 /// [`plain_text` only text object 🔗]: https://api.slack.com/reference/block-kit/composition-objects#text
165 pub fn placeholder<S>(mut self, placeholder: S) -> Self
166 where S: Into<text::Plain>
167 {
168 self.placeholder = Some(placeholder.into().into());
169 self
170 }
171
172 /// Set `initial_date` (Optional)
173 ///
174 /// The initial date that is selected when the element is loaded.
175 ///
176 /// ```
177 /// use slack_blocks::elems::DatePicker;
178 ///
179 /// DatePicker::builder().action_id("foo")
180 /// .initial_date((01, 05, 2021))
181 /// .build();
182 /// ```
183 pub fn initial_date(mut self, (day, month, year): (u8, u8, u16)) -> Self {
184 self.initial_date = Some(format!("{:02}-{:02}-{}", year, month, day));
185 self
186 }
187
188 /// Set `confirm` (Optional)
189 ///
190 /// A [confirm object 🔗] that defines an optional confirmation dialog
191 /// that appears after a date is selected.
192 ///
193 /// [confirm object 🔗]: https://api.slack.com/reference/block-kit/composition-objects#confirm
194 pub fn confirm(mut self, confirm: Confirm) -> Self {
195 self.confirm = Some(confirm);
196 self
197 }
198 }
199
200 impl<'a> DatePickerBuilder<'a, Set<method::action_id>> {
201 /// All done building, now give me a darn date picker!
202 ///
203 /// > `no method name 'build' found for struct 'DatePickerBuilder<...>'`?
204 /// Make sure all required setter methods have been called. See docs for `DatePickerBuilder`.
205 ///
206 /// ```compile_fail
207 /// use slack_blocks::elems::DatePicker;
208 ///
209 /// let foo = DatePicker::builder().build(); // Won't compile!
210 /// ```
211 ///
212 /// ```
213 /// use slack_blocks::{compose::Opt, elems::DatePicker};
214 ///
215 /// let foo = DatePicker::builder().action_id("foo").build();
216 /// ```
217 pub fn build(self) -> DatePicker<'a> {
218 DatePicker { action_id: self.action_id.unwrap(),
219 placeholder: self.placeholder,
220 initial_date: self.initial_date,
221 confirm: self.confirm }
222 }
223 }
224}