Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions PresentationLayer/Constants/ColorEnum.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public enum ColorEnum: String {
case betaRewardsPrimary
case correctionRewardsFill
case correctionRewardsPrimary
case troRewardsFill
case troRewardsPrimary
case lastRun
case tooltip
case textDarkStable
Expand Down
10 changes: 10 additions & 0 deletions PresentationLayer/Extensions/DomainExtensions/BoostCode+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ extension BoostCode {
switch self {
case .betaReward:
return LocalizableString.RewardAnalytics.beta.localized
case .trov2:
return LocalizableString.RewardAnalytics.rollouts.localized
case .correction:
return LocalizableString.RewardAnalytics.compensation.localized
case .unknown:
Expand All @@ -24,6 +26,8 @@ extension BoostCode {
switch self {
case .betaReward:
return .betaRewardsPrimary
case .trov2:
return .troRewardsPrimary
case .correction:
return .correctionRewardsPrimary
case .unknown:
Expand All @@ -35,6 +39,8 @@ extension BoostCode {
switch self {
case .betaReward:
return .betaRewardsFill
case .trov2:
return .troRewardsFill
case .correction:
return .correctionRewardsFill
case .unknown:
Expand All @@ -46,6 +52,8 @@ extension BoostCode {
switch self {
case .betaReward:
return .betaRewardsPrimary
case .trov2:
return .troRewardsPrimary
case .correction:
return .correctionRewardsFill
case .unknown:
Expand All @@ -57,6 +65,8 @@ extension BoostCode {
switch self {
case .betaReward:
return LocalizableString.RewardAnalytics.betaRewards.localized
case .trov2:
return LocalizableString.RewardAnalytics.rolloutsRewards.localized
case .correction:
return LocalizableString.RewardAnalytics.compensationRewards.localized
case .unknown:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@
.foregroundColor(Color(colorEnum: .textWhite))
Spacer()

Text("+ \(rewards.toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)")
.font(.system(size: CGFloat(.caption), weight: .medium))
.foregroundColor(Color(colorEnum: .textWhite))
HStack(spacing: CGFloat(.minimumSpacing)) {
Text(LocalizableString.RewardDetails.boostSeeDetails.localized)
.font(.system(size: CGFloat(.caption)))

Text(FontIcon.chevronRight.rawValue)
.font(.fontAwesome(font: .FAPro, size: CGFloat(.caption)))
}
.foregroundStyle(Color(colorEnum: .textWhite))
}

HStack {
Expand All @@ -34,6 +39,14 @@

Spacer()
}

HStack {
Text("+ \(rewards.toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)")
.font(.system(size: CGFloat(.caption), weight: .medium))
.foregroundColor(Color(colorEnum: .textWhite))

Spacer()
}
}
.padding(CGFloat(.defaultSidePadding))
.background {
Expand All @@ -48,6 +61,6 @@
BoostsView(title: "Beta reward",
description: "Rewarded for participating in our beta reward program.",
rewards: 2.453543,
imageUrl: "https://s3-alpha-sig.figma.com/img/eb97/5518/24aa70629514355d092dfc646d9b51bd?Expires=1710720000&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=OVc-UV-lBgXfX~Nl1VFoL-JijJx72Wld-L40tKQBLBo2afCyJijAJWkRicakQ~celi0ACIuP8W~N2Ixev1roqtO9JAl2IW0u55fOQdITuhDYq0pcqW-Nen7vzvATzti9A-c-pm6IDE37Md7gc0dYgnM55HhR1GAM4FlEIx4~RWOYmOI5rOgXQl6wN7YCB1gv3WI3JvmA1YgZKxLoei0Adny6PVGOlmQYXacN3WMcy6EfPFUO4rVvk~lrgQIOBJi8bSOnVX8RFHZ0RMW9lPljynCPKgbpuwUl0X6djRmdku-ntEnlCCsFp0LF0d~Y-qEK-edLpT96KdG4MM7TS64Qsg__").wxmShadow()

Check warning on line 64 in PresentationLayer/UIComponents/Screens/DailyRewards/Components/BoostsView.swift

View workflow job for this annotation

GitHub Actions / swiftLint

Line Length Violation: Line should be 180 characters or less; currently it has 515 characters (line_length)
.padding()
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class RewardDetailsViewModel: ObservableObject {

func handleBoostTap(boost: NetworkDeviceRewardDetailsResponse.BoostReward) {
switch boost.code {
case .betaReward, .correction:
case .betaReward, .correction, .trov2:
let viewModel = ViewModelsFactory.getRewardsBoostViewModel(boost: boost, device: device, date: rewardDetailsResponse?.timestamp)
Router.shared.navigateTo(.rewardBoosts(viewModel))
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import SwiftUI
import Toolkit
import DomainLayer

struct RewardBoostsView: View {
@StateObject var viewModel: RewardBoostsViewModel
Expand Down Expand Up @@ -74,14 +75,7 @@ private extension RewardBoostsView {
.overlay(Color(colorEnum: .layer2))
}

BoostDetailsView(items: [.init(title: LocalizableString.Boosts.rewardableStationHours.localized,
value: (details.stationHours ?? 0).localizedFormatted),
.init(title: LocalizableString.Boosts.dailyTokensToBeRewarded.localized,
value: "\((details.maxDailyReward ?? 0.0).toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)"),
.init(title: LocalizableString.Boosts.totalTokensToBeRewarded.localized,
value: "\((details.maxTotalReward ?? 0.0).toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)"),
.init(title: LocalizableString.Boosts.boostPeriod.localized,
value: "\(details.boostStartDateString) - \(details.boostStopDateString)")])
BoostDetailsView(items: getDetailsItems(details: details))
}
}
}
Expand Down Expand Up @@ -132,6 +126,30 @@ private extension RewardBoostsView {
}
.WXMCardStyle()
}

func getDetailsItems(details: NetworkDeviceRewardBoostsResponse.Details) -> [BoostDetailsView.Item] {
var items = [BoostDetailsView.Item]()

if let stationHours = details.stationHours {
items.append(.init(title: LocalizableString.Boosts.rewardableStationHours.localized,
value: stationHours.localizedFormatted))
}

if let maxDailyReward = details.maxDailyReward {
items.append(.init(title: LocalizableString.Boosts.dailyTokensToBeRewarded.localized,
value: "\(maxDailyReward.toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)"))
}

if let maxTotalReward = details.maxTotalReward {
items.append(.init(title: LocalizableString.Boosts.totalTokensToBeRewarded.localized,
value: "\(maxTotalReward.toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)"))
}

items.append(.init(title: LocalizableString.Boosts.boostPeriod.localized,
value: "\(details.boostStartDateString) - \(details.boostStopDateString)"))

return items
}
}

#Preview {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,37 @@ struct StationRewardDetailsView: View {
Spacer()
}

let progress = details.completedPercentage ?? 0
ProgressView(value: Float(progress), total: 100)
.progressViewStyle(ProgressBarStyle(text: "\(progress)%",
textColor: Color(colorEnum: .textDarkStable),
bgColor: Color(colorEnum: code.primaryColor),
progressColor: Color(colorEnum: code.fillColor)))
.frame(height: 24)
if let progress = details.completedPercentage {
ProgressView(value: Float(progress), total: 100)
.progressViewStyle(ProgressBarStyle(text: "\(progress)%",
textColor: Color(colorEnum: .textDarkStable),
bgColor: Color(colorEnum: code.primaryColor),
progressColor: Color(colorEnum: code.fillColor)))
.frame(height: 24)
}
}

BoostDetailsView(items: [.init(title: LocalizableString.RewardAnalytics.totalTokensEarnedSoFar.localized,
value: (details.currentRewards ?? 0).toWXMTokenPrecisionString + " " + StringConstants.wxmCurrency),
.init(title: LocalizableString.Boosts.totalTokensToBeRewarded.localized,
value: (details.totalRewards ?? 0).toWXMTokenPrecisionString + " " + StringConstants.wxmCurrency),
.init(title: LocalizableString.Boosts.boostPeriod.localized,
value: "\(details.boostStartDateString) - \(details.boostStopDateString)")])
BoostDetailsView(items: boostDetailsItems)
}
}
}

private extension StationRewardDetailsView {
var boostDetailsItems: [BoostDetailsView.Item] {
var items = [BoostDetailsView.Item]()
if let currentRewards = details.currentRewards {
items.append(.init(title: LocalizableString.RewardAnalytics.totalTokensEarnedSoFar.localized,
value: currentRewards.toWXMTokenPrecisionString + " " + StringConstants.wxmCurrency))
}

if let totalRewards = details.totalRewards {
items.append(.init(title: LocalizableString.Boosts.totalTokensToBeRewarded.localized,
value: totalRewards.toWXMTokenPrecisionString + " " + StringConstants.wxmCurrency))
}

items.append(.init(title: LocalizableString.Boosts.boostPeriod.localized,
value: "\(details.boostStartDateString) - \(details.boostStopDateString)"))

return items
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
"type": "boost",
"code": "beta_rewards",
"value": 1.4353223
},
{
"type": "boost",
"code": "trov2",
"value": 1.4353223
}
]
},
Expand All @@ -78,6 +83,11 @@
"type": "boost",
"code": "correction",
"value": 1.4353223
},
{
"type": "boost",
"code": "trov2",
"value": 0.4353223
}
]
},
Expand All @@ -93,6 +103,11 @@
"type": "boost",
"code": "beta_rewards",
"value": 1.4353223
},
{
"type": "boost",
"code": "trov2",
"value": 1.2
}
]
},
Expand All @@ -108,6 +123,11 @@
"type": "boost",
"code": "beta_rewards",
"value": 1.4353223
},
{
"type": "boost",
"code": "trov2",
"value": 0.6353223
}
]
}
Expand Down Expand Up @@ -138,6 +158,12 @@
"boost_period_start": "2025-09-10T00:00:00.000Z",
"boost_period_end": "2025-09-11T00:00:00.000Z",
"completed_percentage": 100
},
{
"code": "trov2",
"type": "TROv2",
"boost_period_start": "2025-09-10T00:00:00.000Z",
"boost_period_end": "2025-09-11T00:00:00.000Z"
}
Comment on lines +162 to 167
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify intentionally missing fields in TROv2 details.

