💄 More UI

This commit is contained in:
Victor Bodinaud
2024-10-17 15:19:18 +02:00
parent c211091406
commit d962262874
25 changed files with 871 additions and 85 deletions

View File

@@ -12,7 +12,7 @@ struct AlloVoisinsSwiftUIApp: App {
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
NavigationStack { NavigationStack {
ResiliationNavigationScreen(resiliationType: .apProWithTrial) ResiliationNavigationScreen(viewModel: ResiliationViewModel(resiliationType: .apProWithTrial))
} }
} }
} }

View File

@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "allomoji_sad.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,365 @@
%PDF-1.7
1 0 obj
<< /Length 2 0 R
/Range [ 0.000000 1.000000 0.000000 1.000000 0.000000 1.000000 ]
/Domain [ 0.000000 1.000000 ]
/FunctionType 4
>>
stream
{ 0.436170 exch 0.867448 exch 0.925356 exch dup 0.000000 gt { exch pop exch pop exch pop dup 0.000000 sub -0.217539 mul 0.436170 add exch dup 0.000000 sub -0.193018 mul 0.867448 add exch dup 0.000000 sub 0.074644 mul 0.925356 add exch } if dup 1.000000 gt { exch pop exch pop exch pop 0.218632 exch 0.674430 exch 1.000000 exch } if pop }
endstream
endobj
2 0 obj
338
endobj
3 0 obj
<< /Pattern << /P1 << /Matrix [ -149.568039 -159.712708 159.712708 -149.568039 -64.525940 417.659363 ]
/Shading << /Coords [ 0.000000 0.000000 1.000000 0.000000 ]
/ColorSpace /DeviceRGB
/Function 1 0 R
/Domain [ 0.000000 1.000000 ]
/ShadingType 2
/Extend [ true true ]
>>
/PatternType 2
/Type /Pattern
>> >>
/ExtGState << /E1 << /ca 0.097959 >> >>
>>
endobj
4 0 obj
<< /Length 5 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
/E1 gs
1.000000 0.000000 -0.000000 1.000000 53.714600 13.998047 cm
0.000000 0.000000 0.000000 scn
90.547752 7.723469 m
90.547752 3.458379 70.278847 0.000010 45.275021 0.000010 c
20.271200 0.000010 0.000000 3.458379 0.000000 7.723469 c
0.000000 11.990851 20.271200 15.449219 45.275021 15.449219 c
70.278847 15.449219 90.547752 11.990851 90.547752 7.723469 c
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 20.402832 36.408203 cm
/Pattern cs
/P1 scn
159.382812 78.224625 m
159.217804 88.803696 154.723541 98.578331 147.476791 104.113091 c
90.969528 147.272766 l
82.748749 153.552368 72.391983 153.320892 64.427895 146.681473 c
10.877094 102.034409 l
3.937446 96.247543 -0.158046 86.436234 0.004673 75.974052 c
0.678470 32.376640 l
0.942030 15.355255 12.194895 1.725754 25.815214 1.938904 c
135.868683 3.641724 l
149.488998 3.852570 160.315598 17.821259 160.052032 34.842651 c
159.382812 78.224625 l
h
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 115.383301 100.441895 cm
1.000000 1.000000 1.000000 scn
10.930661 0.748501 m
8.290481 0.737041 5.648008 0.723290 3.005536 0.714124 c
1.428762 0.709539 0.074294 1.928792 0.005539 3.503277 c
-0.028838 4.339794 0.094920 5.224439 0.429526 6.143462 c
1.252291 8.403203 3.232426 10.158743 5.595296 10.610232 c
10.013932 11.449041 13.889405 8.100682 13.914616 3.826425 c
13.916907 3.737043 13.914616 3.647662 13.912324 3.558280 c
13.855028 1.981503 12.507436 0.755376 10.930661 0.748501 c
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 71.195068 100.230957 cm
1.000000 1.000000 1.000000 scn
0.000070 3.647342 m
0.004654 4.238633 0.087159 4.848259 0.261338 5.476219 c
0.944303 7.923890 2.979445 9.885694 5.468369 10.401355 c
9.937431 11.329544 13.888540 7.958268 13.913751 3.642758 c
13.913751 3.610673 l
13.918334 2.024729 12.522612 0.787143 10.936667 0.784850 c
8.287316 0.782558 5.640256 0.777975 2.990904 0.775683 c
1.384333 0.773392 -0.011389 2.040771 0.000070 3.647342 c
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 89.196533 74.000000 cm
1.000000 1.000000 1.000000 scn
3.004584 6.093983 m
5.156945 7.444341 8.546254 8.799805 12.205587 8.799805 c
15.864919 8.799805 19.254234 7.444343 21.406603 6.093986 c
22.428444 5.452901 23.424566 4.657184 23.954453 3.813828 c
24.146761 3.507753 24.766466 2.425399 24.132900 1.254358 c
23.488171 0.062685 22.213228 -0.000194 21.805601 -0.000194 c
20.861500 -0.000194 20.007589 0.226774 19.263977 0.487279 c
18.773603 0.659066 18.232281 0.884323 17.729542 1.093524 c
17.516951 1.181988 17.311260 1.267580 17.119238 1.345045 c
15.740918 1.901081 14.239561 2.399805 12.205587 2.399805 c
10.171617 2.399805 8.670266 1.901080 7.291955 1.345045 c
7.099933 1.267580 6.894242 1.181987 6.681652 1.093523 c
6.178916 0.884323 5.637596 0.659066 5.147226 0.487279 c
4.403615 0.226773 3.549706 -0.000196 2.605604 -0.000196 c
2.197973 -0.000196 0.923040 0.062685 0.278309 1.254348 c
-0.355261 2.425384 0.264434 3.507739 0.456743 3.813818 c
0.986627 4.657178 1.982746 5.452897 3.004584 6.093983 c
h
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 112.800293 90.399902 cm
0.168362 0.160503 0.179167 scn
31.999998 16.000000 m
31.999998 7.163446 24.836554 0.000002 15.999999 0.000002 c
7.163444 0.000002 0.000000 7.163446 0.000000 16.000000 c
0.000000 24.836555 7.163444 32.000000 15.999999 32.000000 c
24.836554 32.000000 31.999998 24.836555 31.999998 16.000000 c
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 119.200439 110.399902 cm
1.000000 1.000000 1.000000 scn
8.000000 4.000000 m
8.000000 1.790862 6.209138 0.000000 4.000000 0.000000 c
1.790861 0.000000 0.000000 1.790862 0.000000 4.000000 c
0.000000 6.209139 1.790861 8.000000 4.000000 8.000000 c
6.209138 8.000000 8.000000 6.209139 8.000000 4.000000 c
h
f
n
Q
q
-1.000000 -0.000000 -0.000000 1.000000 130.400391 116.799805 cm
1.000000 1.000000 1.000000 scn
3.200000 1.600195 m
3.200000 0.716540 2.483656 0.000195 1.600000 0.000195 c
0.716344 0.000195 0.000000 0.716540 0.000000 1.600195 c
0.000000 2.483851 0.716344 3.200195 1.600000 3.200195 c
2.483656 3.200195 3.200000 2.483851 3.200000 1.600195 c
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 116.197754 92.000000 cm
0.298039 0.266667 0.341176 scn
0.210692 9.427586 m
0.819494 10.927945 2.263791 11.200195 3.002827 11.200195 c
4.263373 11.200195 5.321895 10.698198 6.093330 10.247780 c
6.611842 9.945037 7.198322 9.538357 7.710639 9.183104 c
7.915307 9.041182 8.108138 8.907468 8.280070 8.791867 c
9.648875 7.871538 10.930213 7.200195 12.602841 7.200195 c
14.275468 7.200195 15.556796 7.871536 16.925592 8.791864 c
17.097525 8.907465 17.290358 9.041180 17.495024 9.183102 c
18.007338 9.538354 18.593817 9.945034 19.112326 10.247778 c
19.883757 10.698196 20.942278 11.200195 22.202826 11.200195 c
22.941864 11.200195 24.386152 10.927944 24.994959 9.427594 c
25.463491 8.272933 25.033445 7.210503 24.829237 6.777150 c
24.329792 5.717262 23.346052 4.650410 22.280838 3.759346 c
20.099072 1.934270 16.546749 0.000196 12.602841 0.000196 c
8.658937 0.000196 5.106606 1.934269 2.924833 3.759343 c
1.859617 4.650406 0.875873 5.717257 0.376423 6.777142 c
0.172215 7.210493 -0.257837 8.272923 0.210692 9.427586 c
h
f*
n
Q
q
-1.000000 -0.000000 -0.000000 1.000000 140.000488 97.600098 cm
1.000000 1.000000 1.000000 scn
4.000000 2.000000 m
4.000000 0.895431 3.104569 0.000000 2.000000 0.000000 c
0.895430 0.000000 0.000000 0.895431 0.000000 2.000000 c
0.000000 3.104569 0.895430 4.000000 2.000000 4.000000 c
3.104569 4.000000 4.000000 3.104569 4.000000 2.000000 c
h
f
n
Q
q
1.000000 -0.000000 0.000000 1.000000 116.197998 88.799805 cm
0.839216 0.941176 1.000000 scn
2.186750 7.132430 m
2.481733 7.187536 2.767972 7.200195 3.002226 7.200195 c
22.202225 7.200195 l
22.436480 7.200195 22.722717 7.187535 23.017700 7.132430 c
23.223743 7.093940 23.849474 6.967839 24.399368 6.459650 c
24.724783 6.158916 25.043146 5.702694 25.159731 5.094691 c
25.273575 4.500982 25.151371 3.990361 25.002514 3.640070 c
24.743748 3.031134 24.310673 2.673494 24.152058 2.547267 c
23.757078 2.232945 23.281164 2.001373 22.906059 1.838783 c
22.485668 1.656564 21.994732 1.478374 21.458691 1.310222 c
19.338472 0.645127 16.070730 0.000196 12.602242 0.000196 c
9.133754 0.000196 5.866003 0.645127 3.745779 1.310222 c
3.209736 1.478374 2.718797 1.656562 2.298405 1.838781 c
1.923299 2.001371 1.447385 2.232941 1.052409 2.547260 c
0.893792 2.673485 0.460720 3.031119 0.201949 3.640047 c
0.053092 3.990332 -0.069120 4.500952 0.044717 5.094664 c
0.161296 5.702672 0.479656 6.158901 0.805074 6.459641 c
1.354972 6.967839 1.980710 7.093940 2.186750 7.132430 c
h
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 56.800049 90.399902 cm
0.168362 0.160503 0.179167 scn
31.999998 16.000000 m
31.999998 7.163446 24.836554 0.000002 15.999999 0.000002 c
7.163444 0.000002 0.000000 7.163446 0.000000 16.000000 c
0.000000 24.836555 7.163444 32.000000 15.999999 32.000000 c
24.836554 32.000000 31.999998 24.836555 31.999998 16.000000 c
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 63.200439 110.399902 cm
1.000000 1.000000 1.000000 scn
8.000000 4.000000 m
8.000000 1.790862 6.209138 0.000000 4.000000 0.000000 c
1.790861 0.000000 0.000000 1.790862 0.000000 4.000000 c
0.000000 6.209139 1.790861 8.000000 4.000000 8.000000 c
6.209138 8.000000 8.000000 6.209139 8.000000 4.000000 c
h
f
n
Q
q
-1.000000 -0.000000 -0.000000 1.000000 74.400391 116.799805 cm
1.000000 1.000000 1.000000 scn
3.200000 1.600195 m
3.200000 0.716540 2.483656 0.000195 1.600000 0.000195 c
0.716344 0.000195 0.000000 0.716540 0.000000 1.600195 c
0.000000 2.483851 0.716344 3.200195 1.600000 3.200195 c
2.483656 3.200195 3.200000 2.483851 3.200000 1.600195 c
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 60.197754 92.000000 cm
0.298039 0.266667 0.341176 scn
0.210692 9.427586 m
0.819494 10.927945 2.263791 11.200195 3.002826 11.200195 c
4.263373 11.200195 5.321895 10.698198 6.093330 10.247780 c
6.611842 9.945036 7.198323 9.538356 7.710640 9.183103 c
7.915307 9.041182 8.108138 8.907468 8.280070 8.791867 c
9.648875 7.871538 10.930213 7.200195 12.602841 7.200195 c
14.275467 7.200195 15.556796 7.871536 16.925592 8.791864 c
17.097525 8.907465 17.290358 9.041180 17.495024 9.183101 c
18.007338 9.538354 18.593815 9.945034 19.112326 10.247778 c
19.883757 10.698197 20.942278 11.200195 22.202826 11.200195 c
22.941864 11.200195 24.386152 10.927944 24.994959 9.427594 c
25.463491 8.272934 25.033445 7.210504 24.829237 6.777150 c
24.329792 5.717262 23.346052 4.650410 22.280838 3.759346 c
20.099072 1.934270 16.546749 0.000196 12.602841 0.000196 c
8.658937 0.000196 5.106606 1.934269 2.924833 3.759343 c
1.859617 4.650406 0.875873 5.717257 0.376423 6.777142 c
0.172215 7.210493 -0.257837 8.272923 0.210692 9.427586 c
h
f*
n
Q
q
-1.000000 -0.000000 -0.000000 1.000000 84.000244 97.600098 cm
1.000000 1.000000 1.000000 scn
4.000000 2.000000 m
4.000000 0.895431 3.104569 0.000000 2.000000 0.000000 c
0.895430 0.000000 0.000000 0.895431 0.000000 2.000000 c
0.000000 3.104569 0.895430 4.000000 2.000000 4.000000 c
3.104569 4.000000 4.000000 3.104569 4.000000 2.000000 c
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 60.800049 88.799805 cm
0.839216 0.941176 1.000000 scn
2.186750 7.132430 m
2.481733 7.187536 2.767971 7.200195 3.002226 7.200195 c
22.202225 7.200195 l
22.436480 7.200195 22.722717 7.187535 23.017700 7.132430 c
23.223743 7.093940 23.849474 6.967839 24.399368 6.459650 c
24.724783 6.158916 25.043146 5.702694 25.159731 5.094691 c
25.273575 4.500982 25.151371 3.990361 25.002514 3.640070 c
24.743748 3.031134 24.310673 2.673494 24.152058 2.547267 c
23.757078 2.232945 23.281164 2.001373 22.906059 1.838783 c
22.485668 1.656564 21.994732 1.478374 21.458691 1.310222 c
19.338472 0.645127 16.070730 0.000196 12.602242 0.000196 c
9.133754 0.000196 5.866003 0.645127 3.745779 1.310222 c
3.209736 1.478374 2.718797 1.656562 2.298405 1.838781 c
1.923299 2.001371 1.447385 2.232941 1.052409 2.547260 c
0.893792 2.673485 0.460720 3.031119 0.201949 3.640047 c
0.053092 3.990332 -0.069120 4.500952 0.044717 5.094664 c
0.161295 5.702673 0.479656 6.158901 0.805074 6.459641 c
1.354972 6.967839 1.980710 7.093940 2.186750 7.132430 c
h
f*
n
Q
endstream
endobj
5 0 obj
10051
endobj
6 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 200.000000 200.000000 ]
/Resources 3 0 R
/Contents 4 0 R
/Parent 7 0 R
>>
endobj
7 0 obj
<< /Kids [ 6 0 R ]
/Count 1
/Type /Pages
>>
endobj
8 0 obj
<< /Pages 7 0 R
/Type /Catalog
>>
endobj
xref
0 9
0000000000 65535 f
0000000010 00000 n
0000000532 00000 n
0000000554 00000 n
0000001236 00000 n
0000011343 00000 n
0000011367 00000 n
0000011542 00000 n
0000011616 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 8 0 R
/Size 9
>>
startxref
11675
%%EOF

