Skip to main content

nylas_types/
scheduler.rs

1//! Scheduler types for the Nylas API v3.
2//!
3//! Scheduler allows users to create booking pages and manage meeting scheduling.
4
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8use crate::{CalendarId, SchedulerBookingId, SchedulerConfigId, SchedulerSessionId};
9
10/// Scheduler configuration.
11///
12/// Defines the settings for a scheduling page.
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub struct SchedulerConfig {
15    /// Unique identifier for the configuration.
16    pub id: SchedulerConfigId,
17
18    /// Name of the configuration.
19    pub name: String,
20
21    /// Slug used in the booking URL.
22    pub slug: String,
23
24    /// Event title template.
25    pub event_title: String,
26
27    /// Event description.
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub event_description: Option<String>,
30
31    /// Event duration in minutes.
32    pub duration_minutes: u32,
33
34    /// Event location.
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub event_location: Option<String>,
37
38    /// Calendar IDs to check availability against.
39    pub calendar_ids: Vec<CalendarId>,
40
41    /// Availability settings.
42    pub availability: AvailabilitySettings,
43
44    /// Booking settings.
45    pub booking: BookingSettings,
46
47    /// Whether this configuration is active.
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub active: Option<bool>,
50
51    /// Unix timestamp when created.
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub created_at: Option<i64>,
54
55    /// Unix timestamp when last modified.
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub modified_at: Option<i64>,
58}
59
60/// Availability settings for scheduler.
61#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62pub struct AvailabilitySettings {
63    /// Days of the week available for booking.
64    pub days: Vec<DayOfWeek>,
65
66    /// Start time for availability (e.g., "09:00").
67    pub start_time: String,
68
69    /// End time for availability (e.g., "17:00").
70    pub end_time: String,
71
72    /// Timezone for availability.
73    pub timezone: String,
74
75    /// Minimum notice period in minutes.
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub min_notice_minutes: Option<u32>,
78
79    /// Buffer time between meetings in minutes.
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub buffer_minutes: Option<u32>,
82}
83
84/// Day of the week for availability.
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
86#[serde(rename_all = "lowercase")]
87pub enum DayOfWeek {
88    /// Monday
89    Monday,
90    /// Tuesday
91    Tuesday,
92    /// Wednesday
93    Wednesday,
94    /// Thursday
95    Thursday,
96    /// Friday
97    Friday,
98    /// Saturday
99    Saturday,
100    /// Sunday
101    Sunday,
102}
103
104/// Booking settings for scheduler.
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
106pub struct BookingSettings {
107    /// Confirmation message shown after booking.
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub confirmation_message: Option<String>,
110
111    /// Confirmation redirect URL.
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub confirmation_redirect_url: Option<String>,
114
115    /// Required fields for booking form.
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub required_fields: Option<Vec<String>>,
118
119    /// Custom fields for booking form.
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub custom_fields: Option<Vec<CustomField>>,
122
123    /// Whether to send confirmation emails.
124    #[serde(skip_serializing_if = "Option::is_none")]
125    pub send_confirmation_email: Option<bool>,
126
127    /// Whether to send reminder emails.
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub send_reminder_email: Option<bool>,
130
131    /// Reminder time in minutes before the meeting.
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub reminder_minutes: Option<u32>,
134}
135
136/// Custom field for booking form.
137#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138pub struct CustomField {
139    /// Field name.
140    pub name: String,
141
142    /// Field label shown to users.
143    pub label: String,
144
145    /// Field type.
146    #[serde(rename = "type")]
147    pub field_type: CustomFieldType,
148
149    /// Whether this field is required.
150    #[serde(skip_serializing_if = "Option::is_none")]
151    pub required: Option<bool>,
152
153    /// Options for select/radio fields.
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub options: Option<Vec<String>>,
156}
157
158/// Type of custom field.
159#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
160#[serde(rename_all = "lowercase")]
161pub enum CustomFieldType {
162    /// Text input
163    Text,
164    /// Email input
165    Email,
166    /// Phone number input
167    Phone,
168    /// Select dropdown
169    Select,
170    /// Radio buttons
171    Radio,
172    /// Checkbox
173    Checkbox,
174    /// Text area
175    Textarea,
176}
177
178/// Supported locales for scheduler UI.
179#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
180#[serde(rename_all = "lowercase")]
181pub enum Locale {
182    /// English
183    En,
184    /// Spanish
185    Es,
186    /// French
187    Fr,
188    /// German
189    De,
190    /// Japanese
191    Ja,
192    /// Chinese (Simplified)
193    #[serde(rename = "zh")]
194    ZhCn,
195    /// Korean (NEW in 2024)
196    Ko,
197}
198
199/// Request to create a scheduler configuration.
200#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
201pub struct CreateSchedulerConfigRequest {
202    /// Name of the configuration.
203    pub name: String,
204
205    /// Slug used in the booking URL.
206    pub slug: String,
207
208    /// Event title template.
209    pub event_title: String,
210
211    /// Event description.
212    #[serde(skip_serializing_if = "Option::is_none")]
213    pub event_description: Option<String>,
214
215    /// Event duration in minutes.
216    pub duration_minutes: u32,
217
218    /// Event location.
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub event_location: Option<String>,
221
222    /// Calendar IDs to check availability against.
223    pub calendar_ids: Vec<String>,
224
225    /// Availability settings.
226    pub availability: AvailabilitySettings,
227
228    /// Booking settings.
229    pub booking: BookingSettings,
230}
231
232/// Request to update a scheduler configuration.
233#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
234pub struct UpdateSchedulerConfigRequest {
235    /// Name of the configuration.
236    #[serde(skip_serializing_if = "Option::is_none")]
237    pub name: Option<String>,
238
239    /// Event title template.
240    #[serde(skip_serializing_if = "Option::is_none")]
241    pub event_title: Option<String>,
242
243    /// Event description.
244    #[serde(skip_serializing_if = "Option::is_none")]
245    pub event_description: Option<String>,
246
247    /// Event duration in minutes.
248    #[serde(skip_serializing_if = "Option::is_none")]
249    pub duration_minutes: Option<u32>,
250
251    /// Whether this configuration is active.
252    #[serde(skip_serializing_if = "Option::is_none")]
253    pub active: Option<bool>,
254}
255
256/// Scheduler session.
257///
258/// Represents an active scheduling session for a guest.
259#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
260pub struct SchedulerSession {
261    /// Unique identifier for the session.
262    pub id: SchedulerSessionId,
263
264    /// Configuration ID this session belongs to.
265    pub config_id: SchedulerConfigId,
266
267    /// Guest email address.
268    pub email: String,
269
270    /// Guest name.
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub name: Option<String>,
273
274    /// Session expiry timestamp.
275    #[serde(skip_serializing_if = "Option::is_none")]
276    pub expires_at: Option<i64>,
277
278    /// Additional session data.
279    #[serde(skip_serializing_if = "Option::is_none")]
280    pub metadata: Option<HashMap<String, String>>,
281}
282
283/// Request to create a scheduler session.
284#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
285pub struct CreateSchedulerSessionRequest {
286    /// Configuration ID to create session for.
287    pub config_id: String,
288
289    /// Guest email address.
290    pub email: String,
291
292    /// Guest name.
293    #[serde(skip_serializing_if = "Option::is_none")]
294    pub name: Option<String>,
295
296    /// Additional session metadata.
297    #[serde(skip_serializing_if = "Option::is_none")]
298    pub metadata: Option<HashMap<String, String>>,
299}
300
301/// Scheduler booking.
302///
303/// Represents a confirmed booking created through the scheduler.
304#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
305pub struct SchedulerBooking {
306    /// Unique identifier for the booking.
307    pub id: SchedulerBookingId,
308
309    /// Configuration ID used for this booking.
310    pub config_id: SchedulerConfigId,
311
312    /// Session ID if created through a session.
313    #[serde(skip_serializing_if = "Option::is_none")]
314    pub session_id: Option<SchedulerSessionId>,
315
316    /// Event ID created for this booking.
317    pub event_id: String,
318
319    /// Guest email address.
320    pub email: String,
321
322    /// Guest name.
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub name: Option<String>,
325
326    /// Booking start time (Unix timestamp).
327    pub start_time: i64,
328
329    /// Booking end time (Unix timestamp).
330    pub end_time: i64,
331
332    /// Timezone for the booking.
333    pub timezone: String,
334
335    /// Booking status.
336    pub status: BookingStatus,
337
338    /// Custom field responses.
339    #[serde(skip_serializing_if = "Option::is_none")]
340    pub custom_fields: Option<HashMap<String, String>>,
341
342    /// Unix timestamp when created.
343    #[serde(skip_serializing_if = "Option::is_none")]
344    pub created_at: Option<i64>,
345}
346
347/// Status of a booking.
348#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
349#[serde(rename_all = "lowercase")]
350pub enum BookingStatus {
351    /// Booking is confirmed
352    Confirmed,
353    /// Booking was cancelled
354    Cancelled,
355    /// Booking is pending
356    Pending,
357}
358
359/// Request to create a scheduler booking.
360#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
361pub struct CreateSchedulerBookingRequest {
362    /// Configuration ID to book against.
363    pub config_id: String,
364
365    /// Session ID if using a session.
366    #[serde(skip_serializing_if = "Option::is_none")]
367    pub session_id: Option<String>,
368
369    /// Guest email address.
370    pub email: String,
371
372    /// Guest name.
373    #[serde(skip_serializing_if = "Option::is_none")]
374    pub name: Option<String>,
375
376    /// Booking start time (Unix timestamp).
377    pub start_time: i64,
378
379    /// Timezone for the booking.
380    pub timezone: String,
381
382    /// Custom field responses.
383    #[serde(skip_serializing_if = "Option::is_none")]
384    pub custom_fields: Option<HashMap<String, String>>,
385}
386
387/// Request to cancel a scheduler booking.
388#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
389pub struct CancelSchedulerBookingRequest {
390    /// Reason for cancellation.
391    #[serde(skip_serializing_if = "Option::is_none")]
392    pub reason: Option<String>,
393}
394
395#[cfg(test)]
396mod tests {
397    use super::*;
398
399    #[test]
400    fn test_scheduler_config_id() {
401        let id = SchedulerConfigId::new("config_123");
402        assert_eq!(id.as_str(), "config_123");
403    }
404
405    #[test]
406    fn test_day_of_week_serialization() {
407        let day = DayOfWeek::Monday;
408        let json = serde_json::to_string(&day).unwrap();
409        assert_eq!(json, "\"monday\"");
410
411        let deserialized: DayOfWeek = serde_json::from_str(&json).unwrap();
412        assert_eq!(day, deserialized);
413    }
414
415    #[test]
416    fn test_custom_field_type_serialization() {
417        let field_type = CustomFieldType::Email;
418        let json = serde_json::to_string(&field_type).unwrap();
419        assert_eq!(json, "\"email\"");
420
421        let deserialized: CustomFieldType = serde_json::from_str(&json).unwrap();
422        assert_eq!(field_type, deserialized);
423    }
424
425    #[test]
426    fn test_booking_status_serialization() {
427        let status = BookingStatus::Confirmed;
428        let json = serde_json::to_string(&status).unwrap();
429        assert_eq!(json, "\"confirmed\"");
430
431        let deserialized: BookingStatus = serde_json::from_str(&json).unwrap();
432        assert_eq!(status, deserialized);
433    }
434
435    #[test]
436    fn test_create_scheduler_booking_request() {
437        let request = CreateSchedulerBookingRequest {
438            config_id: "config_123".to_string(),
439            session_id: Some("session_456".to_string()),
440            email: "guest@example.com".to_string(),
441            name: Some("Guest Name".to_string()),
442            start_time: 1735689600,
443            timezone: "America/New_York".to_string(),
444            custom_fields: None,
445        };
446
447        let json = serde_json::to_string(&request).unwrap();
448        let deserialized: CreateSchedulerBookingRequest = serde_json::from_str(&json).unwrap();
449        assert_eq!(request, deserialized);
450    }
451
452    #[test]
453    fn test_korean_locale() {
454        let locale = Locale::Ko;
455        let json = serde_json::to_string(&locale).unwrap();
456        assert_eq!(json, "\"ko\"");
457    }
458
459    #[test]
460    fn test_korean_locale_deserialization() {
461        let json = "\"ko\"";
462        let locale: Locale = serde_json::from_str(json).unwrap();
463        assert_eq!(locale, Locale::Ko);
464    }
465}