Skip to content

Commit

Permalink
Merge pull request #138 from canopas/add-user-space-admin-check-befor…
Browse files Browse the repository at this point in the history
…e-account-deletion

Add a validation for delete account.
  • Loading branch information
cp-sneh-s authored Dec 27, 2024
2 parents b20b351 + c967c0a commit 916c6e9
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,11 @@ private fun EditProfileScreenContent(modifier: Modifier) {
label = stringResource(id = R.string.settings_btn_delete_account),
onClick = {
if (state.connectivityStatus == ConnectivityObserver.Status.Available) {
viewModel.showDeleteAccountConfirmation(true)
if (state.adminGroupList.isNotEmpty()) {
viewModel.showAdminChangeDialog(true)
} else {
viewModel.showDeleteAccountConfirmation(true)
}
} else {
Toast.makeText(
context,
Expand All @@ -225,6 +229,10 @@ private fun EditProfileScreenContent(modifier: Modifier) {
if (state.showDeleteAccountConfirmation) {
ShowDeleteAccountDialog(viewModel)
}

if (state.showAdminChangeDialog) {
ShowAdminChangeDialog(viewModel)
}
}
}

Expand Down Expand Up @@ -295,3 +303,24 @@ fun UserTextField(
)
}
}

@Composable
fun ShowAdminChangeDialog(viewModel: EditProfileViewModel) {
val state by viewModel.state.collectAsState()

AppAlertDialog(
title = stringResource(R.string.account_deletion_change_admin_dialog_title),
subTitle = stringResource(
R.string.account_deletion_change_admin_dialog_subtitle,
state.adminGroupList.joinToString(separator = "\n") { "\u2022 ${it.name}" }
),
confirmBtnText = stringResource(R.string.common_btn_ok),
dismissBtnText = stringResource(R.string.common_btn_cancel),
onConfirmClick = {
viewModel.showAdminChangeDialog(false)
viewModel.popBackStack()
},
onDismissClick = { viewModel.showAdminChangeDialog(false) },
isConfirmDestructive = false
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.canopas.yourspace.ui.flow.settings.profile
import android.net.Uri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.canopas.yourspace.data.models.space.ApiSpace
import com.canopas.yourspace.data.models.user.ApiUser
import com.canopas.yourspace.data.models.user.LOGIN_TYPE_APPLE
import com.canopas.yourspace.data.models.user.LOGIN_TYPE_GOOGLE
Expand All @@ -18,6 +19,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
Expand All @@ -40,6 +42,7 @@ class EditProfileViewModel @Inject constructor(
init {
checkInternetConnection()
getUser()
fetchAdminSpaces()
}

private fun getUser() = viewModelScope.launch(appDispatcher.IO) {
Expand Down Expand Up @@ -160,8 +163,44 @@ class EditProfileViewModel @Inject constructor(
_state.value = _state.value.copy(showDeleteAccountConfirmation = show)
}

fun showAdminChangeDialog(show: Boolean) {
_state.value = _state.value.copy(showAdminChangeDialog = show)
}

private fun fetchAdminSpaces() = viewModelScope.launch(appDispatcher.IO) {
try {
val userId = authService.currentUser?.id ?: return@launch
val userSpaceList = spaceRepository.getUserSpaces(userId).firstOrNull() ?: return@launch
val spaceWithMember = mutableListOf<ApiSpace>()

for (space in userSpaceList) {
val spaceDetail = spaceRepository.getSpaceInfo(space.id)
if (spaceDetail!!.members.size > 1 && space.admin_id == userId) {
spaceWithMember.add(space)
}
}
_state.emit(_state.value.copy(adminGroupList = spaceWithMember))
} catch (e: Exception) {
Timber.e(e, "Failed to fetch admin spaces")
_state.emit(_state.value.copy(error = e))
}
}

fun deleteAccount() = viewModelScope.launch(appDispatcher.IO) {
try {
val userId = authService.currentUser?.id ?: return@launch
val isAdmin = spaceRepository.isUserAdminOfAnySpace(userId)

if (isAdmin) {
_state.emit(
_state.value.copy(
showDeleteAccountConfirmation = false,
showAdminChangeDialog = true
)
)
return@launch
}

_state.emit(
_state.value.copy(
deletingAccount = true,
Expand Down Expand Up @@ -210,5 +249,7 @@ data class EditProfileState(
val email: String? = null,
val profileUrl: String? = null,
val isImageUploadInProgress: Boolean = false,
val connectivityStatus: ConnectivityObserver.Status = ConnectivityObserver.Status.Available
val connectivityStatus: ConnectivityObserver.Status = ConnectivityObserver.Status.Available,
val showAdminChangeDialog: Boolean = false,
val adminGroupList: List<ApiSpace> = emptyList()
)
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -304,4 +304,7 @@

<string name="place_list_screen_no_members_title">Add members to add places</string>
<string name="place_list_screen_no_members_subtitle">At least one member needs to join your group to be able to add places.</string>

<string name="account_deletion_change_admin_dialog_title">Reassign Admin Before Deletion</string>
<string name="account_deletion_change_admin_dialog_subtitle">Please assign a new admin before proceeding with the account deletion to avoid data loss. \nYou are an admin of the following groups :\n%1$s</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ class SpaceRepository @Inject constructor(
spaceService.updateSpace(newSpace)
}

suspend fun isUserAdminOfAnySpace(userId: String): Boolean {
val spaces = getUserSpaces(userId).firstOrNull() ?: return false
return spaces.any { space ->
space.admin_id == userId &&
(spaceService.getMemberBySpaceId(space.id).firstOrNull()?.size ?: 1) > 1
}
}

suspend fun removeUserFromSpace(spaceId: String, userId: String) {
spaceService.removeUserFromSpace(spaceId, userId)
val user = userService.getUser(userId)
Expand Down

0 comments on commit 916c6e9

Please sign in to comment.