Skip to content

Commit d95f484

Browse files
authored
PIR: Add edit and remove name and addresses messages (#6610)
Task/Issue URL: https://app.asana.com/1/137249556945/project/1203581873609357/task/1211075568938198?focus=true ### Description Adds supports for remaining name and address editing messages during onboarding. ### Steps to test this PR https://app.asana.com/1/137249556945/project/1203581873609357/task/1211088339515453?focus=true ### UI changes No UI changes
1 parent 393c5ac commit d95f484

11 files changed

+470
-77
lines changed

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/dashboard/messaging/handlers/PirWebAddAddressToCurrentUserProfileMessageHandler.kt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import com.duckduckgo.pir.impl.dashboard.messaging.PirDashboardWebMessages
2424
import com.duckduckgo.pir.impl.dashboard.messaging.model.PirWebMessageRequest
2525
import com.duckduckgo.pir.impl.dashboard.messaging.model.PirWebMessageResponse
2626
import com.duckduckgo.pir.impl.dashboard.state.PirWebOnboardingStateHolder
27-
import com.duckduckgo.pir.impl.models.Address
2827
import com.squareup.anvil.annotations.ContributesMultibinding
2928
import javax.inject.Inject
3029
import logcat.logcat
@@ -52,8 +51,11 @@ class PirWebAddAddressToCurrentUserProfileMessageHandler @Inject constructor(
5251
val request =
5352
jsMessage.toRequestMessage(PirWebMessageRequest.AddAddressToCurrentUserProfileRequest::class)
5453

54+
val city = request?.city?.trim().orEmpty()
55+
val state = request?.state?.trim().orEmpty()
56+
5557
// attempting to add an empty address should return success=false
56-
if (request == null || request.city.isEmpty() || request.state.isEmpty()) {
58+
if (city.isBlank() || state.isBlank()) {
5759
logcat { "PIR-WEB: PirWebAddAddressToCurrentUserProfileMessageHandler: missing city and/or state" }
5860
jsMessaging.sendResponse(
5961
jsMessage = jsMessage,
@@ -63,7 +65,7 @@ class PirWebAddAddressToCurrentUserProfileMessageHandler @Inject constructor(
6365
}
6466

6567
// attempting to add a duplicate address should return success=false
66-
if (pirWebOnboardingStateHolder.addresses.any { it.city == request.city && it.state == request.state }) {
68+
if (!pirWebOnboardingStateHolder.addAddress(city, state)) {
6769
logcat { "PIR-WEB: PirWebAddAddressToCurrentUserProfileMessageHandler: address already exists" }
6870
jsMessaging.sendResponse(
6971
jsMessage = jsMessage,
@@ -72,13 +74,6 @@ class PirWebAddAddressToCurrentUserProfileMessageHandler @Inject constructor(
7274
return
7375
}
7476

75-
pirWebOnboardingStateHolder.addresses.add(
76-
Address(
77-
city = request.city,
78-
state = request.state,
79-
),
80-
)
81-
8277
jsMessaging.sendResponse(
8378
jsMessage = jsMessage,
8479
response = PirWebMessageResponse.DefaultResponse.SUCCESS,

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/dashboard/messaging/handlers/PirWebAddNameToCurrentUserProfileMessageHandler.kt

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@ class PirWebAddNameToCurrentUserProfileMessageHandler @Inject constructor(
5151
val request =
5252
jsMessage.toRequestMessage(PirWebMessageRequest.AddNameToCurrentUserProfileRequest::class)
5353

54+
val firstName = request?.first?.trim().orEmpty()
55+
val middleName = request?.middle?.trim().orEmpty()
56+
val lastName = request?.last?.trim().orEmpty()
57+
5458
// attempting to add an empty name should return success=false
55-
if (request == null || request.first.isEmpty() || request.last.isEmpty()) {
59+
if (firstName.isBlank() || lastName.isBlank()) {
5660
logcat { "PIR-WEB: PirWebAddNameToCurrentUserProfileMessageHandler: missing first and/or last names" }
5761
jsMessaging.sendResponse(
5862
jsMessage = jsMessage,
@@ -62,11 +66,11 @@ class PirWebAddNameToCurrentUserProfileMessageHandler @Inject constructor(
6266
}
6367

6468
// attempting to add a duplicate name should return success=false
65-
if (pirWebOnboardingStateHolder.names.any {
66-
it.firstName == request.first &&
67-
it.middleName == request.middle &&
68-
it.lastName == request.last
69-
}
69+
if (!pirWebOnboardingStateHolder.addName(
70+
firstName = firstName,
71+
middleName = middleName,
72+
lastName = lastName,
73+
)
7074
) {
7175
logcat { "PIR-WEB: PirWebAddNameToCurrentUserProfileMessageHandler: duplicate name detected" }
7276
jsMessaging.sendResponse(
@@ -76,15 +80,6 @@ class PirWebAddNameToCurrentUserProfileMessageHandler @Inject constructor(
7680
return
7781
}
7882

79-
// Add the name to the current user profile
80-
pirWebOnboardingStateHolder.names.add(
81-
PirWebOnboardingStateHolder.Name(
82-
firstName = request.first,
83-
middleName = request.middle,
84-
lastName = request.last,
85-
),
86-
)
87-
8883
jsMessaging.sendResponse(
8984
jsMessage = jsMessage,
9085
response = PirWebMessageResponse.DefaultResponse.SUCCESS,

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/dashboard/messaging/handlers/PirWebGetCurrentUserProfileMessageHandler.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import com.duckduckgo.js.messaging.api.JsMessageCallback
2424
import com.duckduckgo.js.messaging.api.JsMessaging
2525
import com.duckduckgo.pir.impl.dashboard.messaging.PirDashboardWebMessages
2626
import com.duckduckgo.pir.impl.dashboard.messaging.model.PirWebMessageResponse
27-
import com.duckduckgo.pir.impl.dashboard.state.PirWebOnboardingStateHolder.Name
2827
import com.duckduckgo.pir.impl.store.PirRepository
28+
import com.duckduckgo.pir.impl.store.db.UserName
2929
import com.squareup.anvil.annotations.ContributesMultibinding
3030
import javax.inject.Inject
3131
import kotlinx.coroutines.CoroutineScope
@@ -67,7 +67,13 @@ class PirWebGetCurrentUserProfileMessageHandler @Inject constructor(
6767
return@launch
6868
}
6969

70-
val names = profiles.map { Name(it.firstName, it.middleName, it.lastName) }
70+
val names = profiles.map {
71+
UserName(
72+
firstName = it.firstName,
73+
lastName = it.lastName,
74+
middleName = it.middleName,
75+
)
76+
}
7177
val addresses = profiles.map { it.addresses }.flatten()
7278
val birthYear = profiles.firstOrNull()?.birthYear ?: 0
7379

@@ -80,13 +86,13 @@ class PirWebGetCurrentUserProfileMessageHandler @Inject constructor(
8086
middle = it.middleName ?: "",
8187
last = it.lastName,
8288
)
83-
},
89+
}.distinct(),
8490
addresses = addresses.map {
8591
PirWebMessageResponse.GetCurrentUserProfileResponse.Address(
8692
city = it.city,
8793
state = it.state,
8894
)
89-
},
95+
}.distinct(),
9096
birthYear = birthYear,
9197
),
9298
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2025 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.pir.impl.dashboard.messaging.handlers
18+
19+
import com.duckduckgo.di.scopes.ActivityScope
20+
import com.duckduckgo.js.messaging.api.JsMessage
21+
import com.duckduckgo.js.messaging.api.JsMessageCallback
22+
import com.duckduckgo.js.messaging.api.JsMessaging
23+
import com.duckduckgo.pir.impl.dashboard.messaging.PirDashboardWebMessages
24+
import com.duckduckgo.pir.impl.dashboard.messaging.model.PirWebMessageRequest
25+
import com.duckduckgo.pir.impl.dashboard.messaging.model.PirWebMessageResponse
26+
import com.duckduckgo.pir.impl.dashboard.state.PirWebOnboardingStateHolder
27+
import com.squareup.anvil.annotations.ContributesMultibinding
28+
import javax.inject.Inject
29+
import logcat.logcat
30+
31+
@ContributesMultibinding(
32+
scope = ActivityScope::class,
33+
boundType = PirWebJsMessageHandler::class,
34+
)
35+
class PirWebRemoveAddressAtIndexFromCurrentUserProfileMessageHandler @Inject constructor(
36+
private val pirWebOnboardingStateHolder: PirWebOnboardingStateHolder,
37+
) : PirWebJsMessageHandler() {
38+
39+
override val message: PirDashboardWebMessages = PirDashboardWebMessages.REMOVE_ADDRESS_AT_INDEX_FROM_CURRENT_USER_PROFILE
40+
41+
override fun process(
42+
jsMessage: JsMessage,
43+
jsMessaging: JsMessaging,
44+
jsMessageCallback: JsMessageCallback?,
45+
) {
46+
logcat { "PIR-WEB: PirWebRemoveAddressAtIndexFromCurrentUserProfileMessageHandler: process $message" }
47+
48+
val request = jsMessage.toRequestMessage(PirWebMessageRequest.RemoveAddressAtIndexFromCurrentUserProfileRequest::class)
49+
if (request == null || !pirWebOnboardingStateHolder.removeAddressAtIndex(request.index)) {
50+
logcat { "PIR-WEB: PirWebRemoveAddressAtIndexFromCurrentUserProfileMessageHandler: failed to remove address at index ${request?.index}" }
51+
jsMessaging.sendResponse(
52+
jsMessage = jsMessage,
53+
response = PirWebMessageResponse.DefaultResponse.ERROR,
54+
)
55+
return
56+
}
57+
58+
jsMessaging.sendResponse(
59+
jsMessage = jsMessage,
60+
response = PirWebMessageResponse.DefaultResponse.SUCCESS,
61+
)
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2025 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.pir.impl.dashboard.messaging.handlers
18+
19+
import com.duckduckgo.di.scopes.ActivityScope
20+
import com.duckduckgo.js.messaging.api.JsMessage
21+
import com.duckduckgo.js.messaging.api.JsMessageCallback
22+
import com.duckduckgo.js.messaging.api.JsMessaging
23+
import com.duckduckgo.pir.impl.dashboard.messaging.PirDashboardWebMessages
24+
import com.duckduckgo.pir.impl.dashboard.messaging.model.PirWebMessageRequest
25+
import com.duckduckgo.pir.impl.dashboard.messaging.model.PirWebMessageResponse
26+
import com.duckduckgo.pir.impl.dashboard.state.PirWebOnboardingStateHolder
27+
import com.squareup.anvil.annotations.ContributesMultibinding
28+
import javax.inject.Inject
29+
import logcat.logcat
30+
31+
@ContributesMultibinding(
32+
scope = ActivityScope::class,
33+
boundType = PirWebJsMessageHandler::class,
34+
)
35+
class PirWebRemoveNameAtIndexFromCurrentUserProfileMessageHandler @Inject constructor(
36+
private val pirWebOnboardingStateHolder: PirWebOnboardingStateHolder,
37+
) : PirWebJsMessageHandler() {
38+
39+
override val message: PirDashboardWebMessages = PirDashboardWebMessages.REMOVE_NAME_AT_INDEX_FROM_CURRENT_USER_PROFILE
40+
41+
override fun process(
42+
jsMessage: JsMessage,
43+
jsMessaging: JsMessaging,
44+
jsMessageCallback: JsMessageCallback?,
45+
) {
46+
logcat { "PIR-WEB: PirWebRemoveNameAtIndexFromCurrentUserProfileMessageHandler: process $message" }
47+
48+
val request = jsMessage.toRequestMessage(PirWebMessageRequest.RemoveNameAtIndexFromCurrentUserProfileRequest::class)
49+
if (request == null || !pirWebOnboardingStateHolder.removeNameAtIndex(request.index)) {
50+
logcat { "PIR-WEB: PirWebRemoveNameAtIndexFromCurrentUserProfileMessageHandler: failed to remove name at index ${request?.index}" }
51+
jsMessaging.sendResponse(
52+
jsMessage = jsMessage,
53+
response = PirWebMessageResponse.DefaultResponse.ERROR,
54+
)
55+
return
56+
}
57+
58+
jsMessaging.sendResponse(
59+
jsMessage = jsMessage,
60+
response = PirWebMessageResponse.DefaultResponse.SUCCESS,
61+
)
62+
}
63+
}

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/dashboard/messaging/handlers/PirWebSaveProfileMessageHandler.kt

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ import com.duckduckgo.pir.impl.dashboard.state.PirWebOnboardingStateHolder
3030
import com.duckduckgo.pir.impl.scan.PirForegroundScanService
3131
import com.duckduckgo.pir.impl.scan.PirScanScheduler
3232
import com.duckduckgo.pir.impl.store.PirRepository
33-
import com.duckduckgo.pir.impl.store.db.Address
34-
import com.duckduckgo.pir.impl.store.db.UserName
35-
import com.duckduckgo.pir.impl.store.db.UserProfile
3633
import com.squareup.anvil.annotations.ContributesMultibinding
3734
import javax.inject.Inject
3835
import kotlinx.coroutines.CoroutineScope
@@ -65,10 +62,7 @@ class PirWebSaveProfileMessageHandler @Inject constructor(
6562
logcat { "PIR-WEB: PirWebSaveProfileMessageHandler: process $jsMessage" }
6663

6764
// validate that we have the complete profile information
68-
if (pirWebOnboardingStateHolder.names.isEmpty() ||
69-
pirWebOnboardingStateHolder.addresses.isEmpty() ||
70-
(pirWebOnboardingStateHolder.birthYear ?: 0) == 0
71-
) {
65+
if (!pirWebOnboardingStateHolder.isProfileComplete) {
7266
logcat { "PIR-WEB: PirWebSaveProfileMessageHandler: incomplete profile information" }
7367
jsMessaging.sendResponse(
7468
jsMessage = jsMessage,
@@ -78,7 +72,7 @@ class PirWebSaveProfileMessageHandler @Inject constructor(
7872
}
7973

8074
appCoroutineScope.launch(dispatcherProvider.io()) {
81-
val profiles = prepareUserProfiles()
75+
val profiles = pirWebOnboardingStateHolder.toUserProfiles()
8276
repository.saveUserProfiles(profiles)
8377

8478
// TODO check if all profiles were saved successfully
@@ -91,29 +85,4 @@ class PirWebSaveProfileMessageHandler @Inject constructor(
9185
scanScheduler.scheduleScans()
9286
}
9387
}
94-
95-
private fun prepareUserProfiles(): List<UserProfile> {
96-
val profiles = mutableListOf<UserProfile>()
97-
98-
pirWebOnboardingStateHolder.names.forEach { name ->
99-
pirWebOnboardingStateHolder.addresses.forEach { address ->
100-
profiles.add(
101-
UserProfile(
102-
userName = UserName(
103-
firstName = name.firstName,
104-
middleName = name.middleName,
105-
lastName = name.lastName,
106-
),
107-
birthYear = pirWebOnboardingStateHolder.birthYear ?: 0,
108-
addresses = Address(
109-
city = address.city,
110-
state = address.state,
111-
),
112-
),
113-
)
114-
}
115-
}
116-
117-
return profiles
118-
}
11988
}

0 commit comments

Comments
 (0)