package responses import ( "time" "github.com/shopspring/decimal" "github.com/treytartt/casera-api/internal/models" ) // ResidenceTypeResponse represents a residence type in the API response type ResidenceTypeResponse struct { ID uint `json:"id"` Name string `json:"name"` } // ResidenceUserResponse represents a user with access to a residence type ResidenceUserResponse struct { ID uint `json:"id"` Username string `json:"username"` Email string `json:"email"` FirstName string `json:"first_name"` LastName string `json:"last_name"` } // ResidenceResponse represents a residence in the API response type ResidenceResponse struct { ID uint `json:"id"` OwnerID uint `json:"owner_id"` Owner *ResidenceUserResponse `json:"owner,omitempty"` Users []ResidenceUserResponse `json:"users,omitempty"` Name string `json:"name"` PropertyTypeID *uint `json:"property_type_id"` PropertyType *ResidenceTypeResponse `json:"property_type,omitempty"` StreetAddress string `json:"street_address"` ApartmentUnit string `json:"apartment_unit"` City string `json:"city"` StateProvince string `json:"state_province"` PostalCode string `json:"postal_code"` Country string `json:"country"` Bedrooms *int `json:"bedrooms"` Bathrooms *decimal.Decimal `json:"bathrooms"` SquareFootage *int `json:"square_footage"` LotSize *decimal.Decimal `json:"lot_size"` YearBuilt *int `json:"year_built"` Description string `json:"description"` PurchaseDate *time.Time `json:"purchase_date"` PurchasePrice *decimal.Decimal `json:"purchase_price"` IsPrimary bool `json:"is_primary"` IsActive bool `json:"is_active"` OverdueCount int `json:"overdue_count"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // TotalSummary represents summary statistics for all residences type TotalSummary struct { TotalResidences int `json:"total_residences"` TotalTasks int `json:"total_tasks"` TotalPending int `json:"total_pending"` TotalOverdue int `json:"total_overdue"` TasksDueNextWeek int `json:"tasks_due_next_week"` TasksDueNextMonth int `json:"tasks_due_next_month"` } // MyResidencesResponse represents the response for my-residences endpoint // NOTE: Summary statistics are calculated client-side from kanban data type MyResidencesResponse struct { Residences []ResidenceResponse `json:"residences"` } // ResidenceWithSummaryResponse wraps ResidenceResponse with TotalSummary for CRUD operations type ResidenceWithSummaryResponse struct { Data ResidenceResponse `json:"data"` Summary TotalSummary `json:"summary"` } // ResidenceDeleteWithSummaryResponse for delete operations type ResidenceDeleteWithSummaryResponse struct { Data string `json:"data"` Summary TotalSummary `json:"summary"` } // ShareCodeResponse represents a share code in the API response type ShareCodeResponse struct { ID uint `json:"id"` Code string `json:"code"` ResidenceID uint `json:"residence_id"` CreatedByID uint `json:"created_by_id"` IsActive bool `json:"is_active"` ExpiresAt *time.Time `json:"expires_at"` CreatedAt time.Time `json:"created_at"` } // JoinResidenceResponse represents the response after joining a residence type JoinResidenceResponse struct { Message string `json:"message"` Residence ResidenceResponse `json:"residence"` Summary TotalSummary `json:"summary"` } // GenerateShareCodeResponse represents the response after generating a share code type GenerateShareCodeResponse struct { Message string `json:"message"` ShareCode ShareCodeResponse `json:"share_code"` } // SharePackageResponse represents the response for generating a share package // This contains the share code plus metadata for the .casera file type SharePackageResponse struct { ShareCode string `json:"share_code"` ResidenceName string `json:"residence_name"` SharedBy string `json:"shared_by"` ExpiresAt *time.Time `json:"expires_at,omitempty"` } // === Factory Functions === // NewResidenceUserResponse creates a ResidenceUserResponse from a User model func NewResidenceUserResponse(user *models.User) *ResidenceUserResponse { if user == nil { return nil } return &ResidenceUserResponse{ ID: user.ID, Username: user.Username, Email: user.Email, FirstName: user.FirstName, LastName: user.LastName, } } // NewResidenceTypeResponse creates a ResidenceTypeResponse from a ResidenceType model func NewResidenceTypeResponse(rt *models.ResidenceType) *ResidenceTypeResponse { if rt == nil { return nil } return &ResidenceTypeResponse{ ID: rt.ID, Name: rt.Name, } } // NewResidenceResponse creates a ResidenceResponse from a Residence model func NewResidenceResponse(residence *models.Residence) ResidenceResponse { resp := ResidenceResponse{ ID: residence.ID, OwnerID: residence.OwnerID, Name: residence.Name, PropertyTypeID: residence.PropertyTypeID, StreetAddress: residence.StreetAddress, ApartmentUnit: residence.ApartmentUnit, City: residence.City, StateProvince: residence.StateProvince, PostalCode: residence.PostalCode, Country: residence.Country, Bedrooms: residence.Bedrooms, Bathrooms: residence.Bathrooms, SquareFootage: residence.SquareFootage, LotSize: residence.LotSize, YearBuilt: residence.YearBuilt, Description: residence.Description, PurchaseDate: residence.PurchaseDate, PurchasePrice: residence.PurchasePrice, IsPrimary: residence.IsPrimary, IsActive: residence.IsActive, CreatedAt: residence.CreatedAt, UpdatedAt: residence.UpdatedAt, } // Include owner if loaded if residence.Owner.ID != 0 { resp.Owner = NewResidenceUserResponse(&residence.Owner) } // Include property type if loaded if residence.PropertyType != nil { resp.PropertyType = NewResidenceTypeResponse(residence.PropertyType) } // Include shared users if loaded if len(residence.Users) > 0 { resp.Users = make([]ResidenceUserResponse, len(residence.Users)) for i, user := range residence.Users { resp.Users[i] = *NewResidenceUserResponse(&user) } } else { resp.Users = []ResidenceUserResponse{} } return resp } // NewResidenceListResponse creates a list of residence responses func NewResidenceListResponse(residences []models.Residence) []ResidenceResponse { results := make([]ResidenceResponse, len(residences)) for i, r := range residences { results[i] = NewResidenceResponse(&r) } return results } // NewShareCodeResponse creates a ShareCodeResponse from a ResidenceShareCode model func NewShareCodeResponse(sc *models.ResidenceShareCode) ShareCodeResponse { return ShareCodeResponse{ ID: sc.ID, Code: sc.Code, ResidenceID: sc.ResidenceID, CreatedByID: sc.CreatedByID, IsActive: sc.IsActive, ExpiresAt: sc.ExpiresAt, CreatedAt: sc.CreatedAt, } }