View File

@@ -8,6 +8,8 @@
import SwiftUI import SwiftUI
struct AlloVoisinReputationScreen: View { struct AlloVoisinReputationScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
@@ -74,7 +76,7 @@ struct AlloVoisinReputationScreen: View {
.background(Color.white) .background(Color.white)
.cornerRadius(8) .cornerRadius(8)
SQButton("Conserver mon abonnement", color: .sqNeutral(100), textColor: .white) { SQButton("Conserver mon abonnement", color: .sqNeutral(100), textColor: .white) {
navigateToNext = true
} }
} }
.padding(16) .padding(16)
@@ -82,7 +84,14 @@ struct AlloVoisinReputationScreen: View {
.cornerRadius(8) .cornerRadius(8)
SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) { SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) {
navigateToNext = true
}
}
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
} }
} }
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
@@ -90,5 +99,5 @@ struct AlloVoisinReputationScreen: View {
} }
#Preview { #Preview {
AlloVoisinReputationScreen() AlloVoisinReputationScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -8,7 +8,10 @@
import SwiftUI import SwiftUI
struct AskIfWillComeBackScreen: View { struct AskIfWillComeBackScreen: View {
@ObservedObject var viewModel: ResiliationViewModel
@State private var navigateToNext = false
@State var selectedIndex: Int? = nil @State var selectedIndex: Int? = nil
var body: some View { var body: some View {
VStack { VStack {
SQRadio(title: "Pensez-vous redevenir abonné Premier ?", orientation: .horizontal, options: ["1\nNon,Jamais", "2", "3", "4", "5\nOui, sûrement"], selectedIndex: $selectedIndex) SQRadio(title: "Pensez-vous redevenir abonné Premier ?", orientation: .horizontal, options: ["1\nNon,Jamais", "2", "3", "4", "5\nOui, sûrement"], selectedIndex: $selectedIndex)
@@ -17,5 +20,5 @@ struct AskIfWillComeBackScreen: View {
} }
#Preview { #Preview {
AskIfWillComeBackScreen() AskIfWillComeBackScreen(viewModel: ResiliationViewModel(resiliationType: .apProWithTrial))
} }

View File

@@ -8,6 +8,9 @@
import SwiftUI import SwiftUI
struct ContinueAsParticularScreen: View { struct ContinueAsParticularScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 32) { VStack(spacing: 32) {
SQText("Souhaitez-vous poursuivre en tant que particulier ?", size: 18, font: .bold) SQText("Souhaitez-vous poursuivre en tant que particulier ?", size: 18, font: .bold)
@@ -16,18 +19,25 @@ struct ContinueAsParticularScreen: View {
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
VStack { VStack {
SQButton("Changer de statut", color: .sqNeutral(100), textColor: .white) { SQButton("Changer de statut", color: .sqNeutral(100), textColor: .white) {
navigateToNext = true
} }
SQButton("Jai compris, mais je souhaite résilier", color: .white) { SQButton("Jai compris, mais je souhaite résilier", color: .white) {
navigateToNext = true
} }
} }
} }
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
}
}
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
.padding(16) .padding(16)
} }
} }
#Preview { #Preview {
ContinueAsParticularScreen() ContinueAsParticularScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -0,0 +1,163 @@
//
// GenericResiliationScreen.swift
// AlloVoisinsSwiftUI
//
// Created by Victor on 14/10/2024.
//
import SwiftUI
protocol ResiliationContentView: View {
var screenType: ResiliationScreenType { get }
}
enum ResiliationScreenType {
case alloVoisinReputation
case askIfWillComeBack
case continueAsParticular
case getMoreRatings
case moreTime
case onlyProRequests
case personalizedSupport
case profileCompletion
case resizePerimeter
case softwarePresentation
case statusChange
case webinaire
var title: String {
switch self {
case .statusChange: return "Changer de statut"
default: return "Ne partez pas !"
}
}
var mainColor: Color {
switch self {
case .alloVoisinReputation, .moreTime: return Color.sqBlue(10)
case .continueAsParticular, .resizePerimeter, .statusChange: return Color.sqOrange(10)
case .getMoreRatings: return Color.sqGold(10)
case .onlyProRequests, .personalizedSupport, .webinaire: return Color.sqGrape(10)
case .profileCompletion: return Color.sqNeutral(10)
case .softwarePresentation: return Color.white
default: return Color.white
}
}
var buttonColor: Color {
switch self {
case .alloVoisinReputation, .continueAsParticular, .profileCompletion, .softwarePresentation:
return Color.sqNeutral(100)
case .getMoreRatings: return Color.sqGold(50)
case .moreTime: return Color.sqBlue(50)
case .onlyProRequests, .personalizedSupport, .webinaire: return Color.sqGrape(80)
case .resizePerimeter, .statusChange: return Color.sqOrange(50)
default: return Color.sqNeutral(100)
}
}
var buttonTitle: String {
switch self {
case .alloVoisinReputation: return "Conserver mon abonnement"
case .continueAsParticular: return "Changer de statut"
case .getMoreRatings: return "Recueillir des avis"
case .moreTime: return "Je prolonge ma période d'essai"
case .onlyProRequests: return "Voir les demandes"
case .personalizedSupport: return "Je souhaite être appelé"
case .profileCompletion: return "Je complète mon profil"
case .resizePerimeter: return "Modifier mon périmètre"
case .softwarePresentation: return "Découvrir le logiciel"
case .statusChange: return "Résilier et changer de statut"
case .webinaire: return "Je m'inscris"
default: return "Continuer"
}
}
var cancelButtonTitle: String {
switch self {
case .moreTime, .personalizedSupport, .webinaire:
return "Non merci, je souhaite résilier"
default:
return "J'ai compris, mais je souhaite résilier"
}
}
}
struct GenericResiliationScreen<Content: ResiliationContentView>: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
let content: Content
let buttonAction: () -> Void
var body: some View {
VStack(spacing: 16) {
VStack(spacing: 32) {
content
.padding(16)
.background(content.screenType.mainColor)
.cornerRadius(8)
SQButton(content.screenType.buttonTitle, color: content.screenType.buttonColor, textColor: .white, action: buttonAction)
}
if content.screenType != .statusChange {
SQButton(content.screenType.cancelButtonTitle, color: .white, textSize: 13) {
navigateToNext = true
}
}
}
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
}
}
.sqNavigationBar(title: content.screenType.title)
.padding()
}
}
//#Preview {
// GenericResiliationScreen(viewModel: ResiliationViewModel(resiliationType: .apProWithTrial), content: ResiliationContentView) {
//
// }
//}
struct AlloVoisinReputationScreens: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
var body: some View {
GenericResiliationScreen(
viewModel: viewModel,
content: AlloVoisinReputationContent(),
buttonAction: {
// Handle button action
}
)
}
}
#Preview {
AlloVoisinReputationScreens(viewModel: PromotionalScreenViewModel())
}
struct AlloVoisinReputationContent: ResiliationContentView {
let screenType: ResiliationScreenType = .alloVoisinReputation
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)
// ... Rest of the content
}
}
}

