- Fix dropdown population on all edit pages (residence, task, contractor, document) - Add formInitialized state pattern to prevent empty dropdowns - Increase pagination max limit from 100 to 10000 for admin queries - Expand handler responses to include all editable fields - Add settings page with seed data and limitations toggle - Fix user form and API client types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
271 lines
10 KiB
Go
271 lines
10 KiB
Go
package dto
|
|
|
|
// PaginatedResponse represents a paginated API response
|
|
type PaginatedResponse struct {
|
|
Data interface{} `json:"data"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PerPage int `json:"per_page"`
|
|
TotalPages int `json:"total_pages"`
|
|
}
|
|
|
|
// NewPaginatedResponse creates a new paginated response
|
|
func NewPaginatedResponse(data interface{}, total int64, page, perPage int) PaginatedResponse {
|
|
totalPages := int(total) / perPage
|
|
if int(total)%perPage > 0 {
|
|
totalPages++
|
|
}
|
|
return PaginatedResponse{
|
|
Data: data,
|
|
Total: total,
|
|
Page: page,
|
|
PerPage: perPage,
|
|
TotalPages: totalPages,
|
|
}
|
|
}
|
|
|
|
// UserResponse represents a user in admin responses
|
|
type UserResponse struct {
|
|
ID uint `json:"id"`
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
FirstName string `json:"first_name"`
|
|
LastName string `json:"last_name"`
|
|
IsActive bool `json:"is_active"`
|
|
IsStaff bool `json:"is_staff"`
|
|
IsSuperuser bool `json:"is_superuser"`
|
|
DateJoined string `json:"date_joined"`
|
|
LastLogin *string `json:"last_login,omitempty"`
|
|
// Profile info
|
|
Verified bool `json:"verified"`
|
|
PhoneNumber *string `json:"phone_number,omitempty"`
|
|
// Counts
|
|
ResidenceCount int `json:"residence_count"`
|
|
TaskCount int `json:"task_count"`
|
|
}
|
|
|
|
// UserDetailResponse includes more details for single user view
|
|
type UserDetailResponse struct {
|
|
UserResponse
|
|
Residences []ResidenceSummary `json:"residences,omitempty"`
|
|
Devices []DeviceSummary `json:"devices,omitempty"`
|
|
}
|
|
|
|
// ResidenceSummary is a brief residence representation
|
|
type ResidenceSummary struct {
|
|
ID uint `json:"id"`
|
|
Name string `json:"name"`
|
|
IsOwner bool `json:"is_owner"`
|
|
IsActive bool `json:"is_active"`
|
|
}
|
|
|
|
// DeviceSummary is a brief device representation
|
|
type DeviceSummary struct {
|
|
ID uint `json:"id"`
|
|
Type string `json:"type"` // "apns" or "gcm"
|
|
Name string `json:"name"`
|
|
IsActive bool `json:"is_active"`
|
|
}
|
|
|
|
// UserSummary is a brief user representation
|
|
type UserSummary struct {
|
|
ID uint `json:"id"`
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
}
|
|
|
|
// ResidenceResponse represents a residence in admin responses
|
|
type ResidenceResponse struct {
|
|
ID uint `json:"id"`
|
|
Name string `json:"name"`
|
|
OwnerID uint `json:"owner_id"`
|
|
OwnerName string `json:"owner_name"`
|
|
PropertyTypeID *uint `json:"property_type_id,omitempty"`
|
|
PropertyType *string `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,omitempty"`
|
|
Bathrooms *float64 `json:"bathrooms,omitempty"`
|
|
SquareFootage *int `json:"square_footage,omitempty"`
|
|
LotSize *float64 `json:"lot_size,omitempty"`
|
|
YearBuilt *int `json:"year_built,omitempty"`
|
|
Description string `json:"description"`
|
|
PurchaseDate *string `json:"purchase_date,omitempty"`
|
|
PurchasePrice *float64 `json:"purchase_price,omitempty"`
|
|
IsPrimary bool `json:"is_primary"`
|
|
IsActive bool `json:"is_active"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
}
|
|
|
|
// ResidenceDetailResponse includes more details for single residence view
|
|
type ResidenceDetailResponse struct {
|
|
ResidenceResponse
|
|
Owner *UserSummary `json:"owner,omitempty"`
|
|
SharedUsers []UserSummary `json:"shared_users,omitempty"`
|
|
TaskCount int `json:"task_count"`
|
|
DocumentCount int `json:"document_count"`
|
|
}
|
|
|
|
// TaskResponse represents a task in admin responses
|
|
type TaskResponse struct {
|
|
ID uint `json:"id"`
|
|
ResidenceID uint `json:"residence_id"`
|
|
ResidenceName string `json:"residence_name"`
|
|
CreatedByID uint `json:"created_by_id"`
|
|
CreatedByName string `json:"created_by_name"`
|
|
AssignedToID *uint `json:"assigned_to_id,omitempty"`
|
|
AssignedToName *string `json:"assigned_to_name,omitempty"`
|
|
Title string `json:"title"`
|
|
Description string `json:"description"`
|
|
CategoryID *uint `json:"category_id,omitempty"`
|
|
CategoryName *string `json:"category_name,omitempty"`
|
|
PriorityID *uint `json:"priority_id,omitempty"`
|
|
PriorityName *string `json:"priority_name,omitempty"`
|
|
StatusID *uint `json:"status_id,omitempty"`
|
|
StatusName *string `json:"status_name,omitempty"`
|
|
FrequencyID *uint `json:"frequency_id,omitempty"`
|
|
FrequencyName *string `json:"frequency_name,omitempty"`
|
|
DueDate *string `json:"due_date,omitempty"`
|
|
EstimatedCost *float64 `json:"estimated_cost,omitempty"`
|
|
ActualCost *float64 `json:"actual_cost,omitempty"`
|
|
ContractorID *uint `json:"contractor_id,omitempty"`
|
|
ParentTaskID *uint `json:"parent_task_id,omitempty"`
|
|
IsCancelled bool `json:"is_cancelled"`
|
|
IsArchived bool `json:"is_archived"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
}
|
|
|
|
// TaskDetailResponse includes more details for single task view
|
|
type TaskDetailResponse struct {
|
|
TaskResponse
|
|
AssignedTo *UserSummary `json:"assigned_to,omitempty"`
|
|
CompletionCount int `json:"completion_count"`
|
|
}
|
|
|
|
// ContractorResponse represents a contractor in admin responses
|
|
type ContractorResponse struct {
|
|
ID uint `json:"id"`
|
|
ResidenceID uint `json:"residence_id"`
|
|
ResidenceName string `json:"residence_name"`
|
|
CreatedByID uint `json:"created_by_id"`
|
|
CreatedByName string `json:"created_by_name"`
|
|
Name string `json:"name"`
|
|
Company string `json:"company"`
|
|
Phone string `json:"phone"`
|
|
Email string `json:"email"`
|
|
Website string `json:"website"`
|
|
Notes string `json:"notes"`
|
|
StreetAddress string `json:"street_address"`
|
|
City string `json:"city"`
|
|
StateProvince string `json:"state_province"`
|
|
PostalCode string `json:"postal_code"`
|
|
Rating *float64 `json:"rating,omitempty"`
|
|
Specialties []string `json:"specialties,omitempty"`
|
|
SpecialtyIDs []uint `json:"specialty_ids,omitempty"`
|
|
IsFavorite bool `json:"is_favorite"`
|
|
IsActive bool `json:"is_active"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
}
|
|
|
|
// ContractorDetailResponse includes more details for single contractor view
|
|
type ContractorDetailResponse struct {
|
|
ContractorResponse
|
|
TaskCount int `json:"task_count"`
|
|
}
|
|
|
|
// DocumentImageResponse represents a document image
|
|
type DocumentImageResponse struct {
|
|
ID uint `json:"id"`
|
|
ImageURL string `json:"image_url"`
|
|
Caption string `json:"caption"`
|
|
}
|
|
|
|
// DocumentResponse represents a document in admin responses
|
|
type DocumentResponse struct {
|
|
ID uint `json:"id"`
|
|
ResidenceID uint `json:"residence_id"`
|
|
ResidenceName string `json:"residence_name"`
|
|
CreatedByID uint `json:"created_by_id"`
|
|
CreatedByName string `json:"created_by_name"`
|
|
Title string `json:"title"`
|
|
Description string `json:"description"`
|
|
DocumentType string `json:"document_type"`
|
|
FileURL string `json:"file_url"`
|
|
FileName string `json:"file_name"`
|
|
FileSize *int64 `json:"file_size,omitempty"`
|
|
MimeType string `json:"mime_type"`
|
|
PurchaseDate *string `json:"purchase_date,omitempty"`
|
|
ExpiryDate *string `json:"expiry_date,omitempty"`
|
|
PurchasePrice *float64 `json:"purchase_price,omitempty"`
|
|
Vendor string `json:"vendor"`
|
|
SerialNumber string `json:"serial_number"`
|
|
ModelNumber string `json:"model_number"`
|
|
Provider string `json:"provider"`
|
|
ProviderContact string `json:"provider_contact"`
|
|
ClaimPhone string `json:"claim_phone"`
|
|
ClaimEmail string `json:"claim_email"`
|
|
ClaimWebsite string `json:"claim_website"`
|
|
Notes string `json:"notes"`
|
|
TaskID *uint `json:"task_id,omitempty"`
|
|
IsActive bool `json:"is_active"`
|
|
Images []DocumentImageResponse `json:"images"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
}
|
|
|
|
// DocumentDetailResponse includes more details for single document view
|
|
type DocumentDetailResponse struct {
|
|
DocumentResponse
|
|
TaskTitle *string `json:"task_title,omitempty"`
|
|
}
|
|
|
|
// NotificationResponse represents a notification in admin responses
|
|
type NotificationResponse struct {
|
|
ID uint `json:"id"`
|
|
UserID uint `json:"user_id"`
|
|
UserEmail string `json:"user_email"`
|
|
Username string `json:"username"`
|
|
NotificationType string `json:"notification_type"`
|
|
Title string `json:"title"`
|
|
Body string `json:"body"`
|
|
Sent bool `json:"sent"`
|
|
SentAt *string `json:"sent_at,omitempty"`
|
|
Read bool `json:"read"`
|
|
ReadAt *string `json:"read_at,omitempty"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
// NotificationDetailResponse includes more details for single notification view
|
|
type NotificationDetailResponse struct {
|
|
NotificationResponse
|
|
Data string `json:"data"`
|
|
TaskID *uint `json:"task_id,omitempty"`
|
|
}
|
|
|
|
// SubscriptionResponse represents a subscription in admin responses
|
|
type SubscriptionResponse struct {
|
|
ID uint `json:"id"`
|
|
UserID uint `json:"user_id"`
|
|
UserEmail string `json:"user_email"`
|
|
Username string `json:"username"`
|
|
Tier string `json:"tier"`
|
|
Platform string `json:"platform"`
|
|
AutoRenew bool `json:"auto_renew"`
|
|
SubscribedAt *string `json:"subscribed_at,omitempty"`
|
|
ExpiresAt *string `json:"expires_at,omitempty"`
|
|
CancelledAt *string `json:"cancelled_at,omitempty"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
// SubscriptionDetailResponse includes more details for single subscription view
|
|
type SubscriptionDetailResponse struct {
|
|
SubscriptionResponse
|
|
}
|