[push/opt-in-prompts] Implement push notifications client integration

Build the full client half of docs/api/push-notifications-integration-guide.md:
OS permission + APNs device-token registration and pipeline wiring, profile
notifications/biometric-login toggles on the Ver Perfil screen reflecting
server truth, order-tracking opt-in fallback prompt, profile-cache refresh
on every mutation, a Notification Service Extension for rich/image push,
the Push Notifications capability, targeting-attributes sync, campaign open
tracking, and tap-to-order deep linking with foreground notification display.
This commit is contained in:
Daniel Arantes Loverde
2026-08-04 11:33:56 -03:00
parent 32f12d6c0e
commit 7dd4cda1a4
20 changed files with 943 additions and 12 deletions

View File

@@ -38,6 +38,53 @@ struct CustomerIdentityUpdatePayload: Encodable {
}
}
/// `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?