Skip to content

Commit 07290ca

Browse files
authored
feat(freeInputPartIOS): adding the freeInputPart of IOS (#232)
1 parent 74532ab commit 07290ca

File tree

3 files changed

+71
-17
lines changed

3 files changed

+71
-17
lines changed

xpeapp_ios/XpeApp/XpeApp/Data/DataSource/Mocks/MockWordpressAPI.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class MockWordpressAPI: WordpressAPIProtocol {
2121
var fetchCampaignsProgressReturnData: [QvstProgressModel]?
2222
var fetchUserInfosReturnData: UserInfosModel?
2323
var updatePasswordData: UserPasswordEditReturnEnum?
24+
var submitOpenAnswersReturnData: Bool?
2425

2526
private init() {
2627
// This initializer is intentionally left empty to make private
@@ -72,4 +73,8 @@ class MockWordpressAPI: WordpressAPIProtocol {
7273
func updatePassword(userPasswordCandidate: UserPasswordEditModel) async -> UserPasswordEditReturnEnum? {
7374
return updatePasswordData
7475
}
76+
77+
func submitOpenAnswers(text: String) async -> Bool? {
78+
return submitOpenAnswersReturnData
79+
}
7580
}

xpeapp_ios/XpeApp/XpeApp/Data/DataSource/WordpressAPI.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,4 +308,21 @@ class WordpressAPI: WordpressAPIProtocol {
308308
}
309309
return nil
310310
}
311+
312+
313+
// send the open answer of a campaign QVST
314+
func submitOpenAnswers(
315+
text: String
316+
) async -> Bool? {
317+
if let (_,statusCode) = await fetchWordpressAPI (
318+
endpoint: "xpeho/v1/qvst/open-answers?text=\(text)",
319+
method: .post,
320+
headers: [:]
321+
) {
322+
return statusCode == 201
323+
} else {
324+
return nil
325+
}
326+
}
327+
311328
}

xpeapp_ios/XpeApp/XpeApp/Presentation/View/Qvst/CampaignFormView.swift

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ struct CampaignForm: View {
1818
@State var questions: [QvstQuestionModel] = []
1919
@State var answersSelected: [QvstAnswerModel?] = []
2020
@State var questionsOffset: Int = 0
21+
@State var openAnswer: String = ""
2122

2223
// Prevent multiple click on send button of the form
2324
@State private var isSending: Bool = false
2425

2526
var body: some View {
2627
VStack {
27-
if let campaign = routerManager.parameters["campaign"] as! QvstCampaignEntity? {
28+
if let campaign = routerManager.parameters["campaign"] as? QvstCampaignEntity {
2829
HStack {
2930
Title(text: campaign.themeName)
3031
Spacer()
@@ -42,6 +43,8 @@ struct CampaignForm: View {
4243
answersSelected: $answersSelected,
4344
questionsOffset: $questionsOffset
4445
)
46+
} else if isLastOffset() {
47+
OpenAnswerView(openAnswer: $openAnswer)
4548
}
4649
}
4750
}
@@ -51,11 +54,11 @@ struct CampaignForm: View {
5154
.renderingMode(.template)
5255
.foregroundStyle(isFirstOffset() ? XPEHO_THEME.DISABLED_COLOR : XPEHO_THEME.CONTENT_COLOR)
5356
.onTapGesture {
54-
questionsOffset-=1
57+
questionsOffset -= 1
5558
}
5659
.disabled(isFirstOffset())
5760
Spacer()
58-
Text("Question \(questionsOffset+1)/\(questions.count)")
61+
Text("Question \(questionsOffset + 1)/\(questions.count + 1)")
5962
.font(.raleway(.semiBold, size: 20))
6063
.foregroundStyle(XPEHO_THEME.XPEHO_COLOR)
6164
Spacer()
@@ -67,7 +70,7 @@ struct CampaignForm: View {
6770
if isLastOffset() {
6871
sendAnswers()
6972
} else if isAnsweredOffset() {
70-
questionsOffset+=1
73+
questionsOffset += 1
7174
}
7275
}
7376
.disabled(!isAnsweredOffset())
@@ -90,7 +93,7 @@ struct CampaignForm: View {
9093
@Binding var questionsOffset: Int
9194

9295
var body: some View {
93-
VStack (spacing: 20) {
96+
VStack(spacing: 20) {
9497
if !question.answers.isEmpty {
9598
Text(question.question)
9699
.font(.raleway(.semiBold, size: 16))
@@ -99,7 +102,7 @@ struct CampaignForm: View {
99102

100103
ChoiceSelector(
101104
choicesAvailable: question.answers.map { $0.answer },
102-
defaultSelectedChoice: answersSelected[questionsOffset]?.answer,
105+
defaultSelectedChoice: answersSelected.indices.contains(questionsOffset) ? answersSelected[questionsOffset]?.answer : nil,
103106
onPress: { choice in
104107
for answerAvailable in question.answers {
105108
if answerAvailable.answer == choice {
@@ -116,21 +119,45 @@ struct CampaignForm: View {
116119
}
117120
}
118121

122+
struct OpenAnswerView: View {
123+
@Binding var openAnswer: String
124+
125+
var body: some View {
126+
VStack(spacing: 20) {
127+
Text("Des remarques ?")
128+
.font(.raleway(.semiBold, size: 16))
129+
.foregroundStyle(XPEHO_THEME.CONTENT_COLOR)
130+
.frame(maxWidth: .infinity, alignment: .leading)
131+
132+
InputText(
133+
label: "Remarques",
134+
onInput: { input in
135+
self.openAnswer = input
136+
}
137+
)
138+
}
139+
.padding(.vertical, 12)
140+
}
141+
}
142+
119143
// Methods to make clear the conditions of appearance
120144
private func isValidOffset() -> Bool {
121145
return (questionsOffset >= 0) && (questionsOffset < questions.count)
122146
}
123147

124148
private func isLastOffset() -> Bool {
125-
return (questionsOffset+1 == questions.count)
149+
return (questionsOffset == questions.count)
126150
}
127151

128152
private func isFirstOffset() -> Bool {
129153
return (questionsOffset == 0)
130154
}
131155

132156
private func isAnsweredOffset() -> Bool {
133-
return (!answersSelected.isEmpty) && (answersSelected[questionsOffset] != nil)
157+
if isLastOffset() {
158+
return !openAnswer.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
159+
}
160+
return answersSelected.indices.contains(questionsOffset) && answersSelected[questionsOffset] != nil
134161
}
135162

136163
// Init questions of the campaign
@@ -141,7 +168,7 @@ struct CampaignForm: View {
141168
return
142169
}
143170
// Prevent access when campaign is already completed
144-
if (campaign.completed){
171+
if (campaign.completed) {
145172
debugPrint("Campaign is already completed")
146173
routerManager.goBack()
147174
return
@@ -152,18 +179,17 @@ struct CampaignForm: View {
152179
routerManager.goBack()
153180
return
154181
}
155-
156182
self.questions = questions
157183
self.answersSelected = Array(repeating: nil, count: self.questions.count)
158184
}
159185
}
160186

161-
// Send answers of the campaign
162187
private func sendAnswers() {
163188
guard let campaign = routerManager.parameters["campaign"] as! QvstCampaignEntity? else {
164189
debugPrint("No campaign selected")
165190
return
166191
}
192+
167193
Task {
168194
// Get user id for the request
169195
guard let user = LoginManager.instance.getUser() else {
@@ -173,16 +199,16 @@ struct CampaignForm: View {
173199

174200
// Check that all questions has been answered
175201
var answers: [QvstAnswerModel] = []
176-
for index in answersSelected.indices {
202+
for index in 0..<questions.count {
177203
guard let answer = answersSelected[index] else {
178204
debugPrint("Not all questions have been answered")
179205
return
180206
}
181207
answers.append(answer)
182208
}
183-
209+
184210
if !isSending {
185-
// Lock to prevent multi sending by spaming button
211+
// Lock to prevent multi sending by spamming button
186212
isSending = true
187213
// Send answers
188214
guard let areAnswersSent = await WordpressAPI.instance.sendCampaignAnswers(
@@ -192,11 +218,18 @@ struct CampaignForm: View {
192218
answers: answers
193219
) else {
194220
debugPrint("Failed to send campaign answers")
221+
isSending = false
222+
return
223+
}
224+
225+
guard let isOpenAnswerSent = await WordpressAPI.instance.submitOpenAnswers(text: openAnswer)
226+
else {
227+
debugPrint("Failed to send open answer")
228+
isSending = false
195229
return
196230
}
197-
198231
// Check the return to inform user
199-
if (!areAnswersSent) {
232+
if (!areAnswersSent || !isOpenAnswerSent) {
200233
// Inform user
201234
toastManager.setParams(
202235
message: "Impossible d'envoyer vos réponses",
@@ -220,4 +253,3 @@ struct CampaignForm: View {
220253
}
221254
}
222255
}
223-

0 commit comments

Comments
 (0)