Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Survey-Question-Logic-Implemented #2262

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions core/data/src/main/java/com/mifos/core/data/di/DataModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import com.mifos.core.data.repository.ReportDetailRepository
import com.mifos.core.data.repository.SearchRepository
import com.mifos.core.data.repository.SignatureRepository
import com.mifos.core.data.repository.SurveyListRepository
import com.mifos.core.data.repository.SurveyQuestionRepository
import com.mifos.core.data.repository.SurveySubmitRepository
import com.mifos.core.data.repositoryImp.ActivateRepositoryImp
import com.mifos.core.data.repositoryImp.CenterDetailsRepositoryImp
Expand Down Expand Up @@ -89,6 +90,7 @@ import com.mifos.core.data.repositoryImp.SearchRepositoryImp
import com.mifos.core.data.repositoryImp.SignatureRepositoryImp
import com.mifos.core.data.repositoryImp.SurveyListRepositoryImp
import com.mifos.core.data.repositoryImp.SurveySubmitRepositoryImp
import com.mifos.core.data.repository_imp.SurveyQuestionRepositoryImp
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
Expand Down Expand Up @@ -191,6 +193,9 @@ abstract class DataModule {
@Binds
internal abstract fun bindSurveyListRepository(impl: SurveyListRepositoryImp): SurveyListRepository

@Binds
internal abstract fun bindSurveyQuestionRepository(impl: SurveyQuestionRepositoryImp): SurveyQuestionRepository

@Binds
internal abstract fun bindSurveySubmitRepository(impl: SurveySubmitRepositoryImp): SurveySubmitRepository

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mifos.core.data.repository

import com.mifos.core.objects.survey.Survey
import rx.Observable

interface SurveyQuestionRepository {

fun getSurvey(surveyId: Int): Observable<Survey>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.mifos.core.data.repository_imp

import com.mifos.core.data.repository.SurveyQuestionRepository
import com.mifos.core.network.datamanager.DataManagerSurveys
import com.mifos.core.objects.survey.Survey
import rx.Observable
import javax.inject.Inject

class SurveyQuestionRepositoryImp @Inject constructor(private val dataManagerSurveys: DataManagerSurveys) :
SurveyQuestionRepository {

override fun getSurvey(surveyId: Int): Observable<Survey> {
return dataManagerSurveys.getSurvey(surveyId)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.gson.Gson
import com.mifos.core.designsystem.component.MifosCircularProgress
import com.mifos.core.designsystem.component.MifosScaffold
import com.mifos.core.designsystem.component.MifosSweetError
import com.mifos.core.designsystem.icon.MifosIcons
import com.mifos.core.designsystem.theme.Black
import com.mifos.core.designsystem.theme.BluePrimary
Expand All @@ -79,65 +81,100 @@ import java.util.Date
@Composable
internal fun SurveyQuestionScreen(
navigateBack: () -> Unit,
survey: Survey?,
viewModel: SurveySubmitViewModel = hiltViewModel(),
submitViewModel: SurveySubmitViewModel = hiltViewModel(),
questionViewModel: SurveyQuestionViewModel = hiltViewModel(),
) {
val surveyId by questionViewModel.surveyId.collectAsStateWithLifecycle()
val context = LocalContext.current
val uiState by viewModel.surveySubmitUiState.collectAsStateWithLifecycle()
val clientId by viewModel.clientId.collectAsStateWithLifecycle()
val userId by viewModel.userId.collectAsStateWithLifecycle()
val surveyQuestionUiState by questionViewModel.surveyQuestionUiState.collectAsStateWithLifecycle()
val surveySubmitUiState by submitViewModel.surveySubmitUiState.collectAsStateWithLifecycle()
val clientId by submitViewModel.clientId.collectAsStateWithLifecycle()
val userId by submitViewModel.userId.collectAsStateWithLifecycle()
val scoreCardData: MutableList<ScorecardValues> by rememberSaveable {
mutableStateOf(mutableListOf())
}
LaunchedEffect(key1 = Unit) {
questionViewModel.loadSurvey(surveyId)
}
var currentQuestionNumber by rememberSaveable { mutableIntStateOf(0) }
var showSubmitScreen by rememberSaveable { mutableStateOf(false) }
val snackbarHostState = remember {
SnackbarHostState()
}
when (surveyQuestionUiState) {
is SurveyQuestionUiState.ShowQuestions -> {
val survey: Survey = (surveyQuestionUiState as SurveyQuestionUiState.ShowQuestions).ques
val (questionData, optionsData) = processSurveyData(survey)

if (survey != null) {
val (questionData, optionsData) = processSurveyData(survey)
SurveyQuestionScreen(
uiState = surveySubmitUiState,
navigateBack = navigateBack,
questionNumber = currentQuestionNumber,
currentQuestionData = questionData,
currentOptionsData = optionsData,
currentScoreCardData = scoreCardData,
showSubmitScreen = showSubmitScreen,
gotoNextQuestion = { index ->
if (index != -1) {
val scoreCardValue = ScorecardValues(
questionId = survey.questionDatas[currentQuestionNumber].questionId,
responseId = survey.questionDatas[currentQuestionNumber].responseDatas[index].responseId,
value = survey.questionDatas[currentQuestionNumber].responseDatas[index].value,
)
scoreCardData.add(scoreCardValue)
}
if (currentQuestionNumber < questionData.size - 1) {
currentQuestionNumber += 1
} else {
showSubmitScreen = true
}
},
submitSurvey = {
if (scoreCardData.isNotEmpty()) {
submitViewModel.submitSurvey(
survey = survey.id,
scorecardPayload = Scorecard(
userId = userId,
clientId = clientId,
createdOn = Date(),
scorecardValues = scoreCardData,
),
)
} else {
Toast.makeText(
context,
context.getString(R.string.feature_client_please_attempt_at_least_one_question),
Toast.LENGTH_SHORT,
).show()
}
},
)
}

SurveyQuestionScreen(
uiState = uiState,
navigateBack = navigateBack,
questionNumber = currentQuestionNumber,
currentQuestionData = questionData,
currentOptionsData = optionsData,
currentScoreCardData = scoreCardData,
showSubmitScreen = showSubmitScreen,
gotoNextQuestion = { index ->
if (index != -1) {
val scoreCardValue = ScorecardValues(
questionId = survey.questionDatas[currentQuestionNumber].questionId,
responseId = survey.questionDatas[currentQuestionNumber].responseDatas[index].responseId,
value = survey.questionDatas[currentQuestionNumber].responseDatas[index].value,
)
scoreCardData.add(scoreCardValue)
}
if (currentQuestionNumber < questionData.size - 1) {
currentQuestionNumber += 1
} else {
showSubmitScreen = true
}
},
submitSurvey = {
if (scoreCardData.isNotEmpty()) {
viewModel.submitSurvey(
survey = survey.id,
scorecardPayload = Scorecard(
userId = userId,
clientId = clientId,
createdOn = Date(),
scorecardValues = scoreCardData,
),
)
} else {
Toast.makeText(
context,
context.getString(R.string.feature_client_please_attempt_at_least_one_question),
Toast.LENGTH_SHORT,
).show()
}
},
)
is SurveyQuestionUiState.ShowFetchingError -> {
MifosScaffold(
snackbarHostState = snackbarHostState,
icon = MifosIcons.arrowBack,
onBackPressed = navigateBack,
title = stringResource(id = R.string.feature_client_surveys),
) {
MifosSweetError(
message = stringResource(id = R.string.feature_client_failed_to_fetch_survey_questions),
onclick = { questionViewModel.loadSurvey(surveyId) },
)
}
}

SurveyQuestionUiState.ShowProgressbar -> {
MifosScaffold(
snackbarHostState = snackbarHostState,
icon = MifosIcons.arrowBack,
onBackPressed = navigateBack,
title = stringResource(id = R.string.feature_client_surveys),
) {
MifosCircularProgress()
}
}
}
}

Expand Down Expand Up @@ -284,7 +321,11 @@ private fun SurveyQuestionContent(
}

@Composable
private fun RadioGroup(options: List<String>, selectedOptionIndex: Int, onOptionSelected: (Int) -> Unit) {
private fun RadioGroup(
options: List<String>,
selectedOptionIndex: Int,
onOptionSelected: (Int) -> Unit,
) {
Column {
options.forEachIndexed { index, option ->
Row(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.feature.client.clientSurveyQuestion

import com.mifos.core.objects.survey.Survey

sealed class SurveyQuestionUiState {

data object ShowProgressbar : SurveyQuestionUiState()

data class ShowFetchingError(val message: Int) : SurveyQuestionUiState()

data class ShowQuestions(val ques: Survey) : SurveyQuestionUiState()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.feature.client.clientSurveyQuestion

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import com.mifos.core.common.utils.Constants
import com.mifos.core.data.repository.SurveyQuestionRepository
import com.mifos.core.objects.survey.Survey
import com.mifos.feature.client.R
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import rx.Subscriber
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import javax.inject.Inject

@HiltViewModel
class SurveyQuestionViewModel @Inject constructor(
private val surveyQuestionRepository: SurveyQuestionRepository,
private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
val surveyId = savedStateHandle.getStateFlow(key = Constants.CLIENT_ID, initialValue = -1)
private val _surveyQuestionUiState =
MutableStateFlow<SurveyQuestionUiState>(SurveyQuestionUiState.ShowProgressbar)
val surveyQuestionUiState: StateFlow<SurveyQuestionUiState> get() = _surveyQuestionUiState

private lateinit var mSyncSurvey: Survey

fun loadSurvey(surveyId: Int) {
_surveyQuestionUiState.value = SurveyQuestionUiState.ShowProgressbar

surveyQuestionRepository.getSurvey(surveyId)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(object : Subscriber<Survey>() {
override fun onCompleted() {
_surveyQuestionUiState.value = SurveyQuestionUiState.ShowQuestions(ques = mSyncSurvey)
}
override fun onError(e: Throwable) {
_surveyQuestionUiState.value =
SurveyQuestionUiState.ShowFetchingError(R.string.feature_client_failed_to_fetch_survey_questions)
}

override fun onNext(survey: Survey) {
mSyncSurvey = survey
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ fun NavGraphBuilder.clientSurveyQuestionRoute(
) {
SurveyQuestionScreen(
navigateBack = onBackPressed,
survey = Survey(),
)
}
}
Expand Down Expand Up @@ -278,6 +277,10 @@ fun NavController.navigateClientSurveyListScreen(clientId: Int) {
navigate(ClientScreens.ClientSurveyListScreen.argument(clientId))
}

fun NavController.navigateSurveyQuestionScreen(surveyId: Int) {
navigate(ClientScreens.ClientSurveyQuestionScreen.argument(surveyId))
}

fun NavController.navigateCreateClientScreen() {
navigate(ClientScreens.CreateClientScreen.route)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ sealed class ClientScreens(val route: String) {
fun argument(clientId: Int) = "client_survey_list_screen/$clientId"
}

data object ClientSurveyQuestionScreen : ClientScreens("client_survey_question_screen")
data object ClientSurveyQuestionScreen : ClientScreens("client_survey_question_screen/{${Constants.CLIENT_ID}}") {
fun argument(surveyId: Int) = "client_survey_question_screen/$surveyId"
}

data object CreateClientScreen : ClientScreens("create_client_screen/{${Constants.CLIENT_ID}}")
}
1 change: 1 addition & 0 deletions feature/client/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
<string name="feature_client_select_one_survey">Select one survey</string>
<string name="feature_client_failed_to_fetch_datatable">Failed to fetch datatable</string>
<string name="feature_client_failed_to_fetch_surveys_list">Failed to fetch surveys list</string>
<string name="feature_client_failed_to_fetch_survey_questions">Failed to fetch survey Questions</string>
<string name="feature_client_failed_to_load_db_question_data">Failed to load db question data</string>
<string name="feature_client_survey_successfully_submitted">Survey successfully submitted</string>
<string name="feature_client_failed_to_submit_survey">Failed to submit survey</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.mifos.feature.checkerInboxTask.navigation.checkerInboxTaskGraph
import com.mifos.feature.client.navigation.clientNavGraph
import com.mifos.feature.client.navigation.navigateClientDetailsScreen
import com.mifos.feature.client.navigation.navigateCreateClientScreen
import com.mifos.feature.client.navigation.navigateSurveyQuestionScreen
import com.mifos.feature.client.navigation.navigateToClientListScreen
import com.mifos.feature.dataTable.navigation.dataTableNavGraph
import com.mifos.feature.dataTable.navigation.navigateDataTableList
Expand Down Expand Up @@ -105,7 +106,8 @@ fun Navigation(
hasDatatables = navController::navigateDataTableList,
onDocumentClicked = navController::navigateToDocumentListScreen,
onCardClicked = { position, survey ->
// TODO
val id: Int = survey[position].id
navController.navigateSurveyQuestionScreen(id)
},
)

Expand Down