import Foundation struct PublicCategory: Decodable { let id: String let name: String let icon: String? } struct CustomerProfileUpdatePayload: Encodable { let addressBook: [CustomerAddressPayload] enum CodingKeys: String, CodingKey { case addressBook = "address_book" } } struct CustomerIdentityUpdatePayload: Encodable { let name: String? let email: String? let phoneNumber: String? let profilePicture: String? enum CodingKeys: String, CodingKey { case name case email case phoneNumber case profilePicture } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(name, forKey: .name) try container.encodeIfPresent(email, forKey: .email) try container.encodeIfPresent(phoneNumber, forKey: .phoneNumber) if let profilePicture, profilePicture.isEmpty == false { try container.encode(profilePicture, forKey: .profilePicture) } } } /// `POST /api/customer/:id` — partial update, sibling of `CustomerProfileUpdatePayload`. /// See docs/api/push-notifications-integration-guide.md §2b. struct CustomerNotificationsUpdatePayload: Encodable { let notificationsEnabled: Bool } /// `POST /api/customer/:id` — biometric-login preference. Persistence only for /// now; the actual Face ID/Touch ID unlock flow is a separate, later plan. struct CustomerFaceIdUpdatePayload: Encodable { let faceIdEnabled: Bool } /// `PUT /api/customer/:id/push-token` — see docs/api/push-notifications-integration-guide.md §2. struct CustomerPushTokenPayload: Encodable { let pushToken: String let deviceId: String let deviceOS: String } /// `PUT /api/customer/:id/attributes` — wholesale replace, not a merge. /// See docs/api/push-notifications-integration-guide.md §2a. struct CustomerAttributesUpdatePayload: Encodable { let appVersion: String? let attributes: [String: String]? func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(appVersion, forKey: .appVersion) try container.encodeIfPresent(attributes, forKey: .attributes) } enum CodingKeys: String, CodingKey { case appVersion case attributes } } /// `POST /api/customer/:id/push-campaigns/opened` — see /// docs/api/push-notifications-integration-guide.md §6a. struct PushCampaignOpenedPayload: Encodable { let campaignId: String } struct PushCampaignOpenedResult: Decodable { let recorded: Bool } struct CustomerAddressPayload: Encodable { let label: String? let address: String? let number: String? let complement: String? let neighborhood: String? let city: String? let state: String? let zipCode: String? let latLong: [Double]? enum CodingKeys: String, CodingKey { case label case address case number case complement case neighborhood case city case state case zipCode case latLong = "lat_long" } init(from address: CustomerAddress) { self.label = address.label self.address = address.address self.number = address.number self.complement = address.complement self.neighborhood = address.neighborhood self.city = address.city self.state = address.state self.zipCode = address.zipCode self.latLong = address.latLong } }