This commit is contained in:
2026-02-18 21:35:32 +01:00
parent 4b0cfaa699
commit 4e49741dfa
47 changed files with 3672 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
import Foundation
struct Client: Codable, Identifiable, Equatable {
let id: String
let name: String
let description: String?
let createdAt: String
let updatedAt: String
}
struct ClientListResponse: Codable {
let clients: [Client]
}
struct CreateClientInput: Codable {
let name: String
let description: String?
}
struct UpdateClientInput: Codable {
let name: String?
let description: String?
}

View File

@@ -0,0 +1,41 @@
import Foundation
struct OngoingTimer: Codable, Identifiable, Equatable {
let id: String
let startTime: String
let projectId: String?
let project: ProjectReference?
let createdAt: String
let updatedAt: String
var elapsedTime: TimeInterval {
guard let start = ISO8601DateFormatter().date(from: startTime) else {
return 0
}
return Date().timeIntervalSince(start)
}
}
struct StartTimerInput: Codable {
let projectId: String?
init(projectId: String? = nil) {
self.projectId = projectId
}
}
struct UpdateTimerInput: Codable {
let projectId: String
init(projectId: String) {
self.projectId = projectId
}
}
struct StopTimerInput: Codable {
let projectId: String
init(projectId: String) {
self.projectId = projectId
}
}

View File

@@ -0,0 +1,35 @@
import Foundation
struct Project: Codable, Identifiable, Equatable {
let id: String
let name: String
let description: String?
let color: String?
let clientId: String
let client: ClientReference
let createdAt: String
let updatedAt: String
}
struct ClientReference: Codable, Equatable {
let id: String
let name: String
}
struct ProjectListResponse: Codable {
let projects: [Project]
}
struct CreateProjectInput: Codable {
let name: String
let description: String?
let color: String?
let clientId: String
}
struct UpdateProjectInput: Codable {
let name: String?
let description: String?
let color: String?
let clientId: String?
}

View File

@@ -0,0 +1,91 @@
import Foundation
struct TimeEntry: Codable, Identifiable, Equatable {
let id: String
let startTime: String
let endTime: String
let description: String?
let projectId: String
let project: ProjectReference
let createdAt: String
let updatedAt: String
var duration: TimeInterval {
guard let start = ISO8601DateFormatter().date(from: startTime),
let end = ISO8601DateFormatter().date(from: endTime) else {
return 0
}
return end.timeIntervalSince(start)
}
}
struct ProjectReference: Codable, Equatable {
let id: String
let name: String
let color: String?
let client: ClientReference
}
struct TimeEntryListResponse: Codable {
let entries: [TimeEntry]
let pagination: Pagination
}
struct Pagination: Codable, Equatable {
let page: Int
let limit: Int
let total: Int
let totalPages: Int
}
struct TimeEntryFilters: Codable {
let startDate: String?
let endDate: String?
let projectId: String?
let clientId: String?
let page: Int?
let limit: Int?
init(
startDate: Date? = nil,
endDate: Date? = nil,
projectId: String? = nil,
clientId: String? = nil,
page: Int = 1,
limit: Int = 20
) {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withFullDate]
self.startDate = startDate.map { formatter.string(from: $0) }
self.endDate = endDate.map { formatter.string(from: $0) }
self.projectId = projectId
self.clientId = clientId
self.page = page
self.limit = limit
}
}
struct CreateTimeEntryInput: Codable {
let startTime: String
let endTime: String
let description: String?
let projectId: String
init(startTime: Date, endTime: Date, description: String? = nil, projectId: String) {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime]
self.startTime = formatter.string(from: startTime)
self.endTime = formatter.string(from: endTime)
self.description = description
self.projectId = projectId
}
}
struct UpdateTimeEntryInput: Codable {
let startTime: String?
let endTime: String?
let description: String?
let projectId: String?
}

View File

@@ -0,0 +1,57 @@
import Foundation
struct TimeStatistics: Codable, Equatable {
let totalSeconds: Int
let entryCount: Int
let byProject: [ProjectStatistics]
let byClient: [ClientStatistics]
let filters: StatisticsFilters
}
struct ProjectStatistics: Codable, Identifiable, Equatable {
let projectId: String
let projectName: String
let projectColor: String?
let totalSeconds: Int
let entryCount: Int
var id: String { projectId }
}
struct ClientStatistics: Codable, Identifiable, Equatable {
let clientId: String
let clientName: String
let totalSeconds: Int
let entryCount: Int
var id: String { clientId }
}
struct StatisticsFilters: Codable, Equatable {
let startDate: String?
let endDate: String?
let projectId: String?
let clientId: String?
}
struct StatisticsFiltersInput: Codable {
let startDate: String?
let endDate: String?
let projectId: String?
let clientId: String?
init(
startDate: Date? = nil,
endDate: Date? = nil,
projectId: String? = nil,
clientId: String? = nil
) {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withFullDate]
self.startDate = startDate.map { formatter.string(from: $0) }
self.endDate = endDate.map { formatter.string(from: $0) }
self.projectId = projectId
self.clientId = clientId
}
}

View File

@@ -0,0 +1,19 @@
import Foundation
struct User: Codable, Equatable {
let id: String
let username: String
let fullName: String?
let email: String
}
struct UserResponse: Codable {
let id: String
let username: String
let fullName: String?
let email: String
func toUser() -> User {
User(id: id, username: username, fullName: fullName, email: email)
}
}