View File

@@ -8,6 +8,8 @@
import SwiftUI import SwiftUI
struct GetMoreRatingsScreen: View { struct GetMoreRatingsScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
@@ -29,7 +31,7 @@ struct GetMoreRatingsScreen: View {
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
SQButton("Recueillir des avis", color: .sqGold(50), textColor: .white) { SQButton("Recueillir des avis", color: .sqGold(50), textColor: .white) {
navigateToNext = true
} }
} }
.padding(16) .padding(16)
@@ -37,7 +39,14 @@ struct GetMoreRatingsScreen: View {
.cornerRadius(8) .cornerRadius(8)
SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) { SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) {
navigateToNext = true
}
}
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
} }
} }
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
@@ -46,5 +55,5 @@ struct GetMoreRatingsScreen: View {
} }
#Preview { #Preview {
GetMoreRatingsScreen() GetMoreRatingsScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -8,6 +8,8 @@
import SwiftUI import SwiftUI
struct MoreTimeScreen: View { struct MoreTimeScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
@@ -21,7 +23,7 @@ struct MoreTimeScreen: View {
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
SQButton("Je prolonge ma période dessai", color: .sqBlue(50), textColor: .white) { SQButton("Je prolonge ma période dessai", color: .sqBlue(50), textColor: .white) {
navigateToNext = true
} }
} }
.padding(16) .padding(16)
@@ -29,7 +31,14 @@ struct MoreTimeScreen: View {
.cornerRadius(8) .cornerRadius(8)
SQButton("Non merci, je souhaite résilier", color: .white, textSize: 13) { SQButton("Non merci, je souhaite résilier", color: .white, textSize: 13) {
navigateToNext = true
}
}
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
} }
} }
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
@@ -38,5 +47,5 @@ struct MoreTimeScreen: View {
} }
#Preview { #Preview {
MoreTimeScreen() MoreTimeScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -8,6 +8,8 @@
import SwiftUI import SwiftUI
struct OnlyProRequestsScreen: View { struct OnlyProRequestsScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
@@ -29,7 +31,7 @@ struct OnlyProRequestsScreen: View {
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
SQButton("Voir les demandes", color: .sqGrape(80), textColor: .white) { SQButton("Voir les demandes", color: .sqGrape(80), textColor: .white) {
navigateToNext = true
} }
} }
.padding(16) .padding(16)
@@ -37,7 +39,14 @@ struct OnlyProRequestsScreen: View {
.cornerRadius(8) .cornerRadius(8)
SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) { SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) {
navigateToNext = true
}
}
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
} }
} }
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
@@ -46,5 +55,5 @@ struct OnlyProRequestsScreen: View {
} }
#Preview { #Preview {
OnlyProRequestsScreen() OnlyProRequestsScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -8,6 +8,8 @@
import SwiftUI import SwiftUI
struct PersonalizedSupportScreen: View { struct PersonalizedSupportScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
@@ -24,7 +26,7 @@ struct PersonalizedSupportScreen: View {
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
SQButton("Je souhaite être appelé", color: .sqGrape(80), textColor: .white) { SQButton("Je souhaite être appelé", color: .sqGrape(80), textColor: .white) {
navigateToNext = true
} }
} }
.padding(16) .padding(16)
@@ -32,7 +34,14 @@ struct PersonalizedSupportScreen: View {
.cornerRadius(8) .cornerRadius(8)
SQButton("Non merci, je souhaite résilier", color: .white, textSize: 13) { SQButton("Non merci, je souhaite résilier", color: .white, textSize: 13) {
navigateToNext = true
}
}
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
} }
} }
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
@@ -41,5 +50,5 @@ struct PersonalizedSupportScreen: View {
} }
#Preview { #Preview {
PersonalizedSupportScreen() PersonalizedSupportScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -8,6 +8,9 @@
import SwiftUI import SwiftUI
struct ProfileCompletionScreen: View { struct ProfileCompletionScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
VStack(spacing: 32) { VStack(spacing: 32) {
@@ -52,7 +55,7 @@ struct ProfileCompletionScreen: View {
SQText("des demandeurs comparent systématiquement les profils des offreurs pour faire leur choix.") SQText("des demandeurs comparent systématiquement les profils des offreurs pour faire leur choix.")
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
SQButton("Je complète mon profil", color: .sqNeutral(100), textColor: .white) { SQButton("Je complète mon profil", color: .sqNeutral(100), textColor: .white) {
navigateToNext = true
} }
} }
.padding(16) .padding(16)
@@ -60,7 +63,14 @@ struct ProfileCompletionScreen: View {
.cornerRadius(8) .cornerRadius(8)
SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) { SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) {
navigateToNext = true
}
}
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
} }
} }
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
@@ -69,5 +79,5 @@ struct ProfileCompletionScreen: View {
} }
#Preview { #Preview {
ProfileCompletionScreen() ProfileCompletionScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -8,9 +8,9 @@
import SwiftUI import SwiftUI
struct ResiliationCheckStepsScreen: View { struct ResiliationCheckStepsScreen: View {
@State var nextStep: Bool = false
@StateObject var viewModel: ResiliationViewModel @StateObject var viewModel: ResiliationViewModel
@State private var selectedSteps: Set<ResiliationCheckStep> = [] @State private var selectedSteps: Set<ResiliationCheckStep> = []
@State private var navigateToReasonScreen = false
var allStepsSelected: Bool { var allStepsSelected: Bool {
selectedSteps.count == viewModel.resiliationCheckSteps.count selectedSteps.count == viewModel.resiliationCheckSteps.count
@@ -46,7 +46,7 @@ struct ResiliationCheckStepsScreen: View {
} }
SQButton("Continuer", color: .sqNeutral(100), textColor: .white) { SQButton("Continuer", color: .sqNeutral(100), textColor: .white) {
nextStep.toggle() navigateToReasonScreen = true
} }
.disabled(!allStepsSelected) .disabled(!allStepsSelected)
} }
@@ -54,7 +54,7 @@ struct ResiliationCheckStepsScreen: View {
} }
.padding() .padding()
} }
.navigationDestination(isPresented: $nextStep) { .navigationDestination(isPresented: $navigateToReasonScreen) {
ResiliationReasonScreen(viewModel: viewModel) ResiliationReasonScreen(viewModel: viewModel)
} }
.sqNavigationBar(title: "Demander la résiliation") .sqNavigationBar(title: "Demander la résiliation")

