Skip to content

Commit

Permalink
Merge pull request #1077 from anyproto/ios-2456-integration-of-middle…
Browse files Browse the repository at this point in the history
…ware

IOS-2456 Membership | Use tiers from API
  • Loading branch information
ignatovv authored Mar 28, 2024
2 parents 41c4399 + 479cb3a commit aa3d7c4
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,17 @@ struct MembershipCoordinator: View {
}

var body: some View {
MembershipModuleView(userMembershipPublisher: model.$userMembership.eraseToAnyPublisher()) { tier in
model.onTierSelected(tier: tier)
Group {
if model.showTiersLoadingError {
errorView
} else {
MembershipModuleView(
membership: model.userMembership,
tiers: model.tiers
) { tier in
model.onTierSelected(tier: tier)
}
}
}
.animation(.default, value: model.userMembership)

Expand All @@ -28,6 +37,17 @@ struct MembershipCoordinator: View {
}
}

var errorView: some View {
EmptyStateView(
title: Loc.Error.Common.title,
subtitle: Loc.Error.Common.message,
actionText: Loc.Error.Common.tryAgain
) {
model.loadTiers(noCache: false)
}
}


func tierSelection(tier: MembershipTierId) -> some View {
MembershipTierSelectionView(userMembership: model.userMembership, tierToDisplay: tier) { data in
model.onEmailDataSubmit(data: data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,24 @@ import Services
@MainActor
final class MembershipCoordinatorModel: ObservableObject {
@Published var userMembership: MembershipStatus = .empty
@Published var tiers: [MembershipTier] = []

@Published var showTiersLoadingError = false
@Published var showTier: MembershipTierId?
@Published var showSuccess: MembershipTierId?
@Published var emailVerificationData: EmailVerificationData?
@Published var emailUrl: URL?

@Injected(\.membershipService)
private var membershipService: MembershipServiceProtocol
@Injected(\.membershipStatusStorage)
private var membershipStatusStorage: MembershipStatusStorageProtocol
@Injected(\.accountManager)
private var accountManager: AccountManagerProtocol

init() {
membershipStatusStorage.status.assign(to: &$userMembership)
loadTiers(noCache: false)
}

func onTierSelected(tier: MembershipTierId) {
Expand All @@ -42,12 +47,23 @@ final class MembershipCoordinatorModel: ObservableObject {
func onSuccessfulValidation() {
emailVerificationData = nil
showTier = nil

loadTiers(noCache: true)

// https://linear.app/anytype/issue/IOS-2434/bottom-sheet-nesting
Task {
try await Task.sleep(seconds: 0.5)
showSuccess = .explorer
}
}

func loadTiers(noCache: Bool) {
Task {
do {
tiers = try await membershipService.getTiers(noCache: noCache)
showTiersLoadingError = false
} catch {
showTiersLoadingError = true
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ struct MembershipModuleView: View {
@StateObject private var model: MembershipModuleViewModel
@Environment(\.openURL) private var openURL

private let membership: MembershipStatus
private let tiers: [MembershipTier]

init(
userMembershipPublisher: AnyPublisher<MembershipStatus, Never>,
membership: MembershipStatus,
tiers: [MembershipTier],
onTierTap: @escaping (MembershipTierId) -> ()
) {
_model = StateObject(wrappedValue: MembershipModuleViewModel(
userMembershipPublisher: userMembershipPublisher,
onTierTap: onTierTap
))
self.membership = membership
self.tiers = tiers
_model = StateObject(wrappedValue: MembershipModuleViewModel(onTierTap: onTierTap))
}

var body: some View {
Expand All @@ -32,7 +35,7 @@ struct MembershipModuleView: View {
Spacer.fixedHeight(32)

baners
MembershipTierListView(userMembership: model.userMembership) {
MembershipTierListView(userMembership: membership, tiers: tiers) {
UISelectionFeedbackGenerator().selectionChanged()
model.onTierTap(tier: $0)
}
Expand Down Expand Up @@ -114,7 +117,8 @@ struct MembershipModuleView: View {
#Preview {
NavigationView {
MembershipModuleView(
userMembershipPublisher: .empty(),
membership: .empty,
tiers: [],
onTierTap: { _ in }
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,11 @@ import Combine


@MainActor
final class MembershipModuleViewModel: ObservableObject {
@Published var userMembership: MembershipStatus = .empty

final class MembershipModuleViewModel: ObservableObject {
private let onTierTap: (MembershipTierId) -> ()

init(
userMembershipPublisher: AnyPublisher<MembershipStatus, Never>,
onTierTap: @escaping (MembershipTierId) -> ()
) {
init(onTierTap: @escaping (MembershipTierId) -> ()) {
self.onTierTap = onTierTap
userMembershipPublisher.assign(to: &$userMembership)
}

func onTierTap(tier: MembershipTierId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Services

struct MembershipTierListView: View {
let userMembership: MembershipStatus
let tiers: [MembershipTier]
let onTierTap: (MembershipTierId) -> ()

var body: some View {
Expand All @@ -12,7 +13,7 @@ struct MembershipTierListView: View {
HStack(spacing: 20) {
Spacer.fixedWidth(0)

ForEach(userMembership.tierId.availableTiers) { tier in
ForEach(tiers.map { $0.id }) { tier in
MembershipTeirView(tierToDisplay: tier, userMembership: userMembership) {
onTierTap(tier)
}
Expand All @@ -39,7 +40,12 @@ struct MembershipTierListView: View {
dateEnds: .tomorrow,
paymentMethod: .methodCard,
anyName: ""
)
),
tiers: [
MembershipTier(id: .explorer),
MembershipTier(id: .builder),
MembershipTier(id: .coCreator)
]
) { _ in }

MembershipTierListView(
Expand All @@ -49,7 +55,12 @@ struct MembershipTierListView: View {
dateEnds: .tomorrow,
paymentMethod: .methodCard,
anyName: ""
)
),
tiers: [
MembershipTier(id: .explorer),
MembershipTier(id: .builder),
MembershipTier(id: .coCreator),
]
) { _ in }

MembershipTierListView(
Expand All @@ -59,7 +70,12 @@ struct MembershipTierListView: View {
dateEnds: .tomorrow,
paymentMethod: .methodCard,
anyName: ""
)
),
tiers: [
MembershipTier(id: .explorer),
MembershipTier(id: .builder),
MembershipTier(id: .coCreator)
]
) { _ in }

MembershipTierListView(
Expand All @@ -69,7 +85,12 @@ struct MembershipTierListView: View {
dateEnds: .tomorrow,
paymentMethod: .methodCard,
anyName: ""
)
),
tiers: [
MembershipTier(id: .custom(id: 0)),
MembershipTier(id: .builder),
MembershipTier(id: .coCreator)
]
) { _ in }


Expand All @@ -80,7 +101,11 @@ struct MembershipTierListView: View {
dateEnds: .tomorrow,
paymentMethod: .methodCard,
anyName: ""
)
),
tiers: [
MembershipTier(id: .builder),
MembershipTier(id: .coCreator)
]
) { _ in }

MembershipTierListView(
Expand All @@ -90,7 +115,10 @@ struct MembershipTierListView: View {
dateEnds: .tomorrow,
paymentMethod: .methodCard,
anyName: ""
)
),
tiers: [
MembershipTier(id: .coCreator)
]
) { _ in }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,6 @@ import Services
import AnytypeCore


extension Optional where Wrapped == MembershipTierId {
var availableTiers: [MembershipTierId] {
switch self {
case .none:
[.explorer, .builder, .coCreator ]
case .some(let tier):
switch tier {
case .custom(let id):
[.custom(id: id), .builder, .coCreator ]
case .explorer:
[.explorer, .builder, .coCreator ]
case .builder:
[.builder, .coCreator ]
case .coCreator:
[.coCreator ]
}
}
}
}

extension MembershipTierId {
var title: String {
switch self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Foundation

public protocol MembershipServiceProtocol {
func getStatus() async throws -> MembershipStatus
func getTiers(noCache: Bool) async throws -> [MembershipTier]

func getVerificationEmail(data: EmailVerificationData) async throws
func verifyEmailCode(code: String) async throws

Expand Down Expand Up @@ -36,48 +38,12 @@ final class MembershipService: MembershipServiceProtocol {
$0.requestedTier = tier.middlewareId
}).invoke(ignoreLogErrors: .hasInvalidChars, .tooLong, .tooShort)
}
}

// MARK: - Models
public extension Anytype_Model_Membership {
func asModel() -> MembershipStatus {
MembershipStatus(
tierId: MembershipTierId,
status: status,
dateEnds: Date(timeIntervalSince1970: TimeInterval(dateEnds)),
paymentMethod: paymentMethod,
anyName: requestedAnyName
)
}

var MembershipTierId: MembershipTierId? {
switch tier {
case 0:
nil
case 1:
.explorer
case 4:
.builder
case 5:
.coCreator
default:
.custom(id: tier)
}
}
}

// TODO: Use API
extension MembershipTierId {
var middlewareId: Int32 {
switch self {
case .explorer:
1
case .builder:
4
case .coCreator:
5
case .custom(let id):
id
}
public func getTiers(noCache: Bool) async throws -> [MembershipTier] {
return try await ClientCommands.membershipGetTiers(.with {
$0.locale = Locale.current.languageCode ?? "en"
$0.noCache = noCache
})
.invoke().tiers.filter { !$0.isTest }.compactMap { $0.asModel() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,6 @@ import Foundation
public typealias MembershipSubscriptionStatus = Anytype_Model_Membership.Status
public typealias MembershipPaymentMethod = Anytype_Model_Membership.PaymentMethod

public enum MembershipTierId: Hashable, Identifiable {
case explorer
case builder
case coCreator

case custom(id: Int32)

public var id: Self {
return self
}
}

public struct MembershipStatus: Equatable {
public let tierId: MembershipTierId?
Expand All @@ -38,3 +27,17 @@ public struct MembershipStatus: Equatable {
}
}


// MARK: - Middleware model mapping

public extension Anytype_Model_Membership {
func asModel() -> MembershipStatus {
MembershipStatus(
tierId: MembershipTierId(intId: tier),
status: status,
dateEnds: Date(timeIntervalSince1970: TimeInterval(dateEnds)),
paymentMethod: paymentMethod,
anyName: requestedAnyName
)
}
}
Loading

0 comments on commit aa3d7c4

Please sign in to comment.