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}