From e9719414e91a323eba0758896c516d800b39643b Mon Sep 17 00:00:00 2001 From: Victor Bodinaud Date: Mon, 14 Oct 2024 17:02:14 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20Start=20Project?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlloVoisinsSwiftUI.xcodeproj/project.pbxproj | 15 ++ .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 + .../AlloVoisinsSwiftUIApp.swift | 4 +- AlloVoisinsSwiftUI/Components/File.swift | 159 ++++++++++++++++++ .../Components/FontRegistration.swift | 36 ++++ .../Extensions/Extension+Color.swift | 55 ++++++ .../Extensions/Extension+View.swift | 41 +++++ AlloVoisinsSwiftUI/Info.plist | 14 ++ .../Booster/BoosterConfirmationScreen.swift | 9 +- .../Booster/BoosterKnowAboutScreen.swift | 7 - .../BoosterSubscriptionManagementScreen.swift | 11 +- .../BoosterSubscriptionSelectionScreen.swift | 8 +- .../Screens/Modals/OnlyForPremierModal.swift | 7 +- .../RegulatedProfessionEditProfilModal.swift | 5 - .../Modals/RegulatedProfessionModal.swift | 5 - .../AlloVoisinReputationScreen.swift | 130 +++++++------- .../ContinueAsParticularScreen.swift | 1 + .../Resiliation/GetMoreRatingsScreen.swift | 8 +- .../Screens/Resiliation/MoreTimeScreen.swift | 8 +- .../Resiliation/OnlyProRequestsScreen.swift | 10 +- .../PersonalizedSupportScreen.swift | 10 +- .../Resiliation/ProfileCompletionScreen.swift | 1 + .../ResiliationCheckStepsScreen.swift | 68 +++----- .../ResiliationNavigationView.swift | 47 +----- .../Resiliation/ResiliationReasonScreen.swift | 54 +++--- .../Resiliation/ResizePerimeterScreen.swift | 39 +++-- .../SoftwarePresentationScreen.swift | 1 + .../Resiliation/StatusChangeScreen.swift | 6 +- .../Screens/Resiliation/WebinaireScreen.swift | 10 +- .../ResiliationNavigationCoordinator.swift | 2 +- .../ViewModels/ResiliationViewModel.swift | 147 ++++++++++++++++ .../Booster/BoosterActiveHeaderView.swift | 12 +- .../Booster/BoosterHistoryCellView.swift | 9 +- .../Booster/BoosterLockedToPremierView.swift | 8 +- .../Views/Booster/BoosterPromotionView.swift | 2 +- .../Views/Booster/BoosterStatsView.swift | 7 - .../Booster/BoosterSubscriptionCardView.swift | 6 +- .../BoosterSubscriptionOptionsView.swift | 8 +- .../Compliments/ComplimentPillView.swift | 36 ++++ .../Views/Compliments/ComplimentView.swift | 46 +++++ .../ProfileComplimentListView.swift | 48 ++++++ .../Views/Components/NeighborBanner.swift | 5 - .../Views/Components/SQIcon.swift | 2 +- .../Views/Components/SQNavigationBar.swift | 51 ++++++ .../Views/Components/SQSocialBar.swift | 36 ++++ .../Views/Components/SQText.swift | 46 +++++ .../Views/Components/SQToast.swift | 3 - .../Views/Modals/OnlyForPremierView.swift | 8 +- .../Views/Resiliation/RatingStarsView.swift | 7 - .../ResiliationCheckStepView.swift | 39 ++++- .../ResiliationCheckStepsScreen.swift | 84 --------- .../Resiliation/TrialWarningCellView.swift | 7 +- .../Subscriptions/NewPerimeterCellView.swift | 34 ++++ 53 files changed, 985 insertions(+), 443 deletions(-) create mode 100644 AlloVoisinsSwiftUI.xcodeproj/xcuserdata/victor.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 AlloVoisinsSwiftUI/Components/File.swift create mode 100644 AlloVoisinsSwiftUI/Components/FontRegistration.swift create mode 100644 AlloVoisinsSwiftUI/Extensions/Extension+Color.swift create mode 100644 AlloVoisinsSwiftUI/Extensions/Extension+View.swift create mode 100644 AlloVoisinsSwiftUI/Info.plist create mode 100644 AlloVoisinsSwiftUI/Views/Compliments/ComplimentPillView.swift create mode 100644 AlloVoisinsSwiftUI/Views/Compliments/ComplimentView.swift create mode 100644 AlloVoisinsSwiftUI/Views/Compliments/ProfileComplimentListView.swift create mode 100644 AlloVoisinsSwiftUI/Views/Components/SQSocialBar.swift create mode 100644 AlloVoisinsSwiftUI/Views/Components/SQText.swift delete mode 100644 AlloVoisinsSwiftUI/Views/Resiliation/ResiliationCheckStepsScreen.swift create mode 100644 AlloVoisinsSwiftUI/Views/Subscriptions/NewPerimeterCellView.swift diff --git a/AlloVoisinsSwiftUI.xcodeproj/project.pbxproj b/AlloVoisinsSwiftUI.xcodeproj/project.pbxproj index 7cd5783..b729520 100644 --- a/AlloVoisinsSwiftUI.xcodeproj/project.pbxproj +++ b/AlloVoisinsSwiftUI.xcodeproj/project.pbxproj @@ -10,9 +10,22 @@ 57282ACB2CBD2810000C443E /* AlloVoisinsSwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AlloVoisinsSwiftUI.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + 57282BA72CBD579A000C443E /* Exceptions for "AlloVoisinsSwiftUI" folder in "AlloVoisinsSwiftUI" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = 57282ACA2CBD2810000C443E /* AlloVoisinsSwiftUI */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + /* Begin PBXFileSystemSynchronizedRootGroup section */ 57282ACD2CBD2810000C443E /* AlloVoisinsSwiftUI */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + 57282BA72CBD579A000C443E /* Exceptions for "AlloVoisinsSwiftUI" folder in "AlloVoisinsSwiftUI" target */, + ); path = AlloVoisinsSwiftUI; sourceTree = ""; }; @@ -255,6 +268,7 @@ DEVELOPMENT_TEAM = WVH3Y23X7X; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = AlloVoisinsSwiftUI/Info.plist; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -284,6 +298,7 @@ DEVELOPMENT_TEAM = WVH3Y23X7X; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = AlloVoisinsSwiftUI/Info.plist; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; diff --git a/AlloVoisinsSwiftUI.xcodeproj/xcuserdata/victor.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/AlloVoisinsSwiftUI.xcodeproj/xcuserdata/victor.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..dac434d --- /dev/null +++ b/AlloVoisinsSwiftUI.xcodeproj/xcuserdata/victor.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/AlloVoisinsSwiftUI/AlloVoisinsSwiftUIApp.swift b/AlloVoisinsSwiftUI/AlloVoisinsSwiftUIApp.swift index 8d01a3e..cc298d1 100644 --- a/AlloVoisinsSwiftUI/AlloVoisinsSwiftUIApp.swift +++ b/AlloVoisinsSwiftUI/AlloVoisinsSwiftUIApp.swift @@ -11,7 +11,9 @@ import SwiftUI struct AlloVoisinsSwiftUIApp: App { var body: some Scene { WindowGroup { - ContentView() + NavigationStack { + ResiliationNavigationView(resiliationType: .apProWithTrial) + } } } } diff --git a/AlloVoisinsSwiftUI/Components/File.swift b/AlloVoisinsSwiftUI/Components/File.swift new file mode 100644 index 0000000..e4ff520 --- /dev/null +++ b/AlloVoisinsSwiftUI/Components/File.swift @@ -0,0 +1,159 @@ +// +// ResponsiveSheetWrapper.swift +// +// Created by Bacem Ben Afia on 04/08/2022. +// ba.bessem@gmail.com + +import SwiftUI +import UIKit + +//MARK: - ViewModifier +fileprivate struct ResponsiveSheetWrapper: ViewModifier { + + @Environment(\.presentationMode) var presentationMode: Binding + + func body(content: Content) -> some View { + /// check device type (ipad sheet are centred / iPhone sheet pinned to bottom ) + if UIDevice.current.userInterfaceIdiom == .phone { + ZStack (alignment: .bottom){ + Color(UIColor.systemBackground.withAlphaComponent(0.01)) + .onTapGesture { + // tap outside the view to dismiss + presentationMode.wrappedValue.dismiss() + } + .edgesIgnoringSafeArea(.all) + VStack { + /// the small thumb for bottom sheet native like + content + } + /// redesign the content + .asResponsiveSheetContent() + } + /// remove system background + .clearSheetSystemBackground() + .edgesIgnoringSafeArea(.bottom) + } else { + ZStack { + Color(UIColor.systemBackground.withAlphaComponent(0.01)) + .onTapGesture { + // tap outside the view to dismiss + presentationMode.wrappedValue.dismiss() + } + content + /// redesign the content + .asResponsiveSheetContent() + } + /// remove system background + .clearSheetSystemBackground() + .edgesIgnoringSafeArea(.all) + } + } +} + +fileprivate struct ResponsiveSheetContent: ViewModifier { + /// ResponsiveSheetContent will create the form of a bottom sheet (apply corners radius for both iPad an iPhone sheet) + @Environment(\.safeAreaInsets) private var safeAreaInsets + + func body(content: Content) -> some View { + if UIDevice.current.userInterfaceIdiom == .phone { + content + .padding(.bottom, safeAreaInsets.bottom) + .background(Color(UIColor.systemBackground)) + .cornerRadius(10, corners: [.topLeft, .topRight]) + } else { + content + .padding() + .background(Color(UIColor.systemBackground)) + .cornerRadius(10, corners: [.allCorners]) + } + } +} + +fileprivate struct ClearBackgroundViewModifier: ViewModifier { + + func body(content: Content) -> some View { + content + .background(ClearBackgroundView()) + } +} + +fileprivate struct CornerRadiusStyle: ViewModifier { + var radius: CGFloat + var corners: UIRectCorner + + struct CornerRadiusShape: Shape { + + var radius = CGFloat.infinity + var corners = UIRectCorner.allCorners + + func path(in rect: CGRect) -> Path { + let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) + return Path(path.cgPath) + } + } + + func body(content: Content) -> some View { + content + .clipShape(CornerRadiusShape(radius: radius, corners: corners)) + } +} + +//MARK: - UIViewRepresentable +fileprivate struct ClearBackgroundView: UIViewRepresentable { + /// The Key + func makeUIView(context: Context) -> UIView { + let view = UIView() + DispatchQueue.main.async { + /// GOD BLESS UI KIT + /// Target sheet system background view + /// Apply clear Color + view.superview?.superview?.backgroundColor = .clear + } + return view + } + + func updateUIView(_ uiView: UIView, context: Context) {} +} + +//MARK: - View Extension +extension View { + /// Return a formatted View Based on Device Type + /// if iPad => Centred Alert-Like View + /// if iPhone => Bottom Sheet View + /// That's all folks + func asResponsiveSheet() -> some View { + self.modifier(ResponsiveSheetWrapper()) + } + + fileprivate func asResponsiveSheetContent() -> some View { + self.modifier(ResponsiveSheetContent()) + } + + fileprivate func clearSheetSystemBackground() -> some View { + self.modifier(ClearBackgroundViewModifier()) + } + + func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View { + self.modifier(CornerRadiusStyle(radius: radius, corners: corners)) + } +} + +//MARK: - EnvironmentKey & Values +fileprivate struct SafeAreaInsetsKey: EnvironmentKey { + static var defaultValue: EdgeInsets { + (UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.safeAreaInsets ?? .zero).insets + } +} + +fileprivate extension EnvironmentValues { + var safeAreaInsets: EdgeInsets { + self[SafeAreaInsetsKey.self] + } +} + +//MARK: - UIEdgeInsets Extension +fileprivate extension UIEdgeInsets { + var insets: EdgeInsets { + EdgeInsets(top: top, leading: left, bottom: bottom, trailing: right) + } +} diff --git a/AlloVoisinsSwiftUI/Components/FontRegistration.swift b/AlloVoisinsSwiftUI/Components/FontRegistration.swift new file mode 100644 index 0000000..536fe2a --- /dev/null +++ b/AlloVoisinsSwiftUI/Components/FontRegistration.swift @@ -0,0 +1,36 @@ +// +// FontRegistration.swift +// +// +// Created by Victor on 12/06/2024. +// + +import CoreGraphics +import CoreText +import UIKit + +struct FontRegistration { + public enum FontError: Swift.Error { + case failedToRegisterFont + } + + func registerFonts() throws { + let fontNames = [ + "TTChocolates-Bold-Italic", + "TTChocolates-Bold", + "TTChocolates-DemiBold", + "TTChocolates-Medium", + "TTChocolates-MediumIt" + ] + + for name in fontNames { + guard let asset = NSDataAsset(name: "Fonts/\(name)"), + let provider = CGDataProvider(data: asset.data as NSData), + let font = CGFont(provider), + CTFontManagerRegisterGraphicsFont(font, nil) + else { + throw FontError.failedToRegisterFont + } + } + } +} diff --git a/AlloVoisinsSwiftUI/Extensions/Extension+Color.swift b/AlloVoisinsSwiftUI/Extensions/Extension+Color.swift new file mode 100644 index 0000000..8e85c59 --- /dev/null +++ b/AlloVoisinsSwiftUI/Extensions/Extension+Color.swift @@ -0,0 +1,55 @@ +// +// Extension+Color.swift +// +// +// Created by Victor on 12/06/2024. +// + +import SwiftUI + +extension Color { + static func sqRoyal(_ variant: Int = 60) -> Color { + return Color("ROYAL_\(variant)") + } + + static func sqPurple(_ variant: Int = 60) -> Color { + return Color("PURPLE_\(variant)") + } + + static func sqNeutral(_ variant: Int = 60) -> Color { + return Color("NEUTRAL_\(variant)") + } + + static func sqOrange(_ variant: Int = 60) -> Color { + return Color("ORANGE_\(variant)") + } + + static func sqGreen(_ variant: Int = 60) -> Color { + return Color("GREEN_\(variant)") + } + + static func sqYellow(_ variant: Int = 60) -> Color { + return Color("YELLOW_\(variant)") + } + + static func sqGold(_ variant: Int = 60) -> Color { + return Color("GOLD_\(variant)") + } + + static func sqBlue(_ variant: Int = 60) -> Color { + return Color("BLUE_\(variant)") + } + + static func sqGrape(_ variant: Int = 60) -> Color { + return Color("GRAPE_\(variant)") + } + + static let sqSemanticRed = Color("SEMANTIC_RED") + static let sqSemanticOrange = Color("SEMANTIC_CRITICAL") + static let sqSemanticGreen = Color("SEMANTIC_GREEN") + static let sqSemanticBlue = Color("SEMANTIC_BLUE") + static let sqSemanticCritical = Color("SEMANTIC_CRITICAL") + static let sqSemanticWarning = Color("SEMANTIC_WARNING") + static let sqSemanticPositive = Color("SEMANTIC_GREEN") + static let sqSemanticNegative = Color("SEMANTIC_RED") +} diff --git a/AlloVoisinsSwiftUI/Extensions/Extension+View.swift b/AlloVoisinsSwiftUI/Extensions/Extension+View.swift new file mode 100644 index 0000000..aa5e67e --- /dev/null +++ b/AlloVoisinsSwiftUI/Extensions/Extension+View.swift @@ -0,0 +1,41 @@ +// +// Extension+View.swift +// +// +// Created by Victor on 19/06/2024. +// + +import SwiftUI + +//extension View { +// func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View { +// clipShape( RoundedCorner(radius: radius, corners: corners) ) +// } +//} +// +//struct RoundedCorner: Shape { +// let radius: CGFloat +// let corners: UIRectCorner +// +// init(radius: CGFloat = .infinity, corners: UIRectCorner = .allCorners) { +// self.radius = radius +// self.corners = corners +// } +// +// func path(in rect: CGRect) -> Path { +// let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) +// return Path(path.cgPath) +// } +//} + +extension View { + func sqFont(_ font: SQTextFont, size: CGFloat = 16) -> some View { + self.font(.custom(font.rawValue, size: size)) + } +} + +extension Font { + static func sq(_ font: SQTextFont, size: CGFloat = 16) -> Font { + .custom(font.rawValue, size: size) + } +} diff --git a/AlloVoisinsSwiftUI/Info.plist b/AlloVoisinsSwiftUI/Info.plist new file mode 100644 index 0000000..24afeb0 --- /dev/null +++ b/AlloVoisinsSwiftUI/Info.plist @@ -0,0 +1,14 @@ + + + + + UIAppFonts + + TTChocolates-Bold.otf + TTChocolates-Bold-Italic.otf + TTChocolates-DemiBold.otf + TTChocolates-Medium.otf + TTChocolates-MediumIt.otf + + + diff --git a/AlloVoisinsSwiftUI/Screens/Booster/BoosterConfirmationScreen.swift b/AlloVoisinsSwiftUI/Screens/Booster/BoosterConfirmationScreen.swift index 3ef5777..8bf62e9 100644 --- a/AlloVoisinsSwiftUI/Screens/Booster/BoosterConfirmationScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Booster/BoosterConfirmationScreen.swift @@ -8,13 +8,6 @@ import SwiftUI struct BoosterConfirmationScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { ZStack { @@ -22,7 +15,7 @@ struct BoosterConfirmationScreen: View { .ignoresSafeArea() VStack { VStack(spacing: 32) { - Image("booster_logo", bundle: Bundle.module) + Image("booster_logo") .resizable() .frame(width: 210, height: 180) SQText("C’est confirmé !", size: 18, font: .bold) diff --git a/AlloVoisinsSwiftUI/Screens/Booster/BoosterKnowAboutScreen.swift b/AlloVoisinsSwiftUI/Screens/Booster/BoosterKnowAboutScreen.swift index d7a10e3..21e68d3 100644 --- a/AlloVoisinsSwiftUI/Screens/Booster/BoosterKnowAboutScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Booster/BoosterKnowAboutScreen.swift @@ -8,13 +8,6 @@ import SwiftUI struct BoosterKnowAboutScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { ScrollView(showsIndicators: false) { diff --git a/AlloVoisinsSwiftUI/Screens/Booster/BoosterSubscriptionManagementScreen.swift b/AlloVoisinsSwiftUI/Screens/Booster/BoosterSubscriptionManagementScreen.swift index ed50ac9..e6aa01b 100644 --- a/AlloVoisinsSwiftUI/Screens/Booster/BoosterSubscriptionManagementScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Booster/BoosterSubscriptionManagementScreen.swift @@ -8,11 +8,6 @@ import SwiftUI struct BoosterSubscriptionManagementScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch {} - } @State var selectedValue = 0 @State var presentControls = false @@ -43,9 +38,9 @@ struct BoosterSubscriptionManagementScreen: View { } } } - .bottomSheet(isShowing: $presentControls, content: { - BoosterSubscriptionOptionsView() - }) +// .bottomSheet(isShowing: $presentControls, content: { +// BoosterSubscriptionOptionsView() +// }) } } diff --git a/AlloVoisinsSwiftUI/Screens/Booster/BoosterSubscriptionSelectionScreen.swift b/AlloVoisinsSwiftUI/Screens/Booster/BoosterSubscriptionSelectionScreen.swift index 58e6e3b..f9aee68 100644 --- a/AlloVoisinsSwiftUI/Screens/Booster/BoosterSubscriptionSelectionScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Booster/BoosterSubscriptionSelectionScreen.swift @@ -39,12 +39,6 @@ struct BoosterSubscriptionSelectionScreen: View { var cancellation: Bool = true @State var mode: BoosterSubscriptionMode = .edit @State var isNotPremier = false - - init() { - do { - try FontRegistration().registerFonts() - } catch {} - } var body: some View { NavigationView { @@ -63,7 +57,7 @@ struct BoosterSubscriptionSelectionScreen: View { VStack(alignment: .trailing) { BoosterLockedToPremierView() VStack(spacing: 16) { - Image("booster_logo", bundle: Bundle.module) + Image("booster_logo") .resizable() .frame(width: 210, height: 180) diff --git a/AlloVoisinsSwiftUI/Screens/Modals/OnlyForPremierModal.swift b/AlloVoisinsSwiftUI/Screens/Modals/OnlyForPremierModal.swift index 7751fd7..79a57d8 100644 --- a/AlloVoisinsSwiftUI/Screens/Modals/OnlyForPremierModal.swift +++ b/AlloVoisinsSwiftUI/Screens/Modals/OnlyForPremierModal.swift @@ -8,11 +8,6 @@ import SwiftUI struct OnlyForPremierModal: View { - init() { - do { - try FontRegistration().registerFonts() - } catch {} - } var body: some View { NavigationView { @@ -23,7 +18,7 @@ struct OnlyForPremierModal: View { .fill(Color.sqOrange(50)) .frame(height: 200) VStack(alignment: .leading, spacing: 32) { - Image("only_for_premier", bundle: .module) + Image("only_for_premier") .resizable() .frame(width: 307, height: 108) } diff --git a/AlloVoisinsSwiftUI/Screens/Modals/RegulatedProfessionEditProfilModal.swift b/AlloVoisinsSwiftUI/Screens/Modals/RegulatedProfessionEditProfilModal.swift index a01f57a..cee9b0e 100644 --- a/AlloVoisinsSwiftUI/Screens/Modals/RegulatedProfessionEditProfilModal.swift +++ b/AlloVoisinsSwiftUI/Screens/Modals/RegulatedProfessionEditProfilModal.swift @@ -8,11 +8,6 @@ import SwiftUI struct RegulatedProfessionEditProfilModal: View { - init() { - do { - try FontRegistration().registerFonts() - } catch {} - } var body: some View { VStack { diff --git a/AlloVoisinsSwiftUI/Screens/Modals/RegulatedProfessionModal.swift b/AlloVoisinsSwiftUI/Screens/Modals/RegulatedProfessionModal.swift index 19bf64d..2a06e36 100644 --- a/AlloVoisinsSwiftUI/Screens/Modals/RegulatedProfessionModal.swift +++ b/AlloVoisinsSwiftUI/Screens/Modals/RegulatedProfessionModal.swift @@ -8,11 +8,6 @@ import SwiftUI struct RegulatedProfessionModal: View { - init() { - do { - try FontRegistration().registerFonts() - } catch {} - } var body: some View { VStack() { diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/AlloVoisinReputationScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/AlloVoisinReputationScreen.swift index 503ec9a..00655e5 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/AlloVoisinReputationScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/AlloVoisinReputationScreen.swift @@ -8,86 +8,84 @@ import SwiftUI struct AlloVoisinReputationScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch {} - } var body: some View { - VStack(spacing: 32) { - VStack { - SQText("Le saviez-vous ?", size: 20, font: .bold) - SQText("AlloVoisins en France, c’est :", size: 20, font: .bold) - } - VStack { - SQText("4,5 millions", size: 32, font: .bold) - SQText("de membres, partout en France") - } - .padding(16) - .background(Color.white) - .cornerRadius(8) - VStack(spacing: 8) { + VStack(spacing: 16) { + VStack(spacing: 32) { VStack { - HStack { - SQIcon(.star, size: .xxl, type: .solid, color: .sqGold(50)) - SQText("4,6/5", size: 32, font: .bold) - } - SQText("Calculé à partir de 107,1 k avis") + SQText("Le saviez-vous ?", size: 20, font: .bold) + SQText("AlloVoisins en France, c’est :", size: 20, font: .bold) } - HStack(spacing: 16) { - HStack(spacing: 2) { - SQIcon(.apple_brand, size: .s) - SQText("App Store", size: 10) + VStack { + SQText("4,5 millions", size: 32, font: .bold) + SQText("de membres, partout en France") + } + .padding(16) + .background(Color.white) + .cornerRadius(8) + VStack(spacing: 8) { + VStack { + HStack { + SQIcon(.star, size: .xxl, type: .solid, color: .sqGold(50)) + SQText("4,6/5", size: 32, font: .bold) + } + SQText("Calculé à partir de 107,1 k avis") } - HStack(spacing: 2) { - SQIcon(.play_store_brand, size: .s) - SQText("Google Play", size: 10) + HStack(spacing: 16) { + HStack(spacing: 2) { + SQIcon(.apple_brand, size: .s) + SQText("App Store", size: 10) + } + HStack(spacing: 2) { + SQIcon(.play_store_brand, size: .s) + SQText("Google Play", size: 10) + } + HStack(spacing: 2) { + SQIcon(.star_trustpilot_brand, size: .s) + SQText("Trustpilot", size: 10) + } } - HStack(spacing: 2) { - SQIcon(.star_trustpilot_brand, size: .s) - SQText("Trustpilot", size: 10) + } + .padding(16) + .background(Color.white) + .cornerRadius(8) + VStack { + SQText("La presse en parle", size: 24, font: .bold) + HStack(spacing: 16) { + Image("m6") + .resizable() + .scaledToFit() + .frame(height: 24) + Image("rtl") + .resizable() + .scaledToFit() + .frame(height: 24) + Image("tf1") + .resizable() + .scaledToFit() + .frame(height: 24) + Image("bfm") + .resizable() + .scaledToFit() + .frame(height: 24) } } + .padding(16) + .background(Color.white) + .cornerRadius(8) + SQButton("Conserver mon abonnement", color: .sqNeutral(100), textColor: .white) { + + } } .padding(16) - .background(Color.white) + .background(Color.sqBlue(10)) .cornerRadius(8) - VStack { - SQText("La presse en parle", size: 24, font: .bold) - HStack(spacing: 16) { - Image("m6", bundle: Bundle.module) - .resizable() - .scaledToFit() - .frame(height: 24) - Image("rtl", bundle: Bundle.module) - .resizable() - .scaledToFit() - .frame(height: 24) - Image("tf1", bundle: Bundle.module) - .resizable() - .scaledToFit() - .frame(height: 24) - Image("bfm", bundle: Bundle.module) - .resizable() - .scaledToFit() - .frame(height: 24) - } - } - .padding(16) - .background(Color.white) - .cornerRadius(8) - SQButton("Conserver mon abonnement", color: .sqNeutral(100), textColor: .white) { + + SQButton("J’ai compris, mais je souhaite résilier", color: .white, textSize: 13) { } } - .padding(16) - .background(Color.sqBlue(10)) - .cornerRadius(8) - - SQButton("J’ai compris, mais je souhaite résilier", color: .white, textSize: 13) { - - } + .sqNavigationBar(title: "Ne partez pas !") } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/ContinueAsParticularScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/ContinueAsParticularScreen.swift index 28450c2..7bce276 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/ContinueAsParticularScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/ContinueAsParticularScreen.swift @@ -23,6 +23,7 @@ struct ContinueAsParticularScreen: View { } } } + .sqNavigationBar(title: "Ne partez pas !") .padding(16) } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/GetMoreRatingsScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/GetMoreRatingsScreen.swift index 6173d3f..48fe734 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/GetMoreRatingsScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/GetMoreRatingsScreen.swift @@ -8,13 +8,6 @@ import SwiftUI struct GetMoreRatingsScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { VStack(spacing: 16) { @@ -47,6 +40,7 @@ struct GetMoreRatingsScreen: View { } } + .sqNavigationBar(title: "Ne partez pas !") .padding() } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/MoreTimeScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/MoreTimeScreen.swift index 610a4ea..70cc79b 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/MoreTimeScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/MoreTimeScreen.swift @@ -8,13 +8,6 @@ import SwiftUI struct MoreTimeScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { VStack(spacing: 16) { @@ -39,6 +32,7 @@ struct MoreTimeScreen: View { } } + .sqNavigationBar(title: "Ne partez pas !") .padding() } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/OnlyProRequestsScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/OnlyProRequestsScreen.swift index 68e7976..38dba42 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/OnlyProRequestsScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/OnlyProRequestsScreen.swift @@ -8,20 +8,13 @@ import SwiftUI struct OnlyProRequestsScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { VStack(spacing: 16) { VStack(spacing: 32) { SQText("Demandes réservées aux pros", size: 20, font: .bold) .multilineTextAlignment(.center) - Image("only_for_pro", bundle: Bundle.module) + Image("only_for_pro") .resizable() .scaledToFit() .frame(height: 60) @@ -47,6 +40,7 @@ struct OnlyProRequestsScreen: View { } } + .sqNavigationBar(title: "Ne partez pas !") .padding() } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/PersonalizedSupportScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/PersonalizedSupportScreen.swift index ca8a6a8..07aec94 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/PersonalizedSupportScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/PersonalizedSupportScreen.swift @@ -8,20 +8,13 @@ import SwiftUI struct PersonalizedSupportScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { VStack(spacing: 16) { VStack(spacing: 32) { SQText("Bénéficiez d’un accompagnement personnalisé.", size: 20, font: .bold) .multilineTextAlignment(.center) - Image("assistance", bundle: Bundle.module) + Image("assistance") .resizable() .scaledToFit() .frame(height: 100) @@ -42,6 +35,7 @@ struct PersonalizedSupportScreen: View { } } + .sqNavigationBar(title: "Ne partez pas !") .padding() } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/ProfileCompletionScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/ProfileCompletionScreen.swift index a0f7f07..d6d3b64 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/ProfileCompletionScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/ProfileCompletionScreen.swift @@ -63,6 +63,7 @@ struct ProfileCompletionScreen: View { } } + .sqNavigationBar(title: "Ne partez pas !") .padding() } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationCheckStepsScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationCheckStepsScreen.swift index e3b0c72..db0a70d 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationCheckStepsScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationCheckStepsScreen.swift @@ -1,5 +1,5 @@ // -// ResiliationCheckStepView.swift +// ResiliationCheckStepsScreen.swift // Sequoia // // Created by Victor on 10/10/2024. @@ -7,58 +7,21 @@ import SwiftUI -private struct ResiliationCheckStepView: View { - var checkStep: ResiliationCheckStep - @Binding var isSelected: Bool - - var body: some View { - VStack(alignment: .leading) { - RoundedRectangle(cornerRadius: 4, style: .continuous) - .fill(isSelected ? Color.sqNeutral(100) : .clear) - .stroke(isSelected ? Color.sqNeutral(100) : Color.sqNeutral(30), lineWidth: 1) - .frame(width: 20, height: 20) - HStack(alignment: .center) { - Spacer() - Image(checkStep.image, bundle: Bundle.main) - .resizable() - .scaledToFit() - .frame(height: 100) - Spacer() - } - HStack { - SQText(checkStep.text) - .multilineTextAlignment(.leading) - Spacer() - } - .frame(maxWidth: .infinity) - } - .padding() - .frame(maxWidth: .infinity) - .overlay( - RoundedRectangle(cornerRadius: 8) - .stroke(Color.sqNeutral(30), lineWidth: 1) - ) - .onTapGesture { - self.isSelected.toggle() - } - } -} - struct ResiliationCheckStepsScreen: View { + @State var nextStep: Bool = false @StateObject var viewModel: ResiliationViewModel - var steps: [ResiliationCheckStep] { - viewModel.resiliationCheckSteps - } @State private var selectedSteps: Set = [] var allStepsSelected: Bool { - selectedSteps.count == steps.count + selectedSteps.count == viewModel.resiliationCheckSteps.count } var body: some View { ScrollView { VStack(spacing: 16) { - ForEach(steps, id: \.self) { step in + SQText("En résiliant votre abonnement vous renoncez à :", size: 18, font: .bold) + .multilineTextAlignment(.center) + ForEach(viewModel.resiliationCheckSteps, id: \.self) { step in ResiliationCheckStepView( checkStep: step, isSelected: Binding( @@ -73,9 +36,28 @@ struct ResiliationCheckStepsScreen: View { ) ) } + + if viewModel.resiliationType == .apProWithTrial || viewModel.resiliationType == .apProWithTrialWithBooster { + TrialWarningCellView() + } + + HStack { + SQButton("Annuler", color: .sqNeutral(100), isFull: false) { + + } + SQButton("Continuer", color: .sqNeutral(100), textColor: .white) { + nextStep.toggle() + } + .disabled(!allStepsSelected) + } + .padding() } .padding() } + .navigationDestination(isPresented: $nextStep) { + ResiliationReasonScreen(viewModel: viewModel) + } + .sqNavigationBar(title: "Demander la résiliation") } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationNavigationView.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationNavigationView.swift index 801e0fa..b8f99e7 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationNavigationView.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationNavigationView.swift @@ -1,5 +1,5 @@ // -// ResiliationProcess.swift +// ResiliationNavigationView.swift // AlloVoisinsSwiftUI // // Created by Victor on 14/10/2024. @@ -32,57 +32,16 @@ import SwiftUI struct ResiliationNavigationView: View { - @StateObject private var coordinator = ResiliationNavigationCoordinator() @StateObject private var viewModel: ResiliationViewModel init(resiliationType: ResiliationType) { - let coordinator = ResiliationNavigationCoordinator() - self._coordinator = StateObject(wrappedValue: coordinator) self._viewModel = StateObject(wrappedValue: ResiliationViewModel(resiliationType: resiliationType)) } var body: some View { - NavigationStack(path: $coordinator.path) { + NavigationStack { ResiliationCheckStepsScreen(viewModel: viewModel) - .navigationDestination(for: ResiliationNavigationCoordinator.Screen.self) { screen in - switch screen { - case .reason: - ResiliationReasonScreen(viewModel: viewModel) - case .promotional(let promotionalScreen): - getPromotionalScreen(for: promotionalScreen) - case .final: - EmptyView() - case .checkSteps: - EmptyView() - } - } - } - .environmentObject(coordinator) - } - - @ViewBuilder - private func getPromotionalScreen(for screen: ResiliationPromotionalScreen) -> some View { - switch screen { - case .webinarPresentation: - WebinaireScreen() - case .profileCompletion: - ProfileCompletionScreen() - case .editPerimeter: - ResizePerimeterScreen() - case .onlyProSearches: - OnlyProRequestsScreen() - case .oneMonthBoosterOffered: - BoosterSubscriptionSelectionScreen() - case .allovoisinsPromotion: - AlloVoisinReputationScreen() - case .extendMyTrialPeriod: - MoreTimeScreen() - case .askPartProStatusChangeWithCancellation, .askPartProStatusChange: - StatusChangeScreen() - case .customerSupportForPro, .customerSupportForPart: - PersonalizedSupportScreen() - default: - EmptyView() + .navigationBarTitle("Résiliation", displayMode: .inline) } } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationReasonScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationReasonScreen.swift index 608e89f..dcd50da 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationReasonScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/ResiliationReasonScreen.swift @@ -8,42 +8,42 @@ import SwiftUI struct ResiliationReasonScreen: View { - @State var selectedIndex: Int? = nil - @State var resiliationOtherMotif: String = "" + @Environment(\.dismiss) var dismiss + @ObservedObject var viewModel: ResiliationViewModel + @State private var selectedIndex: Int? = nil + @State private var resiliationOtherMotif: String = "" var body: some View { - VStack(spacing: 16) { - SQRadio(title: "Aidez-nous à nous améliorer : précisez le motif de votre résiliation", - options: [ - "Je ne suis pas un professionnel, c’est une erreur", - "Je reçois des demandes mais je n’ai pas assez de réponses positives à mes propositions", - "Je ne reçois pas assez de demandes", - "Je n’ai pas eu suffisamment de temps pour me faire une opinion", - "J’ai des demandes, mais elles ne m’intéressent pas", - "Je n’ai pas compris le fonctionnement de l’abonnement Premier", - "Je suis sur d’autres plateformes plus intéressantes", - "Autre", - ], - selectedIndex: $selectedIndex) - if selectedIndex == 7 { + ScrollView { + VStack(spacing: 16) { + SQRadio(title: "Aidez-nous à nous améliorer : précisez le motif de votre résiliation", + options: viewModel.resiliationReasons.map { $0.text }, + selectedIndex: $selectedIndex) + if selectedIndex == viewModel.resiliationReasons.count - 1 { SQTextField("", placeholder: "Précisez-nous le motif de votre résiliation", text: $resiliationOtherMotif) } - HStack { - SQButton("Annuler", color: .sqNeutral(100), isFull: false) { - + HStack { + SQButton("Annuler", color: .sqNeutral(100), isFull: false) { + dismiss() + } + SQButton("Continuer", color: .sqNeutral(100), textColor: .white) { + // TODO: Aller au prochain promotional screen + if let index = selectedIndex { + let selectedReason = viewModel.resiliationReasons[index] + viewModel.setSelectedReason(selectedReason) + } + } + .disabled(selectedIndex == nil) } - SQButton("Continuer", color: .sqNeutral(100), textColor: .white) { - - } - .disabled(selectedIndex == nil) + Spacer() } - Spacer() } .padding() + .sqNavigationBar(title: "Demander la résiliation") } } -#Preview { - ResiliationReasonScreen() -} + #Preview { + ResiliationReasonScreen(viewModel: ResiliationViewModel(resiliationType: .apProWithTrial)) + } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/ResizePerimeterScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/ResizePerimeterScreen.swift index b80385a..7e2f464 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/ResizePerimeterScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/ResizePerimeterScreen.swift @@ -9,29 +9,32 @@ import SwiftUI struct ResizePerimeterScreen: View { var body: some View { - VStack(spacing: 32) { - SQText("Augmentez votre périmètre afin de recevoir plus de demandes", size: 20, font: .bold) - .multilineTextAlignment(.center) - Image("perimeter", bundle: Bundle.module) - .resizable() - .scaledToFit() - .frame(height: 140) - VStack { - SQText("Le saviez-vous ?", font: .demiBold) - SQText("Si vous le souhaitez, vous pouvez modifier à tout moment votre abonnement en élargissant votre périmètre d’intervention.") + VStack(spacing: 16) { + VStack(spacing: 32) { + SQText("Augmentez votre périmètre afin de recevoir plus de demandes", size: 20, font: .bold) .multilineTextAlignment(.center) + Image("perimeter") + .resizable() + .scaledToFit() + .frame(height: 140) + VStack { + SQText("Le saviez-vous ?", font: .demiBold) + SQText("Si vous le souhaitez, vous pouvez modifier à tout moment votre abonnement en élargissant votre périmètre d’intervention.") + .multilineTextAlignment(.center) + } + SQButton("Modifier mon périmètre", color: .sqOrange(50), textColor: .white) { + + } } - SQButton("Modifier mon périmètre", color: .sqOrange(50), textColor: .white) { + .padding(16) + .background(Color.sqOrange(10)) + .cornerRadius(8) + + SQButton("J’ai compris, mais je souhaite résilier", color: .white, textSize: 13) { } } - .padding(16) - .background(Color.sqOrange(10)) - .cornerRadius(8) - - SQButton("J’ai compris, mais je souhaite résilier", color: .white, textSize: 13) { - - } + .sqNavigationBar(title: "Ne partez pas !") } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/SoftwarePresentationScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/SoftwarePresentationScreen.swift index 9fe588f..e4998f5 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/SoftwarePresentationScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/SoftwarePresentationScreen.swift @@ -44,6 +44,7 @@ struct SoftwarePresentationScreen: View { } } } + .sqNavigationBar(title: "Ne partez pas !") .padding() } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/StatusChangeScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/StatusChangeScreen.swift index b0ab8d6..4c6beac 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/StatusChangeScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/StatusChangeScreen.swift @@ -8,11 +8,6 @@ import SwiftUI struct StatusChangeScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch {} - } var body: some View { VStack { @@ -30,6 +25,7 @@ struct StatusChangeScreen: View { .background(Color.sqOrange(10)) .cornerRadius(8) } + .sqNavigationBar(title: "Changer de statut") .padding() } } diff --git a/AlloVoisinsSwiftUI/Screens/Resiliation/WebinaireScreen.swift b/AlloVoisinsSwiftUI/Screens/Resiliation/WebinaireScreen.swift index e5a48e8..c35363b 100644 --- a/AlloVoisinsSwiftUI/Screens/Resiliation/WebinaireScreen.swift +++ b/AlloVoisinsSwiftUI/Screens/Resiliation/WebinaireScreen.swift @@ -8,20 +8,13 @@ import SwiftUI struct WebinaireScreen: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { VStack(spacing: 16) { VStack(spacing: 32) { SQText("Webinaire spécial Pro", size: 20, font: .bold) .multilineTextAlignment(.center) - Image("webinaire", bundle: Bundle.module) + Image("webinaire") .resizable() .scaledToFit() .frame(height: 140) @@ -43,6 +36,7 @@ struct WebinaireScreen: View { } } + .sqNavigationBar(title: "Ne partez pas !") } } diff --git a/AlloVoisinsSwiftUI/ViewModels/ResiliationNavigationCoordinator.swift b/AlloVoisinsSwiftUI/ViewModels/ResiliationNavigationCoordinator.swift index 0de2ef6..d3b68e6 100644 --- a/AlloVoisinsSwiftUI/ViewModels/ResiliationNavigationCoordinator.swift +++ b/AlloVoisinsSwiftUI/ViewModels/ResiliationNavigationCoordinator.swift @@ -5,4 +5,4 @@ // Created by Victor on 14/10/2024. // -import Foundation +import SwiftUI diff --git a/AlloVoisinsSwiftUI/ViewModels/ResiliationViewModel.swift b/AlloVoisinsSwiftUI/ViewModels/ResiliationViewModel.swift index 383801b..6eeacfc 100644 --- a/AlloVoisinsSwiftUI/ViewModels/ResiliationViewModel.swift +++ b/AlloVoisinsSwiftUI/ViewModels/ResiliationViewModel.swift @@ -6,3 +6,150 @@ // import Foundation +import SwiftUICore + +class ResiliationViewModel: ObservableObject { + @Published var resiliationType: ResiliationType + @Published var resiliationCheckSteps: [ResiliationCheckStep] + @Published var resiliationReasons: [ResiliationReason] + @Published var selectedReason: ResiliationReason? + @Published var promotionalScreens: [ResiliationPromotionalScreen] = [] + @Published var currentScreen: Screen = .checkSteps + + enum Screen: Equatable { + case checkSteps + case reason + case promotional(ResiliationPromotionalScreen) + case final + } + + init(resiliationType: ResiliationType) { + self.resiliationType = resiliationType + self.resiliationCheckSteps = ResiliationCheckStep.getCheckSteps(for: resiliationType) + self.resiliationReasons = ResiliationReason.getRadioResiliation(for: resiliationType) + } + + func moveToReason() { + currentScreen = .reason + } + + func setSelectedReason(_ reason: ResiliationReason) { + selectedReason = reason + promotionalScreens = selectResiliationPromotions( + availablePromotions: getAvailablePromotionalScreens(for: reason), + eligibleScreens: getEligiblePromotionalScreens() + ) + + if promotionalScreens.isEmpty { + currentScreen = .final + } else { + currentScreen = .promotional(promotionalScreens.removeFirst()) + } + } + + func moveToNextPromotionalScreen() { + if !promotionalScreens.isEmpty { + currentScreen = .promotional(promotionalScreens.removeFirst()) + } else { + currentScreen = .final + } + } + + private func selectResiliationPromotions(availablePromotions: [ResiliationPromotionalScreen], eligibleScreens: [ResiliationPromotionalScreen]) -> [ResiliationPromotionalScreen] { + let shuffledArray1 = availablePromotions.shuffled() + + let commonPromotions = shuffledArray1.filter { promotion in + eligibleScreens.contains(promotion) + } + + let result = commonPromotions.map { $0 } + + return Array(result.prefix(2)) + } + + private func getAvailablePromotionalScreens(for reason: ResiliationReason) -> [ResiliationPromotionalScreen] { + switch reason { + case .noPositiveResponses: + return [.externalReview, .webinarPresentation, .profileCompletion] + case .uninterestingRequests: + return [.webinarPresentation, .editPerimeter, .onlyProSearches] + case .lowDemand: + return [.externalReview, .profileCompletion, .editPerimeter, .oneMonthBoosterOffered] + case .betterPlatforms: + // TODO: Rajouter présentation Logiciel + return [.oneMonthBoosterOffered, .allovoisinsPromotion, .extendMyTrialPeriod, .webinarPresentation] + case .notPro: + return [.askPartProStatusChange] + case .insufficientTime: + return [.extendMyTrialPeriod] + case .misunderstoodPremier: + // TODO: Check si c'est le bon .cusrommerSupport* + return [.webinarPresentation, .customerSupportForPro] + default: + return [.allovoisinsPromotion] + } + } + + private func getEligiblePromotionalScreens() -> [ResiliationPromotionalScreen] { + return [.extendMyTrialPeriod, .profileCompletion, .allovoisinsPromotion] + } + + private func getPromotionalScreen(for screen: ResiliationPromotionalScreen) -> any View { + switch screen { + case .externalReview: + break + case .webinarPresentation: + return WebinaireScreen() + case .profileCompletion: + return ProfileCompletionScreen() + case .editPerimeter: + return ResizePerimeterScreen() + case .onlyProSearches: + return OnlyProRequestsScreen() + case .oneMonthBoosterOffered: + return BoosterSubscriptionSelectionScreen() + case .allovoisinsPromotion: + return AlloVoisinReputationScreen() + case .extendMyTrialPeriod: + return MoreTimeScreen() + case .askPartProStatusChangeWithCancellation: + return StatusChangeScreen() + case .customerSupportForPro: + return PersonalizedSupportScreen() + case .customerSupportForPart: + return PersonalizedSupportScreen() + case .askPartProStatusChange: + return StatusChangeScreen() + case .ordersPresentation: + break + } + + return EmptyView() + } + + @ViewBuilder + func getPromotionalScreenNew(for screen: ResiliationPromotionalScreen) -> some View { + switch screen { + case .webinarPresentation: + WebinaireScreen() + case .profileCompletion: + ProfileCompletionScreen() + case .editPerimeter: + ResizePerimeterScreen() + case .onlyProSearches: + OnlyProRequestsScreen() + case .oneMonthBoosterOffered: + BoosterSubscriptionSelectionScreen() + case .allovoisinsPromotion: + AlloVoisinReputationScreen() + case .extendMyTrialPeriod: + MoreTimeScreen() + case .askPartProStatusChangeWithCancellation, .askPartProStatusChange: + StatusChangeScreen() + case .customerSupportForPro, .customerSupportForPart: + PersonalizedSupportScreen() + default: + EmptyView() + } + } +} diff --git a/AlloVoisinsSwiftUI/Views/Booster/BoosterActiveHeaderView.swift b/AlloVoisinsSwiftUI/Views/Booster/BoosterActiveHeaderView.swift index 1bd752c..0a02d09 100644 --- a/AlloVoisinsSwiftUI/Views/Booster/BoosterActiveHeaderView.swift +++ b/AlloVoisinsSwiftUI/Views/Booster/BoosterActiveHeaderView.swift @@ -8,16 +8,10 @@ import SwiftUI struct BoosterActiveHeaderView: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } + var body: some View { VStack { - Image("booster_logo", bundle: Bundle.module) + Image("booster_logo") .resizable() .frame(width: 93, height: 80) VStack { @@ -30,7 +24,7 @@ struct BoosterActiveHeaderView: View { .frame(maxWidth: .infinity) .overlay( ZStack(alignment: .topLeading) { - Image("booster_corner", bundle: Bundle.module) + Image("booster_corner") .resizable() .frame(width: 50, height: 50) .cornerRadius(8, corners: [.topLeft]) diff --git a/AlloVoisinsSwiftUI/Views/Booster/BoosterHistoryCellView.swift b/AlloVoisinsSwiftUI/Views/Booster/BoosterHistoryCellView.swift index 03eafb7..36659a9 100644 --- a/AlloVoisinsSwiftUI/Views/Booster/BoosterHistoryCellView.swift +++ b/AlloVoisinsSwiftUI/Views/Booster/BoosterHistoryCellView.swift @@ -10,13 +10,6 @@ import SwiftUI struct BoosterHistoryCellView: View { var isEnded: Bool = false - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { ZStack { HStack(alignment: .center) { @@ -28,7 +21,7 @@ struct BoosterHistoryCellView: View { } .overlay( ZStack(alignment: .topLeading) { - Image("booster_corner", bundle: Bundle.module) + Image("booster_corner") .resizable() .frame(width: 50, height: 50) .cornerRadius(8, corners: [.topLeft, .bottomLeft]) diff --git a/AlloVoisinsSwiftUI/Views/Booster/BoosterLockedToPremierView.swift b/AlloVoisinsSwiftUI/Views/Booster/BoosterLockedToPremierView.swift index 70e735f..bae6845 100644 --- a/AlloVoisinsSwiftUI/Views/Booster/BoosterLockedToPremierView.swift +++ b/AlloVoisinsSwiftUI/Views/Booster/BoosterLockedToPremierView.swift @@ -8,13 +8,7 @@ import SwiftUI struct BoosterLockedToPremierView: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } + var body: some View { HStack { SQIcon(.lock_keyhole, size: .xs, type: .solid, color: .white) diff --git a/AlloVoisinsSwiftUI/Views/Booster/BoosterPromotionView.swift b/AlloVoisinsSwiftUI/Views/Booster/BoosterPromotionView.swift index 8822051..7695143 100644 --- a/AlloVoisinsSwiftUI/Views/Booster/BoosterPromotionView.swift +++ b/AlloVoisinsSwiftUI/Views/Booster/BoosterPromotionView.swift @@ -25,7 +25,7 @@ struct BoosterPromotionView: View { .foregroundColor(.sqRoyal()) .overlay( ZStack(alignment: .topLeading) { - Image("booster_corner", bundle: Bundle.module) + Image("booster_corner") .resizable() .frame(width: 50, height: 50) .cornerRadius(8, corners: .topLeft) diff --git a/AlloVoisinsSwiftUI/Views/Booster/BoosterStatsView.swift b/AlloVoisinsSwiftUI/Views/Booster/BoosterStatsView.swift index 4466d7f..35a4167 100644 --- a/AlloVoisinsSwiftUI/Views/Booster/BoosterStatsView.swift +++ b/AlloVoisinsSwiftUI/Views/Booster/BoosterStatsView.swift @@ -8,13 +8,6 @@ import SwiftUI struct BoosterStatsView: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { VStack(spacing: 8) { diff --git a/AlloVoisinsSwiftUI/Views/Booster/BoosterSubscriptionCardView.swift b/AlloVoisinsSwiftUI/Views/Booster/BoosterSubscriptionCardView.swift index 69fbd7b..267c0c2 100644 --- a/AlloVoisinsSwiftUI/Views/Booster/BoosterSubscriptionCardView.swift +++ b/AlloVoisinsSwiftUI/Views/Booster/BoosterSubscriptionCardView.swift @@ -18,10 +18,6 @@ struct BoosterSubscriptionCardView: View { } init(id: Int, selectedId: Binding, currentOption: Bool = false, isFree: Bool = false) { - do { - try FontRegistration().registerFonts() - } catch {} - self.id = id self._selectedId = selectedId self.currentOption = currentOption @@ -61,7 +57,7 @@ struct BoosterSubscriptionCardView: View { .padding(.top, 30) .padding([.leading, .trailing]) - Image("booster_corner_light", bundle: Bundle.module) + Image("booster_corner_light") .resizable() .frame(width: 50, height: 50) .position(x: 25, y: 25) diff --git a/AlloVoisinsSwiftUI/Views/Booster/BoosterSubscriptionOptionsView.swift b/AlloVoisinsSwiftUI/Views/Booster/BoosterSubscriptionOptionsView.swift index f142282..d17a901 100644 --- a/AlloVoisinsSwiftUI/Views/Booster/BoosterSubscriptionOptionsView.swift +++ b/AlloVoisinsSwiftUI/Views/Booster/BoosterSubscriptionOptionsView.swift @@ -8,13 +8,7 @@ import SwiftUI struct BoosterSubscriptionOptionsView: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } + var body: some View { VStack { HStack { diff --git a/AlloVoisinsSwiftUI/Views/Compliments/ComplimentPillView.swift b/AlloVoisinsSwiftUI/Views/Compliments/ComplimentPillView.swift new file mode 100644 index 0000000..c28d58d --- /dev/null +++ b/AlloVoisinsSwiftUI/Views/Compliments/ComplimentPillView.swift @@ -0,0 +1,36 @@ +// +// ComplimentPillView.swift +// +// +// Created by Victor on 31/07/2024. +// + +import SwiftUI + +struct ComplimentPillView: View { + var body: some View { + HStack(spacing: 4) { + VStack { + SQIcon(.gen_euro_sign, size: .s, color: .sqGreen(100)) + } + .padding(3) + .frame(width: 32, height: 32, alignment: .center) + .background(Color.sqGreen(10)) + .cornerRadius(32) + SQText("Excellent rapport qualité/prix", size: 12, font: .demiBold) + } + .padding(.leading, 1) + .padding(.trailing, 16) + .padding(.vertical, 1) + .cornerRadius(40) + .overlay( + RoundedRectangle(cornerRadius: 40) + .inset(by: 0.5) + .stroke(Color.sqNeutral(20), lineWidth: 1) + ) + } +} + +#Preview { + ComplimentPillView() +} diff --git a/AlloVoisinsSwiftUI/Views/Compliments/ComplimentView.swift b/AlloVoisinsSwiftUI/Views/Compliments/ComplimentView.swift new file mode 100644 index 0000000..6e46457 --- /dev/null +++ b/AlloVoisinsSwiftUI/Views/Compliments/ComplimentView.swift @@ -0,0 +1,46 @@ +// +// ComplimentView.swift +// +// +// Created by Victor on 31/07/2024. +// + +import SwiftUI + +struct ComplimentView: View { + var body: some View { + ZStack(alignment: .topTrailing) { + VStack(spacing: 4) { + VStack { + SQIcon(.gen_euro_sign, size: .xl, color: .sqGreen(100)) + } + .frame(width: 56, height: 56, alignment: .center) + .background(Color.sqGreen(10)) + .cornerRadius(100) + SQText("Excellent rapport qualité/prix", size: 11, font: .demiBold) + .multilineTextAlignment(.center) + .foregroundColor(Color.sqNeutral(90)) + } + .padding(.top, 4) + .frame(width: 87) + + HStack { + SQText("1", size: 11, font: .bold) + .foregroundColor(Color.sqNeutral()) + .padding(.horizontal, 6) + .frame(height: 16) + .background(.white) + .cornerRadius(30) + .overlay( + RoundedRectangle(cornerRadius: 30) + .stroke(Color.sqNeutral(60), lineWidth: 1) + ) + } + .padding(.trailing, 10) + } + } +} + +#Preview { + ComplimentView() +} diff --git a/AlloVoisinsSwiftUI/Views/Compliments/ProfileComplimentListView.swift b/AlloVoisinsSwiftUI/Views/Compliments/ProfileComplimentListView.swift new file mode 100644 index 0000000..d9e53ea --- /dev/null +++ b/AlloVoisinsSwiftUI/Views/Compliments/ProfileComplimentListView.swift @@ -0,0 +1,48 @@ +// +// ProfileComplimentListView.swift +// +// +// Created by Victor on 31/07/2024. +// + +import SwiftUI + +private struct Compliment: Identifiable { + let id: Int +} + +struct ProfileComplimentListView: View { + private let compliments: [Compliment] = [ + Compliment(id: 1), + Compliment(id: 2), + Compliment(id: 3), + Compliment(id: 4), + Compliment(id: 5) + ] + + var body: some View { + VStack(alignment: .leading) { + SQText("Compliments reçus", size: 18, font: .bold) + .padding(.horizontal) + VStack(alignment: .center, spacing: 16) { + VStack(alignment: .leading) { + ForEach(Array(stride(from: 0, to: compliments.count, by: 3)), id: \.self) { index in + HStack(spacing: 24) { + ForEach(index ..< min(index + 3, compliments.count), id: \.self) { _ in + ComplimentView() + } + } + } + } + + Rectangle() + .frame(height: 16) + .foregroundColor(Color.sqNeutral(10)) + } + } + } +} + +#Preview { + ProfileComplimentListView() +} diff --git a/AlloVoisinsSwiftUI/Views/Components/NeighborBanner.swift b/AlloVoisinsSwiftUI/Views/Components/NeighborBanner.swift index 6fdb998..b68b297 100644 --- a/AlloVoisinsSwiftUI/Views/Components/NeighborBanner.swift +++ b/AlloVoisinsSwiftUI/Views/Components/NeighborBanner.swift @@ -8,11 +8,6 @@ import SwiftUI struct NeighborBanner: View { - init() { - do { - try FontRegistration().registerFonts() - } catch {} - } var body: some View { HStack(spacing: 8) { diff --git a/AlloVoisinsSwiftUI/Views/Components/SQIcon.swift b/AlloVoisinsSwiftUI/Views/Components/SQIcon.swift index ec498e8..f721a88 100644 --- a/AlloVoisinsSwiftUI/Views/Components/SQIcon.swift +++ b/AlloVoisinsSwiftUI/Views/Components/SQIcon.swift @@ -201,7 +201,7 @@ struct SQIcon: View { } var body: some View { - Image(type == .solid ? "\(name.rawValue)_solid" : name.rawValue, bundle: .module) + Image(type == .solid ? "\(name.rawValue)_solid" : name.rawValue) .resizable() .scaledToFit() .frame(height: customSize ?? size.rawValue) diff --git a/AlloVoisinsSwiftUI/Views/Components/SQNavigationBar.swift b/AlloVoisinsSwiftUI/Views/Components/SQNavigationBar.swift index e69de29..05a1b79 100644 --- a/AlloVoisinsSwiftUI/Views/Components/SQNavigationBar.swift +++ b/AlloVoisinsSwiftUI/Views/Components/SQNavigationBar.swift @@ -0,0 +1,51 @@ +// +// SQNavigationBar.swift +// AlloVoisinsSwiftUI +// +// Created by Victor on 14/10/2024. +// + +import SwiftUI + +struct SQNavigationBar: ViewModifier { + @Environment(\.presentationMode) var presentationMode + let title: String + + func body(content: Content) -> some View { + content + .navigationBarBackButtonHidden(true) + .navigationBarTitle(title, displayMode: .inline) + .navigationBarItems(leading: backButton) + .onAppear { + configureNavigationBarAppearance() + } + } + + private var backButton: some View { + Button(action: { + self.presentationMode.wrappedValue.dismiss() + }) { + Image(systemName: "chevron.left") + .foregroundColor(.black) + .imageScale(.large) + } + } + + private func configureNavigationBarAppearance() { + let appearance = UINavigationBarAppearance() + appearance.configureWithOpaqueBackground() + appearance.backgroundColor = .white + appearance.shadowColor = .gray.withAlphaComponent(0.3) + appearance.titleTextAttributes = [.foregroundColor: UIColor.black] + + UINavigationBar.appearance().standardAppearance = appearance + UINavigationBar.appearance().compactAppearance = appearance + UINavigationBar.appearance().scrollEdgeAppearance = appearance + } +} + +extension View { + func sqNavigationBar(title: String) -> some View { + self.modifier(SQNavigationBar(title: title)) + } +} diff --git a/AlloVoisinsSwiftUI/Views/Components/SQSocialBar.swift b/AlloVoisinsSwiftUI/Views/Components/SQSocialBar.swift new file mode 100644 index 0000000..393878e --- /dev/null +++ b/AlloVoisinsSwiftUI/Views/Components/SQSocialBar.swift @@ -0,0 +1,36 @@ +// +// SQSocialBar.swift +// +// +// Created by Victor on 18/07/2024. +// + +import SwiftUI + +struct SQSocialBar: View { + var style: SQSocialBarStyle = .full + + init(style: SQSocialBarStyle) { + self.style = style + } + + var body: some View { + VStack { + HStack { + + } + HStack { + + } + } + } +} + +enum SQSocialBarStyle { + case full + case compact +} + +#Preview { + SQSocialBar(style: .full) +} diff --git a/AlloVoisinsSwiftUI/Views/Components/SQText.swift b/AlloVoisinsSwiftUI/Views/Components/SQText.swift new file mode 100644 index 0000000..a1b322f --- /dev/null +++ b/AlloVoisinsSwiftUI/Views/Components/SQText.swift @@ -0,0 +1,46 @@ +// +// SQText.swift +// +// +// Created by Victor on 12/06/2024. +// + +import SwiftUI + +enum SQTextFont: String { + case medium = "TTChocolates-Medium" + case mediumItalic = "TTChocolates-MediumIt" + case demiBold = "TTChocolates-DemiBold" + case bold = "TTChocolates-Bold" + case boldItalic = "TTChocolates-Bold-Italic" +} + +struct SQText: View { + var text: String + var size: CGFloat + var font: SQTextFont + var textColor: Color + + init(_ text: String, size: CGFloat = 16, font: SQTextFont = .medium, textColor: Color = .sqNeutral(90)) { + self.text = text + self.size = size + self.font = font + self.textColor = textColor + } + + var body: some View { + Text(text) + .font(.custom(font.rawValue, size: size)) + .foregroundStyle(textColor) + } +} + +#Preview { + VStack(spacing: 10) { + SQText("Hello world!", font: .medium) + SQText("Hello world!", font: .mediumItalic) + SQText("Hello world!", size: 18, font: .demiBold) + SQText("Hello world!", font: .bold) + SQText("Hello world!", size: 18, font: .boldItalic) + } +} diff --git a/AlloVoisinsSwiftUI/Views/Components/SQToast.swift b/AlloVoisinsSwiftUI/Views/Components/SQToast.swift index 3a96479..db7093d 100644 --- a/AlloVoisinsSwiftUI/Views/Components/SQToast.swift +++ b/AlloVoisinsSwiftUI/Views/Components/SQToast.swift @@ -27,9 +27,6 @@ struct SQToast: View { } init(_ title: String = "", content: String, style: SQToastStyle = .success, hasClose: Bool = false) { - do { - try FontRegistration().registerFonts() - } catch {} self.title = title self.content = content self.style = style diff --git a/AlloVoisinsSwiftUI/Views/Modals/OnlyForPremierView.swift b/AlloVoisinsSwiftUI/Views/Modals/OnlyForPremierView.swift index 0ccc2b6..b0f5384 100644 --- a/AlloVoisinsSwiftUI/Views/Modals/OnlyForPremierView.swift +++ b/AlloVoisinsSwiftUI/Views/Modals/OnlyForPremierView.swift @@ -8,13 +8,7 @@ import SwiftUI struct OnlyForPremierView: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } + var body: some View { VStack(spacing: 8) { VStack(alignment: .leading, spacing: 8) { diff --git a/AlloVoisinsSwiftUI/Views/Resiliation/RatingStarsView.swift b/AlloVoisinsSwiftUI/Views/Resiliation/RatingStarsView.swift index 6438853..f4aa142 100644 --- a/AlloVoisinsSwiftUI/Views/Resiliation/RatingStarsView.swift +++ b/AlloVoisinsSwiftUI/Views/Resiliation/RatingStarsView.swift @@ -8,13 +8,6 @@ import SwiftUI struct RatingStarsView: View { - init() { - do { - try FontRegistration().registerFonts() - } catch { - - } - } var body: some View { HStack(alignment: .bottom) { diff --git a/AlloVoisinsSwiftUI/Views/Resiliation/ResiliationCheckStepView.swift b/AlloVoisinsSwiftUI/Views/Resiliation/ResiliationCheckStepView.swift index 77972bd..1b5d2ba 100644 --- a/AlloVoisinsSwiftUI/Views/Resiliation/ResiliationCheckStepView.swift +++ b/AlloVoisinsSwiftUI/Views/Resiliation/ResiliationCheckStepView.swift @@ -8,11 +8,46 @@ import SwiftUI struct ResiliationCheckStepView: View { + var checkStep: ResiliationCheckStep + @Binding var isSelected: Bool + var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + VStack(alignment: .leading) { + if isSelected { + Image("checked_neutral") + .frame(width: 20, height: 20) + } else { + Image("checkbox_unchecked") + .frame(width: 20, height: 20) + } + HStack(alignment: .center) { + Spacer() + Image(checkStep.image) + .resizable() + .scaledToFit() + .frame(height: 100) + Spacer() + } + HStack { + SQText(checkStep.text) + .multilineTextAlignment(.leading) + Spacer() + } + .frame(maxWidth: .infinity) + } + .padding() + .frame(maxWidth: .infinity) + .overlay( + RoundedRectangle(cornerRadius: 8) + .stroke(Color.sqNeutral(30), lineWidth: 1) + ) + .onTapGesture { + self.isSelected.toggle() + } } } #Preview { - ResiliationCheckStepView() + ResiliationCheckStepView(checkStep: .marketing, isSelected: .constant(true)) + .padding() } diff --git a/AlloVoisinsSwiftUI/Views/Resiliation/ResiliationCheckStepsScreen.swift b/AlloVoisinsSwiftUI/Views/Resiliation/ResiliationCheckStepsScreen.swift deleted file mode 100644 index e3b0c72..0000000 --- a/AlloVoisinsSwiftUI/Views/Resiliation/ResiliationCheckStepsScreen.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// ResiliationCheckStepView.swift -// Sequoia -// -// Created by Victor on 10/10/2024. -// - -import SwiftUI - -private struct ResiliationCheckStepView: View { - var checkStep: ResiliationCheckStep - @Binding var isSelected: Bool - - var body: some View { - VStack(alignment: .leading) { - RoundedRectangle(cornerRadius: 4, style: .continuous) - .fill(isSelected ? Color.sqNeutral(100) : .clear) - .stroke(isSelected ? Color.sqNeutral(100) : Color.sqNeutral(30), lineWidth: 1) - .frame(width: 20, height: 20) - HStack(alignment: .center) { - Spacer() - Image(checkStep.image, bundle: Bundle.main) - .resizable() - .scaledToFit() - .frame(height: 100) - Spacer() - } - HStack { - SQText(checkStep.text) - .multilineTextAlignment(.leading) - Spacer() - } - .frame(maxWidth: .infinity) - } - .padding() - .frame(maxWidth: .infinity) - .overlay( - RoundedRectangle(cornerRadius: 8) - .stroke(Color.sqNeutral(30), lineWidth: 1) - ) - .onTapGesture { - self.isSelected.toggle() - } - } -} - -struct ResiliationCheckStepsScreen: View { - @StateObject var viewModel: ResiliationViewModel - var steps: [ResiliationCheckStep] { - viewModel.resiliationCheckSteps - } - @State private var selectedSteps: Set = [] - - var allStepsSelected: Bool { - selectedSteps.count == steps.count - } - - var body: some View { - ScrollView { - VStack(spacing: 16) { - ForEach(steps, id: \.self) { step in - ResiliationCheckStepView( - checkStep: step, - isSelected: Binding( - get: { selectedSteps.contains(step) }, - set: { isSelected in - if isSelected { - selectedSteps.insert(step) - } else { - selectedSteps.remove(step) - } - } - ) - ) - } - } - .padding() - } - } -} - -#Preview { - ResiliationCheckStepsScreen(viewModel: ResiliationViewModel(resiliationType: .apPart)) -} diff --git a/AlloVoisinsSwiftUI/Views/Resiliation/TrialWarningCellView.swift b/AlloVoisinsSwiftUI/Views/Resiliation/TrialWarningCellView.swift index 2012b7c..c27d404 100644 --- a/AlloVoisinsSwiftUI/Views/Resiliation/TrialWarningCellView.swift +++ b/AlloVoisinsSwiftUI/Views/Resiliation/TrialWarningCellView.swift @@ -9,7 +9,12 @@ import SwiftUI struct TrialWarningCellView: View { var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + VStack(spacing: 8) { + SQIcon(.triangle_exclamation, size: .xxl, type: .solid, color: .SEMANTIC_RED) + SQText("Votre période d’essai gratuite* se termine le 14 mars 2024. Toute résiliation avant cette date entraînera la coupure immédiate du service.", font: .demiBold) + .multilineTextAlignment(.center) + SQText("* Offre d’essai valable une seule fois par utilisateur.", size: 13) + } } } diff --git a/AlloVoisinsSwiftUI/Views/Subscriptions/NewPerimeterCellView.swift b/AlloVoisinsSwiftUI/Views/Subscriptions/NewPerimeterCellView.swift new file mode 100644 index 0000000..8b18a64 --- /dev/null +++ b/AlloVoisinsSwiftUI/Views/Subscriptions/NewPerimeterCellView.swift @@ -0,0 +1,34 @@ +// +// NewPerimeterCellView.swift +// Sequoia +// +// Created by Victor on 26/09/2024. +// + +import SwiftUI + +struct NewPerimeterCellView: View { + + var body: some View { + VStack(spacing: 16) { + SQText("Vous souhaitez ajouter un nouveau périmètre ?", size: 24, font: .bold) + .multilineTextAlignment(.center) + SQText("Si vous souhaitez couvrir une zone géographique différente de votre périmètre actuel, souscrivez à un nouvel abonnement pour proposer vos services dans ce nouveau secteur.") + SQButton("Souscrire à un nouveau périmètre", color: .sqOrange(50), textColor: .sqOrange(50), isFull: false) {} + SQText("À partir de 9,99€ / mois, sans engagement", size: 13) + } + .padding(.horizontal, 32) + .padding(.vertical, 16) + .cornerRadius(8) + .overlay( + RoundedRectangle(cornerRadius: 8) + .inset(by: 0.5) + .stroke(Color.sqNeutral(20), lineWidth: 1) + ) + } +} + +#Preview { + NewPerimeterCellView() + .padding() +}