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 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -88,6 +89,7 @@ import com.mifos.core.data.repositoryImp.ReportDetailRepositoryImp
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.SurveyQuestionRepositoryImp
import com.mifos.core.data.repositoryImp.SurveySubmitRepositoryImp
import dagger.Binds
import dagger.Module
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,18 @@
/*
* Copyright 2025 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.core.data.repository

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

interface SurveyQuestionRepository {

fun getSurvey(surveyId: Int): Observable<Survey>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@itsPronay bhai, what do you say about using Flow instead of Observables???

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea bhai, we can use that. but it shouldn't be an issue now i guess, since we are using Observable in the whole project.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ha bhai

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2025 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.core.data.repositoryImp

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> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here!

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,97 @@ 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())
}
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 +318,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,62 @@
/*
* 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 = 0)
private val _surveyQuestionUiState =
MutableStateFlow<SurveyQuestionUiState>(SurveyQuestionUiState.ShowProgressbar)
val surveyQuestionUiState: StateFlow<SurveyQuestionUiState> get() = _surveyQuestionUiState

init {
loadSurvey(surveyId.value)
}

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"
}
Comment on lines +48 to +50
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

client ID? shouldn't this be survey_id !?

Copy link
Contributor

@Darkeye14 Darkeye14 Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nahi bhai, I think clientid is correct??? We are taking the survey for that particular client right??

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Darkeye14 Correct me if I am wrong, but on line 49 we are passing surveyId right?? Even in the ViewModel, we are retrieving that value and storing it in the surveyId variable. however on line 48, it says Client_ID

Shouldn’t both be the same!?!

Copy link
Contributor

@itsPronay itsPronay Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea in my opinion both should be the same.. either survey_id or client_id depending on what we are passing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nahi bhai, i think this is correct!!

Copy link
Contributor

@itsPronay itsPronay Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh... my apologies. I didn't see we are using 2 view models here. @sujalagrawal2 its correct


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 = survey[position].id
navController.navigateSurveyQuestionScreen(id)
},
)

Expand Down