View File

@@ -0,0 +1,33 @@
//
// ResiliationConfirmationScreen.swift
// AlloVoisinsSwiftUI
//
// Created by Victor on 15/10/2024.
//
import SwiftUI
struct ResiliationConfirmationScreen: View {
@State var navigateToNext: Bool = false
var body: some View {
VStack(spacing: 8) {
Image("allomoji_sad")
.resizable()
.scaledToFit()
.frame(height: 200)
SQText("Votre résiliation a été prise en compte. Elle sera effective le JJ/MM/AAAA.", size: 18, font: .bold)
SQButton("Terminer", color: .sqNeutral(100), textColor: .white) {
}
.padding()
Spacer()
}
.padding()
.sqNavigationBar(title: "Demander la résiliation")
}
}
#Preview {
ResiliationConfirmationScreen()
}

View File

@@ -8,16 +8,23 @@
import SwiftUI import SwiftUI
struct ResiliationNavigationScreen: View { struct ResiliationNavigationScreen: View {
@StateObject private var viewModel: ResiliationViewModel @StateObject var viewModel: ResiliationViewModel
init(resiliationType: ResiliationType) {
self._viewModel = StateObject(wrappedValue: ResiliationViewModel(resiliationType: resiliationType))
}
var body: some View { var body: some View {
NavigationStack { NavigationStack {
ResiliationCheckStepsScreen(viewModel: viewModel) ResiliationCheckStepsScreen(viewModel: viewModel)
.navigationBarTitle("Résiliation", displayMode: .inline) }
}
}
struct PromotionalScreenWrapper: View {
@ObservedObject var viewModel: ResiliationViewModel
var body: some View {
if let screen = viewModel.currentPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
} }
} }
} }

