slack_messaging/blocks/elements/
date_picker.rs

1use crate::composition_objects::{ConfirmationDialog, Plain, Text};
2use crate::validators::*;
3
4use serde::Serialize;
5use slack_messaging_derive::Builder;
6
7/// [Date picker element](https://docs.slack.dev/reference/block-kit/block-elements/date-picker-element)
8/// representation.
9///
10/// # Fields and Validations
11///
12/// For more details, see the [official
13/// documentation](https://docs.slack.dev/reference/block-kit/block-elements/date-picker-element).
14///
15/// | Field | Type | Required | Validation |
16/// |-------|------|----------|------------|
17/// | action_id | String | No | Max length 255 characters |
18/// | initial_date | String | No | Must match date format "YYYY-MM-DD" |
19/// | confirm | [ConfirmationDialog] | No | N/A |
20/// | focus_on_load | bool | No | N/A |
21/// | placeholder | [Text]<[Plain]> | No | Max length 150 characters |
22///
23/// # Example
24///
25/// ```
26/// use slack_messaging::plain_text;
27/// use slack_messaging::blocks::elements::DatePicker;
28/// # use std::error::Error;
29///
30/// # fn try_main() -> Result<(), Box<dyn Error>> {
31/// let datepicker = DatePicker::builder()
32///     .action_id("datepicker-123")
33///     .initial_date("1990-04-28")
34///     .placeholder(plain_text!("Select a date")?)
35///     .build()?;
36///
37/// let expected = serde_json::json!({
38///     "type": "datepicker",
39///     "action_id": "datepicker-123",
40///     "initial_date": "1990-04-28",
41///     "placeholder": {
42///         "type": "plain_text",
43///         "text": "Select a date"
44///     }
45/// });
46///
47/// let json = serde_json::to_value(datepicker).unwrap();
48///
49/// assert_eq!(json, expected);
50///
51/// // If your object has any validation errors, the build method returns Result::Err
52/// let datepicker = DatePicker::builder()
53///     .action_id("datepicker-123")
54///     .initial_date("1990-04-31")
55///     .placeholder(plain_text!("Select a date")?)
56///     .build();
57///
58/// assert!(datepicker.is_err());
59/// #     Ok(())
60/// # }
61/// # fn main() {
62/// #     try_main().unwrap()
63/// # }
64/// ```
65#[derive(Debug, Clone, Serialize, PartialEq, Builder)]
66#[serde(tag = "type", rename = "datepicker")]
67pub struct DatePicker {
68    #[serde(skip_serializing_if = "Option::is_none")]
69    #[builder(validate("text::max_255"))]
70    pub(crate) action_id: Option<String>,
71
72    #[serde(skip_serializing_if = "Option::is_none")]
73    #[builder(validate("text::date_format"))]
74    pub(crate) initial_date: Option<String>,
75
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub(crate) confirm: Option<ConfirmationDialog>,
78
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub(crate) focus_on_load: Option<bool>,
81
82    #[serde(skip_serializing_if = "Option::is_none")]
83    #[builder(validate("text_object::max_150"))]
84    pub(crate) placeholder: Option<Text<Plain>>,
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use crate::composition_objects::test_helpers::*;
91    use crate::errors::*;
92
93    #[test]
94    fn it_implements_builder() {
95        let expected = DatePicker {
96            action_id: Some("datepicker_0".into()),
97            initial_date: Some("2025-12-10".into()),
98            confirm: Some(confirm()),
99            focus_on_load: Some(true),
100            placeholder: Some(plain_text("Select a date")),
101        };
102
103        let val = DatePicker::builder()
104            .set_action_id(Some("datepicker_0"))
105            .set_initial_date(Some("2025-12-10"))
106            .set_confirm(Some(confirm()))
107            .set_focus_on_load(Some(true))
108            .set_placeholder(Some(plain_text("Select a date")))
109            .build()
110            .unwrap();
111
112        assert_eq!(val, expected);
113
114        let val = DatePicker::builder()
115            .action_id("datepicker_0")
116            .initial_date("2025-12-10")
117            .confirm(confirm())
118            .focus_on_load(true)
119            .placeholder(plain_text("Select a date"))
120            .build()
121            .unwrap();
122
123        assert_eq!(val, expected);
124    }
125
126    #[test]
127    fn it_requires_action_id_less_than_255_characters_long() {
128        let err = DatePicker::builder()
129            .action_id("a".repeat(256))
130            .build()
131            .unwrap_err();
132        assert_eq!(err.object(), "DatePicker");
133
134        let errors = err.field("action_id");
135        assert!(errors.includes(ValidationErrorKind::MaxTextLength(255)));
136    }
137
138    #[test]
139    fn it_requires_initial_date_matches_date_format() {
140        let err = DatePicker::builder()
141            .initial_date("foobar")
142            .build()
143            .unwrap_err();
144        assert_eq!(err.object(), "DatePicker");
145
146        let errors = err.field("initial_date");
147        assert!(errors.includes(ValidationErrorKind::InvalidFormat("YYYY-MM-DD")));
148    }
149
150    #[test]
151    fn it_requires_placeholder_less_than_150_characters_long() {
152        let err = DatePicker::builder()
153            .placeholder(plain_text("a".repeat(151)))
154            .build()
155            .unwrap_err();
156        assert_eq!(err.object(), "DatePicker");
157
158        let errors = err.field("placeholder");
159        assert!(errors.includes(ValidationErrorKind::MaxTextLength(150)));
160    }
161}