Skip to content

Commit 1b2a0f7

Browse files
fix: Add identify for SwiftUI
1 parent 565703d commit 1b2a0f7

2 files changed

Lines changed: 64 additions & 59 deletions

File tree

mParticle-Rokt-Swift/MPRoktLayout.swift

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import mParticle_Apple_SDK
1717
import mParticle_Rokt
1818

1919
@available(iOS 15, *)
20-
public struct MPRoktLayout: View {
21-
public var roktLayout: RoktLayout
20+
public class MPRoktLayout {
21+
public var roktLayout: RoktLayout? = nil
2222

2323
public init(
2424
sdkTriggered: Binding<Bool>,
@@ -28,19 +28,60 @@ public struct MPRoktLayout: View {
2828
config: RoktConfig? = nil,
2929
onEvent: ((RoktEvent) -> Void)? = nil
3030
) {
31-
let preparedAttributes = MPKitRokt.prepareAttributes(attributes, filteredUser: Optional<FilteredMParticleUser>.none, performMapping: true)
31+
confirmUser(attributes: attributes) {
32+
let preparedAttributes = MPKitRokt.prepareAttributes(attributes, filteredUser: Optional<FilteredMParticleUser>.none, performMapping: true)
3233

33-
self.roktLayout = RoktLayout.init(
34-
sdkTriggered: sdkTriggered,
35-
viewName: viewName,
36-
locationName: locationName,
37-
attributes: preparedAttributes,
38-
config: config,
39-
onEvent: onEvent
40-
)
34+
self.roktLayout = RoktLayout.init(
35+
sdkTriggered: sdkTriggered,
36+
viewName: viewName,
37+
locationName: locationName,
38+
attributes: preparedAttributes,
39+
config: config,
40+
onEvent: onEvent
41+
)
42+
}
4143
}
44+
}
4245

43-
public var body: some View {
44-
return self.roktLayout.body
46+
func confirmUser(
47+
attributes: [String: String]?,
48+
completion: @escaping () -> Void
49+
) {
50+
let email = attributes?["email"]
51+
let hashedEmail = attributes?["emailsha256"]
52+
53+
if let user = MParticle.sharedInstance().identity.currentUser {
54+
let userEmailIdentity = user.identities[NSNumber(value: MPIdentity.email.rawValue)]
55+
let userHashedEmailIdentity = user.identities[NSNumber(value: MPIdentity.other.rawValue)]
56+
57+
let emailMismatch = email != nil && email != userEmailIdentity
58+
let hashedEmailMismatch = hashedEmail != nil && hashedEmail != userHashedEmailIdentity
59+
60+
if emailMismatch || hashedEmailMismatch {
61+
// If there is an existing email or hashed email but it doesn't match what was passed in, warn the customer
62+
if let email = email, let userEmail = userEmailIdentity {
63+
print("The existing email on the user (\(userEmail)) does not match the email passed in to `selectPlacements:` (\(email)). Please remember to sync the email identity to mParticle as soon as you receive it. We will now identify the user before continuing to `selectPlacements:`")
64+
} else if let hashedEmail = hashedEmail, let userHashedEmail = userHashedEmailIdentity {
65+
print("The existing hashed email on the user (\(userHashedEmail)) does not match the email passed in to `selectPlacements:` (\(hashedEmail)). Please remember to sync the email identity to mParticle as soon as you receive it. We will now identify the user before continuing to `selectPlacements:`")
66+
}
67+
68+
let identityRequest = MPIdentityApiRequest(user: user)
69+
identityRequest.setIdentity(email, identityType: .email)
70+
identityRequest.setIdentity(hashedEmail, identityType: .other)
71+
72+
MParticle.sharedInstance().identity.identify(identityRequest) {apiResult, error in
73+
if let error = error {
74+
print("Failed to sync email from selectPlacement to user: \(error)")
75+
completion()
76+
} else {
77+
if let identities = apiResult?.user.identities {
78+
print("Updated user identity based off selectPlacement's attributes: \(identities)")
79+
}
80+
completion()
81+
}
82+
}
83+
} else {
84+
completion()
85+
}
4586
}
4687
}

mParticle_RoktTests/mParticle_Rokt_SwiftTests.swift

Lines changed: 10 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct mParticle_Rokt_SwiftTests {
3131
)
3232

3333
// Then
34-
#expect(layout.body != nil, "Layout body should not be nil")
34+
#expect(layout.roktLayout != nil, "Layout should not be nil")
3535
}
3636

3737
@MainActor @available(iOS 15, *)
@@ -58,7 +58,7 @@ struct mParticle_Rokt_SwiftTests {
5858
)
5959

6060
// Then
61-
#expect(layout.body != nil, "Layout body should not be nil")
61+
#expect(layout.roktLayout != nil, "Layout body should not be nil")
6262
}
6363

6464
@MainActor @available(iOS 15, *)
@@ -76,7 +76,7 @@ struct mParticle_Rokt_SwiftTests {
7676
)
7777

7878
// Then
79-
#expect(layout.body != nil, "Layout should handle empty attributes")
79+
#expect(layout.roktLayout != nil, "Layout should handle empty attributes")
8080
}
8181