View File

@@ -12,6 +12,7 @@ struct ResiliationReasonScreen: View {
@ObservedObject var viewModel: ResiliationViewModel @ObservedObject var viewModel: ResiliationViewModel
@State private var selectedIndex: Int? = nil @State private var selectedIndex: Int? = nil
@State private var resiliationOtherMotif: String = "" @State private var resiliationOtherMotif: String = ""
@State private var navigateToPromotionalScreen = false
var body: some View { var body: some View {
ScrollView { ScrollView {
@@ -28,10 +29,10 @@ struct ResiliationReasonScreen: View {
dismiss() dismiss()
} }
SQButton("Continuer", color: .sqNeutral(100), textColor: .white) { SQButton("Continuer", color: .sqNeutral(100), textColor: .white) {
// TODO: Aller au prochain promotional screen
if let index = selectedIndex { if let index = selectedIndex {
let selectedReason = viewModel.resiliationReasons[index] let selectedReason = viewModel.resiliationReasons[index]
viewModel.setSelectedReason(selectedReason) viewModel.setSelectedReason(selectedReason)
navigateToPromotionalScreen = true
} }
} }
.disabled(selectedIndex == nil) .disabled(selectedIndex == nil)
@@ -41,9 +42,16 @@ struct ResiliationReasonScreen: View {
} }
.padding() .padding()
.sqNavigationBar(title: "Demander la résiliation") .sqNavigationBar(title: "Demander la résiliation")
.navigationDestination(isPresented: $navigateToPromotionalScreen) {
if viewModel.hasNextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: viewModel.currentPromotionalScreen!)
} else {
ResiliationConfirmationScreen()
}
}
} }
} }
#Preview { #Preview {
ResiliationReasonScreen(viewModel: ResiliationViewModel(resiliationType: .apProWithTrial)) ResiliationReasonScreen(viewModel: ResiliationViewModel(resiliationType: .apProWithTrial))
} }