The TROv2 details entry omits current_rewards, total_rewards, and completed_percentage fields that are present in other boost detail entries (e.g., lines 136-143). If these fields are intentionally omitted for TROv2 boosts, ensure the UI handles their absence gracefully. Otherwise, add them for consistency.

Run the following script to check how the app handles optional detail fields:


🏁 Script executed:

#!/bin/bash
# Description: Verify handling of optional detail fields in TROv2

# Search for code that accesses these optional fields
rg -nP --type=swift -C3 '\b(currentRewards|totalRewards|completedPercentage)\b' -g '!*Test*'

Length of output: 29078


Include missing reward fields in TROv2 analytics mock

Add current_rewards, total_rewards, and completed_percentage to the TROv2 details entry so it aligns with the NetworkDeviceRewardsResponse.Details model and renders correctly in the UI.

🤖 Prompt for AI Agents
In
wxm-ios/DataLayer/DataLayer/Networking/Mock/Jsons/get_device_rewards_analytics_7d.json
around lines 162 to 167, the TROv2 details object is missing the required fields
current_rewards, total_rewards, and completed_percentage; update that JSON entry
to include these three fields with appropriate numeric values (e.g.,
current_rewards and total_rewards as numbers and completed_percentage as a
number between 0 and 100) so the mock conforms to
NetworkDeviceRewardsResponse.Details and the UI renders correctly.

]
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@
"actual_reward": 1.23,
"reward_score": 50,
"max_reward": 2.46
},
{
"code": "trov2",
"title": "TROv2 Rewards",
"description": "A reward boost used to distribute additional rewards to TROv2 devices",
"img_url": "https://i0.wp.com/weatherxm.com/wp-content/uploads/2023/12/Home-header-image-1200-x-1200-px-2.png",
"doc_url": "https://docs.weatherxm.com",
"actual_reward": 1.23,
"reward_score": 100
}
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,15 @@ public extension NetworkDeviceRewardDetailsResponse {
public enum BoostCode: Codable, RawRepresentable, Hashable, Comparable, Sendable {
case betaReward
case correction(String)
case trov2
case unknown(String)

public init?(rawValue: String) {
switch rawValue {
case "beta_rewards":
self = .betaReward
case "trov2":
self = .trov2
case let str where str.hasPrefix("correction"):
self = .correction(rawValue)
default:
Expand All @@ -131,6 +134,8 @@ public enum BoostCode: Codable, RawRepresentable, Hashable, Comparable, Sendable
switch self {
case .betaReward:
return "beta_rewards"
case .trov2:
return "trov2"
case .correction(let raw):
return raw
case .unknown(let raw):
Expand Down
6 changes: 6 additions & 0 deletions wxm-ios/Resources/Colors.xcassets/Boosts/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x62",
"green" : "0x2F",
"red" : "0xAA"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x80",
"green" : "0x3E",
"red" : "0xDE"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
3 changes: 3 additions & 0 deletions wxm-ios/Resources/Localizable/Localizable+RewardDetails.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extension LocalizableString {
case contactSupportButtonTitle
case unhandledBoostMessage
case rewardsBoostFailedTitle
case boostSeeDetails
}
}

Expand Down Expand Up @@ -229,6 +230,8 @@ extension LocalizableString.RewardDetails: WXMLocalizable {
return "reward_details_unhandled_boost_message"
case .rewardsBoostFailedTitle:
return "reward_details_rewards_boost_failed_title"
case .boostSeeDetails:
return "reward_details_boost_see_details"
}
}
}
Loading