1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8use crate::{CalendarId, SchedulerBookingId, SchedulerConfigId, SchedulerSessionId};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub struct SchedulerConfig {
15 pub id: SchedulerConfigId,
17
18 pub name: String,
20
21 pub slug: String,
23
24 pub event_title: String,
26
27 #[serde(skip_serializing_if = "Option::is_none")]
29 pub event_description: Option<String>,
30
31 pub duration_minutes: u32,
33
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub event_location: Option<String>,
37
38 pub calendar_ids: Vec<CalendarId>,
40
41 pub availability: AvailabilitySettings,
43
44 pub booking: BookingSettings,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub active: Option<bool>,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub created_at: Option<i64>,
54
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub modified_at: Option<i64>,
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62pub struct AvailabilitySettings {
63 pub days: Vec<DayOfWeek>,
65
66 pub start_time: String,
68
69 pub end_time: String,
71
72 pub timezone: String,
74
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub min_notice_minutes: Option<u32>,
78
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub buffer_minutes: Option<u32>,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
86#[serde(rename_all = "lowercase")]
87pub enum DayOfWeek {
88 Monday,
90 Tuesday,
92 Wednesday,
94 Thursday,
96 Friday,
98 Saturday,
100 Sunday,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
106pub struct BookingSettings {
107 #[serde(skip_serializing_if = "Option::is_none")]
109 pub confirmation_message: Option<String>,
110
111 #[serde(skip_serializing_if = "Option::is_none")]
113 pub confirmation_redirect_url: Option<String>,
114
115 #[serde(skip_serializing_if = "Option::is_none")]
117 pub required_fields: Option<Vec<String>>,
118
119 #[serde(skip_serializing_if = "Option::is_none")]
121 pub custom_fields: Option<Vec<CustomField>>,
122
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub send_confirmation_email: Option<bool>,
126
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub send_reminder_email: Option<bool>,
130
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub reminder_minutes: Option<u32>,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138pub struct CustomField {
139 pub name: String,
141
142 pub label: String,
144
145 #[serde(rename = "type")]
147 pub field_type: CustomFieldType,
148
149 #[serde(skip_serializing_if = "Option::is_none")]
151 pub required: Option<bool>,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub options: Option<Vec<String>>,
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
160#[serde(rename_all = "lowercase")]
161pub enum CustomFieldType {
162 Text,
164 Email,
166 Phone,
168 Select,
170 Radio,
172 Checkbox,
174 Textarea,
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
180#[serde(rename_all = "lowercase")]
181pub enum Locale {
182 En,
184 Es,
186 Fr,
188 De,
190 Ja,
192 #[serde(rename = "zh")]
194 ZhCn,
195 Ko,
197}
198
199#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
201pub struct CreateSchedulerConfigRequest {
202 pub name: String,
204
205 pub slug: String,
207
208 pub event_title: String,
210
211 #[serde(skip_serializing_if = "Option::is_none")]
213 pub event_description: Option<String>,
214
215 pub duration_minutes: u32,
217
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub event_location: Option<String>,
221
222 pub calendar_ids: Vec<String>,
224
225 pub availability: AvailabilitySettings,
227
228 pub booking: BookingSettings,
230}
231
232#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
234pub struct UpdateSchedulerConfigRequest {
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub name: Option<String>,
238
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub event_title: Option<String>,
242
243 #[serde(skip_serializing_if = "Option::is_none")]
245 pub event_description: Option<String>,
246
247 #[serde(skip_serializing_if = "Option::is_none")]
249 pub duration_minutes: Option<u32>,
250
251 #[serde(skip_serializing_if = "Option::is_none")]
253 pub active: Option<bool>,
254}
255
256#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
260pub struct SchedulerSession {
261 pub id: SchedulerSessionId,
263
264 pub config_id: SchedulerConfigId,
266
267 pub email: String,
269
270 #[serde(skip_serializing_if = "Option::is_none")]
272 pub name: Option<String>,
273
274 #[serde(skip_serializing_if = "Option::is_none")]
276 pub expires_at: Option<i64>,
277
278 #[serde(skip_serializing_if = "Option::is_none")]
280 pub metadata: Option<HashMap<String, String>>,
281}
282
283#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
285pub struct CreateSchedulerSessionRequest {
286 pub config_id: String,
288
289 pub email: String,
291
292 #[serde(skip_serializing_if = "Option::is_none")]
294 pub name: Option<String>,
295
296 #[serde(skip_serializing_if = "Option::is_none")]
298 pub metadata: Option<HashMap<String, String>>,
299}
300
301#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
305pub struct SchedulerBooking {
306 pub id: SchedulerBookingId,
308
309 pub config_id: SchedulerConfigId,
311
312 #[serde(skip_serializing_if = "Option::is_none")]
314 pub session_id: Option<SchedulerSessionId>,
315
316 pub event_id: String,
318
319 pub email: String,
321
322 #[serde(skip_serializing_if = "Option::is_none")]
324 pub name: Option<String>,
325
326 pub start_time: i64,
328
329 pub end_time: i64,
331
332 pub timezone: String,
334
335 pub status: BookingStatus,
337
338 #[serde(skip_serializing_if = "Option::is_none")]
340 pub custom_fields: Option<HashMap<String, String>>,
341
342 #[serde(skip_serializing_if = "Option::is_none")]
344 pub created_at: Option<i64>,
345}
346
347#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
349#[serde(rename_all = "lowercase")]
350pub enum BookingStatus {
351 Confirmed,
353 Cancelled,
355 Pending,
357}
358
359#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
361pub struct CreateSchedulerBookingRequest {
362 pub config_id: String,
364
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub session_id: Option<String>,
368
369 pub email: String,
371
372 #[serde(skip_serializing_if = "Option::is_none")]
374 pub name: Option<String>,
375
376 pub start_time: i64,
378
379 pub timezone: String,
381
382 #[serde(skip_serializing_if = "Option::is_none")]
384 pub custom_fields: Option<HashMap<String, String>>,
385}
386
387#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
389pub struct CancelSchedulerBookingRequest {
390 #[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}