View File

@@ -8,6 +8,9 @@
import SwiftUI import SwiftUI
struct ResizePerimeterScreen: View { struct ResizePerimeterScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
VStack(spacing: 32) { VStack(spacing: 32) {
@@ -23,7 +26,7 @@ struct ResizePerimeterScreen: View {
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
SQButton("Modifier mon périmètre", color: .sqOrange(50), textColor: .white) { SQButton("Modifier mon périmètre", color: .sqOrange(50), textColor: .white) {
navigateToNext = true
} }
} }
.padding(16) .padding(16)
@@ -31,7 +34,14 @@ struct ResizePerimeterScreen: View {
.cornerRadius(8) .cornerRadius(8)
SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) { SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) {
navigateToNext = true
}
}
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
} }
} }
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
@@ -39,5 +49,5 @@ struct ResizePerimeterScreen: View {
} }
#Preview { #Preview {
ResizePerimeterScreen() ResizePerimeterScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -8,6 +8,9 @@
import SwiftUI import SwiftUI
struct SoftwarePresentationScreen: View { struct SoftwarePresentationScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 32) { VStack(spacing: 32) {
SQText("Saviez-vous que votre abonnement peut vous offrir bien plus que de nouveaux clients ?", size: 18, font: .bold) SQText("Saviez-vous que votre abonnement peut vous offrir bien plus que de nouveaux clients ?", size: 18, font: .bold)
@@ -37,18 +40,25 @@ struct SoftwarePresentationScreen: View {
} }
VStack { VStack {
SQButton("Découvrir le logiciel", color: .sqNeutral(100), textColor: .white) { SQButton("Découvrir le logiciel", color: .sqNeutral(100), textColor: .white) {
navigateToNext = true
} }
SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) { SQButton("Jai compris, mais je souhaite résilier", color: .white, textSize: 13) {
navigateToNext = true
} }
} }
} }
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
}
}
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
.padding() .padding()
} }
} }
#Preview { #Preview {
SoftwarePresentationScreen() SoftwarePresentationScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -8,6 +8,8 @@
import SwiftUI import SwiftUI
struct StatusChangeScreen: View { struct StatusChangeScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack { VStack {
@@ -19,17 +21,26 @@ struct StatusChangeScreen: View {
SQText("Si vous le souhaitez, vous pourrez vous abonner à labonnement Premier en tant que particulier.") SQText("Si vous le souhaitez, vous pourrez vous abonner à labonnement Premier en tant que particulier.")
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
SQButton("Résilier et changer de statut", color: .sqOrange(50), textColor: .white) {} SQButton("Résilier et changer de statut", color: .sqOrange(50), textColor: .white) {
navigateToNext = true
}
} }
.padding(16) .padding(16)
.background(Color.sqOrange(10)) .background(Color.sqOrange(10))
.cornerRadius(8) .cornerRadius(8)
} }
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
}
}
.sqNavigationBar(title: "Changer de statut") .sqNavigationBar(title: "Changer de statut")
.padding() .padding()
} }
} }
#Preview { #Preview {
StatusChangeScreen() StatusChangeScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -8,6 +8,8 @@
import SwiftUI import SwiftUI
struct WebinaireScreen: View { struct WebinaireScreen: View {
@ObservedObject var viewModel: PromotionalScreenViewModel
@State private var navigateToNext = false
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
@@ -24,16 +26,37 @@ struct WebinaireScreen: View {
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
SQText("“Augmenter mon chiffre d'affaires.“", size: 18, font: .bold) SQText("“Augmenter mon chiffre d'affaires.“", size: 18, font: .bold)
} }
SQButton("Je minscris", color: .sqGrape(80), textColor: .white) { NavigationLink {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
}
} label: {
SQButton("Je minscris", color: .sqGrape(80), textColor: .white) {
}
} }
} }
.padding(16) .padding(16)
.background(Color.sqGrape(10)) .background(Color.sqGrape(10))
.cornerRadius(8) .cornerRadius(8)
SQButton("Non merci, je souhaite résilier", color: .white, textSize: 13) { NavigationLink {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
}
} label: {
SQButton("Non merci, je souhaite résilier", color: .white, textSize: 13) {
}
}
}
.navigationDestination(isPresented: $navigateToNext) {
if let screen = viewModel.nextPromotionalScreen {
viewModel.getPromotionalScreenNew(for: screen)
} else {
ResiliationConfirmationScreen()
} }
} }
.sqNavigationBar(title: "Ne partez pas !") .sqNavigationBar(title: "Ne partez pas !")
@@ -41,5 +64,5 @@ struct WebinaireScreen: View {
} }
#Preview { #Preview {
WebinaireScreen() WebinaireScreen(viewModel: PromotionalScreenViewModel())
} }

