koprogo_api/application/dto/
notice_dto.rs

1use crate::domain::entities::{Notice, NoticeCategory, NoticeStatus, NoticeType};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6/// DTO for creating a new notice (Draft status)
7#[derive(Debug, Serialize, Deserialize)]
8pub struct CreateNoticeDto {
9    pub building_id: Uuid,
10    pub notice_type: NoticeType,
11    pub category: NoticeCategory,
12    pub title: String,
13    pub content: String,
14    // Event-specific fields (required for Event type)
15    pub event_date: Option<DateTime<Utc>>,
16    pub event_location: Option<String>,
17    // Contact info for LostAndFound and ClassifiedAd
18    pub contact_info: Option<String>,
19    // Optional expiration date
20    pub expires_at: Option<DateTime<Utc>>,
21}
22
23/// DTO for updating a notice (Draft only)
24#[derive(Debug, Serialize, Deserialize)]
25pub struct UpdateNoticeDto {
26    pub title: Option<String>,
27    pub content: Option<String>,
28    pub category: Option<NoticeCategory>,
29    pub event_date: Option<Option<DateTime<Utc>>>,
30    pub event_location: Option<Option<String>>,
31    pub contact_info: Option<Option<String>>,
32    pub expires_at: Option<Option<DateTime<Utc>>>,
33}
34
35/// DTO for setting expiration date
36#[derive(Debug, Serialize, Deserialize)]
37pub struct SetExpirationDto {
38    pub expires_at: Option<DateTime<Utc>>,
39}
40
41/// Complete notice response with author information
42#[derive(Debug, Serialize, Clone)]
43pub struct NoticeResponseDto {
44    pub id: Uuid,
45    pub building_id: Uuid,
46    pub author_id: Uuid,
47    pub author_name: String, // Enriched from Owner
48    pub notice_type: NoticeType,
49    pub category: NoticeCategory,
50    pub title: String,
51    pub content: String,
52    pub status: NoticeStatus,
53    pub is_pinned: bool,
54    pub published_at: Option<DateTime<Utc>>,
55    pub expires_at: Option<DateTime<Utc>>,
56    pub archived_at: Option<DateTime<Utc>>,
57    // Event-specific fields
58    pub event_date: Option<DateTime<Utc>>,
59    pub event_location: Option<String>,
60    // Contact info
61    pub contact_info: Option<String>,
62    // Timestamps
63    pub created_at: DateTime<Utc>,
64    pub updated_at: DateTime<Utc>,
65    // Computed fields
66    pub is_expired: bool,
67    pub days_until_event: Option<i64>, // For Event type
68}
69
70impl NoticeResponseDto {
71    /// Create from Notice with author name enrichment
72    pub fn from_notice(notice: Notice, author_name: String) -> Self {
73        let is_expired = notice.is_expired();
74        let days_until_event = if notice.notice_type == NoticeType::Event {
75            notice.event_date.map(|event_date| {
76                let now = Utc::now();
77                (event_date - now).num_days()
78            })
79        } else {
80            None
81        };
82
83        Self {
84            id: notice.id,
85            building_id: notice.building_id,
86            author_id: notice.author_id,
87            author_name,
88            notice_type: notice.notice_type,
89            category: notice.category,
90            title: notice.title,
91            content: notice.content,
92            status: notice.status,
93            is_pinned: notice.is_pinned,
94            published_at: notice.published_at,
95            expires_at: notice.expires_at,
96            archived_at: notice.archived_at,
97            event_date: notice.event_date,
98            event_location: notice.event_location,
99            contact_info: notice.contact_info,
100            created_at: notice.created_at,
101            updated_at: notice.updated_at,
102            is_expired,
103            days_until_event,
104        }
105    }
106}
107
108/// Summary notice response for list views
109#[derive(Debug, Serialize, Clone)]
110pub struct NoticeSummaryDto {
111    pub id: Uuid,
112    pub building_id: Uuid,
113    pub author_name: String,
114    pub notice_type: NoticeType,
115    pub category: NoticeCategory,
116    pub title: String,
117    pub status: NoticeStatus,
118    pub is_pinned: bool,
119    pub published_at: Option<DateTime<Utc>>,
120    pub event_date: Option<DateTime<Utc>>, // For Event type
121    pub created_at: DateTime<Utc>,
122    pub is_expired: bool,
123}
124
125impl NoticeSummaryDto {
126    /// Create from Notice with author name enrichment
127    pub fn from_notice(notice: Notice, author_name: String) -> Self {
128        let is_expired = notice.is_expired();
129
130        Self {
131            id: notice.id,
132            building_id: notice.building_id,
133            author_name,
134            notice_type: notice.notice_type,
135            category: notice.category,
136            title: notice.title,
137            status: notice.status.clone(),
138            is_pinned: notice.is_pinned,
139            published_at: notice.published_at,
140            event_date: notice.event_date,
141            created_at: notice.created_at,
142            is_expired,
143        }
144    }
145}