8282
@MainActor @available(iOS 15, *)
@@ -94,7 +94,7 @@ struct mParticle_Rokt_SwiftTests {
9494
)
9595

9696
// Then
97-
#expect(layout.body != nil, "Layout should handle sandbox attribute")
97+
#expect(layout.roktLayout != nil, "Layout should handle sandbox attribute")
9898
}
9999

100100
// MARK: - Attribute Preparation Tests
@@ -183,47 +183,11 @@ struct mParticle_Rokt_SwiftTests {
183183
)
184184

185185
// Then
186-
#expect(layout is any View, "MPRoktLayout should conform to SwiftUI View protocol")
187-
}
188-
189-
@MainActor @available(iOS 15, *)
190-
@Test func testMPRoktLayoutBodyProperty() {
191-
// Given
192-
let sdkTriggered = Binding.constant(false)
193-
let attributes: [String: String] = ["test": "value"]
194-
195-
// When
196-
let layout = MPRoktLayout(
197-
sdkTriggered: sdkTriggered,
198-
locationName: "test",
199-
attributes: attributes
200-
)
201-
202-
// Then
203-
let body = layout.body
204-
#expect(body != nil, "Layout body should be accessible")
186+
#expect(layout.roktLayout is any View, "MPRoktLayout should conform to SwiftUI View protocol")
205187
}
206188

207189
// MARK: - Parameter Validation Tests
208190

209-
@MainActor @available(iOS 15, *)
210-
@Test func testMPRoktLayoutWithLongLocationName() {
211-
// Given
212-
let sdkTriggered = Binding.constant(false)
213-
let longLocationName = String(repeating: "a", count: 1000)
214-
let attributes: [String: String] = ["test": "value"]
215-
216-
// When
217-
let layout = MPRoktLayout(
218-
sdkTriggered: sdkTriggered,
219-
locationName: longLocationName,
220-
attributes: attributes
221-
)
222-
223-
// Then
224-
#expect(layout.body != nil, "Layout should handle long location names")
225-
}
226-
227191
@MainActor @available(iOS 15, *)
228192
@Test func testMPRoktLayoutWithSpecialCharacters() {
229193
// Given
@@ -242,7 +206,7 @@ struct mParticle_Rokt_SwiftTests {
242206
)
243207

244208
// Then
245-
#expect(layout.body != nil, "Layout should handle special characters and unicode")
209+
#expect(layout.roktLayout != nil, "Layout should handle special characters and unicode")
246210
}
247211

248212
// MARK: - State Management Tests
@@ -261,13 +225,13 @@ struct mParticle_Rokt_SwiftTests {
261225
)
262226

263227
// Then
264-
#expect(layout.body != nil, "Layout should be created with initial state")
228+
#expect(layout.roktLayout != nil, "Layout should be created with initial state")
265229

266230
// When state changes
267231
sdkTriggered.wrappedValue = true
268232

269233
// Then
270-
#expect(layout.body != nil, "Layout should handle state changes")
234+
#expect(layout.roktLayout != nil, "Layout should handle state changes")
271235
}
272236

273237
// MARK: - Integration Tests
@@ -291,7 +255,7 @@ struct mParticle_Rokt_SwiftTests {
291255
)
292256

293257
// Then
294-
#expect(layout.body != nil, "Layout should properly integrate attribute processing")
258+
#expect(layout.roktLayout == nil, "Layout should attempt to identify user attributes and fail")
295259
}
296260

297261
@MainActor @available(iOS 15, *)
@@ -325,6 +289,6 @@ struct mParticle_Rokt_SwiftTests {
325289
)
326290

327291
// Then
328-
#expect(layout.body != nil, "Layout should handle complex configurations")
292+
#expect(layout.roktLayout != nil, "Layout should handle complex configurations")
329293
}
330294
}

0 commit comments

Comments
 (0)