View File

@@ -0,0 +1,43 @@
//
// PromotionalScreenViewModel.swift
// AlloVoisinsSwiftUI
//
// Created by Victor on 15/10/2024.
//
import Foundation
import SwiftUICore
class PromotionalScreenViewModel: ObservableObject {
@Published var nextPromotionalScreen: ResiliationPromotionalScreen?
init(nextPromotionalScreen: ResiliationPromotionalScreen? = nil) {
self.nextPromotionalScreen = nextPromotionalScreen
}
@ViewBuilder
func getPromotionalScreenNew(for screen: ResiliationPromotionalScreen) -> some View {
switch screen {
case .webinarPresentation:
WebinaireScreen(viewModel: PromotionalScreenViewModel())
case .profileCompletion:
ProfileCompletionScreen(viewModel: PromotionalScreenViewModel())
case .editPerimeter:
ResizePerimeterScreen(viewModel: PromotionalScreenViewModel())
case .onlyProSearches:
OnlyProRequestsScreen(viewModel: PromotionalScreenViewModel())
case .oneMonthBoosterOffered:
BoosterSubscriptionSelectionScreen()
case .allovoisinsPromotion:
AlloVoisinReputationScreen(viewModel: PromotionalScreenViewModel())
case .extendMyTrialPeriod:
MoreTimeScreen(viewModel: PromotionalScreenViewModel())
case .askPartProStatusChangeWithCancellation, .askPartProStatusChange:
StatusChangeScreen(viewModel: PromotionalScreenViewModel())
case .customerSupportForPro, .customerSupportForPart:
PersonalizedSupportScreen(viewModel: PromotionalScreenViewModel())
default:
EmptyView()
}
}
}

View File

@@ -14,13 +14,22 @@ class ResiliationViewModel: ObservableObject {
@Published var resiliationReasons: [ResiliationReason] @Published var resiliationReasons: [ResiliationReason]
@Published var selectedReason: ResiliationReason? @Published var selectedReason: ResiliationReason?
@Published var promotionalScreens: [ResiliationPromotionalScreen] = [] @Published var promotionalScreens: [ResiliationPromotionalScreen] = []
@Published var currentScreen: Screen = .checkSteps @Published var currentPromotionalScreenIndex: Int = 0
@Published var shouldShowConfirmationScreen: Bool = false
enum Screen: Equatable { var currentPromotionalScreen: ResiliationPromotionalScreen? {
case checkSteps guard currentPromotionalScreenIndex < promotionalScreens.count else {
case reason return nil
case promotional(ResiliationPromotionalScreen) }
case final return promotionalScreens[currentPromotionalScreenIndex]
}
var hasNextPromotionalScreen: Bool {
currentPromotionalScreenIndex < promotionalScreens.count
}
var nextPromotionalScreen: ResiliationPromotionalScreen? {
hasNextPromotionalScreen ? promotionalScreens[currentPromotionalScreenIndex + 1] : nil
} }
init(resiliationType: ResiliationType) { init(resiliationType: ResiliationType) {
@@ -35,32 +44,19 @@ class ResiliationViewModel: ObservableObject {
availablePromotions: getAvailablePromotionalScreens(for: reason), availablePromotions: getAvailablePromotionalScreens(for: reason),
eligibleScreens: getEligiblePromotionalScreens() eligibleScreens: getEligiblePromotionalScreens()
) )
currentPromotionalScreenIndex = 0
if promotionalScreens.isEmpty { shouldShowConfirmationScreen = false
currentScreen = .final
} else {
currentScreen = .promotional(promotionalScreens.removeFirst())
}
}
func moveToNextPromotionalScreen() {
if !promotionalScreens.isEmpty {
currentScreen = .promotional(promotionalScreens.removeFirst())
} else {
currentScreen = .final
}
} }
// OK
private func selectResiliationPromotions(availablePromotions: [ResiliationPromotionalScreen], eligibleScreens: [ResiliationPromotionalScreen]) -> [ResiliationPromotionalScreen] { private func selectResiliationPromotions(availablePromotions: [ResiliationPromotionalScreen], eligibleScreens: [ResiliationPromotionalScreen]) -> [ResiliationPromotionalScreen] {
let shuffledArray1 = availablePromotions.shuffled() let promotionsShuffuled = availablePromotions.shuffled()
let commonPromotions = shuffledArray1.filter { promotion in let commonPromotions = promotionsShuffuled.filter { promotion in
eligibleScreens.contains(promotion) eligibleScreens.contains(promotion)
} }
let result = commonPromotions.map { $0 } return Array(commonPromotions.prefix(2))
return Array(result.prefix(2))
} }
private func getAvailablePromotionalScreens(for reason: ResiliationReason) -> [ResiliationPromotionalScreen] { private func getAvailablePromotionalScreens(for reason: ResiliationReason) -> [ResiliationPromotionalScreen] {
@@ -87,30 +83,30 @@ class ResiliationViewModel: ObservableObject {
} }
private func getEligiblePromotionalScreens() -> [ResiliationPromotionalScreen] { private func getEligiblePromotionalScreens() -> [ResiliationPromotionalScreen] {
return [.extendMyTrialPeriod, .profileCompletion, .allovoisinsPromotion] return [.extendMyTrialPeriod, .profileCompletion, .allovoisinsPromotion, .externalReview, .webinarPresentation, .editPerimeter, .onlyProSearches, .askPartProStatusChange, .customerSupportForPro]
} }
@ViewBuilder @ViewBuilder
func getPromotionalScreenNew(for screen: ResiliationPromotionalScreen) -> some View { func getPromotionalScreenNew(for screen: ResiliationPromotionalScreen) -> some View {
switch screen { switch screen {
case .webinarPresentation: case .webinarPresentation:
WebinaireScreen() WebinaireScreen(viewModel: PromotionalScreenViewModel(nextPromotionalScreen: nextPromotionalScreen))
case .profileCompletion: case .profileCompletion:
ProfileCompletionScreen() ProfileCompletionScreen(viewModel: PromotionalScreenViewModel(nextPromotionalScreen: nextPromotionalScreen))
case .editPerimeter: case .editPerimeter:
ResizePerimeterScreen() ResizePerimeterScreen(viewModel: PromotionalScreenViewModel(nextPromotionalScreen: nextPromotionalScreen))
case .onlyProSearches: case .onlyProSearches:
OnlyProRequestsScreen() OnlyProRequestsScreen(viewModel: PromotionalScreenViewModel(nextPromotionalScreen: nextPromotionalScreen))
case .oneMonthBoosterOffered: case .oneMonthBoosterOffered:
BoosterSubscriptionSelectionScreen() BoosterSubscriptionSelectionScreen()
case .allovoisinsPromotion: case .allovoisinsPromotion:
AlloVoisinReputationScreen() AlloVoisinReputationScreen(viewModel: PromotionalScreenViewModel(nextPromotionalScreen: nextPromotionalScreen))
case .extendMyTrialPeriod: case .extendMyTrialPeriod:
MoreTimeScreen() MoreTimeScreen(viewModel: PromotionalScreenViewModel(nextPromotionalScreen: nextPromotionalScreen))
case .askPartProStatusChangeWithCancellation, .askPartProStatusChange: case .askPartProStatusChangeWithCancellation, .askPartProStatusChange:
StatusChangeScreen() StatusChangeScreen(viewModel: PromotionalScreenViewModel(nextPromotionalScreen: nextPromotionalScreen))
case .customerSupportForPro, .customerSupportForPart: case .customerSupportForPro, .customerSupportForPart:
PersonalizedSupportScreen() PersonalizedSupportScreen(viewModel: PromotionalScreenViewModel(nextPromotionalScreen: nextPromotionalScreen))
default: default:
EmptyView() EmptyView()
} }

View File

@@ -0,0 +1,37 @@
//
// SQProgressBar.swift
// AlloVoisinsSwiftUI
//
// Created by Victor on 17/10/2024.
//
import SwiftUI
struct SQProgressBar: View {
var progress: Double // Valeur entre 0 et 1
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle()
.foregroundColor(Color.sqNeutral(20))
.frame(width: geometry.size.width, height: 12)
.cornerRadius(50)
Rectangle()
.foregroundColor(Color.sqNeutral(60)) // Vous pouvez changer la couleur ici
.frame(width: min(CGFloat(self.progress) * geometry.size.width, geometry.size.width), height: 12)
.cornerRadius(50)
}
}
.frame(height: 12)
.frame(maxWidth: .infinity, alignment: .topLeading)
.background(Color.sqNeutral(20))
.cornerRadius(12)
}
}
#Preview {
SQProgressBar(progress: 0.2)
.padding()
}