Skip to content

Commit

Permalink
Merge pull request #400 from Assocify-Team/mc/378-vm-members-management
Browse files Browse the repository at this point in the history
Viewmodel : members management
  • Loading branch information
Mai-LinhC authored Jun 2, 2024
2 parents 02429b4 + dfca8fe commit 2f0f590
Show file tree
Hide file tree
Showing 11 changed files with 820 additions and 611 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.github.se.assocify.screens.profile

import android.util.Log
import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsSelected
import androidx.compose.ui.test.assertTextContains
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onAllNodesWithTag
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
Expand All @@ -14,6 +14,7 @@ import androidx.compose.ui.test.performScrollToNode
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.github.se.assocify.model.CurrentUser
import com.github.se.assocify.model.database.AssociationAPI
import com.github.se.assocify.model.database.UserAPI
import com.github.se.assocify.model.entities.Association
import com.github.se.assocify.model.entities.AssociationMember
import com.github.se.assocify.model.entities.PermissionRole
Expand Down Expand Up @@ -41,7 +42,7 @@ class ProfileMembersScreenTest :
private val navActions = mockk<NavigationActions>()
private var goBack = false

private val userList =
private var userList =
listOf(
User("1", "Sarah"),
User("2", "veryveryveryverylooooooooooooooooooooongnameeeeeeeeee"),
Expand All @@ -56,14 +57,29 @@ class ProfileMembersScreenTest :
User("11", "Ivy"),
)

private var userRole: MutableMap<String, RoleType> =
mutableMapOf(
"1" to RoleType.PRESIDENCY,
"2" to RoleType.TREASURY,
"3" to RoleType.MEMBER,
"4" to RoleType.MEMBER,
"5" to RoleType.MEMBER,
"6" to RoleType.MEMBER,
"7" to RoleType.MEMBER,
"8" to RoleType.MEMBER,
"9" to RoleType.MEMBER,
"10" to RoleType.MEMBER,
"11" to RoleType.MEMBER,
)

private val applicantList = userList.take(2)

private val assoMembers: List<AssociationMember> =
private var assoMembers: List<AssociationMember> =
userList.map {
AssociationMember(
it,
Association("a", "assoName", "", LocalDate.EPOCH),
PermissionRole("r", "a", RoleType.MEMBER))
PermissionRole("r", "a", userRole[it.uid]!!))
}

private val associationAPI =
Expand All @@ -76,6 +92,27 @@ class ProfileMembersScreenTest :
{
secondArg<(List<AssociationMember>) -> Unit>().invoke(assoMembers)
}
every { updateCache(any(), any()) } answers
{
firstArg<(Map<String, Association>) -> Unit>()
.invoke(mapOf("a" to Association("a", "assoName", "", LocalDate.EPOCH)))
}
}

private val userAPI =
mockk<UserAPI> {
every { removeUserFromAssociation(any(), any(), any(), any()) } answers
{
assoMembers = assoMembers.filter { it.user.uid != firstArg<String>() }
val onSuccess = thirdArg<() -> Unit>()
onSuccess()
}
every { changeRoleOfUser(any(), any(), any(), any(), any()) } answers
{
userRole[firstArg<String>()] = thirdArg<RoleType>()
val onSuccess = arg<() -> Unit>(3)
onSuccess()
}
}

@Before
Expand All @@ -87,7 +124,7 @@ class ProfileMembersScreenTest :

composeTestRule.setContent {
ProfileMembersScreen(
navActions = navActions, ProfileMembersViewModel(navActions, associationAPI))
navActions = navActions, ProfileMembersViewModel(associationAPI, userAPI))
}
}

Expand All @@ -96,11 +133,6 @@ class ProfileMembersScreenTest :
with(composeTestRule) {
onNodeWithTag("Members Screen").assertIsDisplayed()

onNodeWithText("New requests").assertIsDisplayed()
applicantList.forEach { onNodeWithTag("applicantCard-${it.uid}").assertIsDisplayed() }
onAllNodesWithTag("rejectButton").assertCountEquals(applicantList.size)
onAllNodesWithTag("acceptButton").assertCountEquals(applicantList.size)

onNodeWithText("Current members").performScrollTo().assertIsDisplayed()
assoMembers.forEach {
Log.e("assoMembers", it.user.uid)
Expand All @@ -110,6 +142,43 @@ class ProfileMembersScreenTest :
}
}

@Test
fun editMember() {
with(composeTestRule) {
val member = assoMembers[0]
val originalRole = member.role.type.name
onNodeWithTag("memberItem-${member.user.uid}").assertTextContains(originalRole)
onNodeWithTag("editButton-0").performClick()
onNodeWithText("Change ${member.user.name}'s role ?").assertIsDisplayed()
onNodeWithTag("role-${originalRole}").assertIsSelected()
onNodeWithTag("role-${RoleType.PRESIDENCY.name}").performClick()
onNodeWithTag("confirmButton").performClick()
onNodeWithTag("memberItem-${member.user.uid}").assertTextContains(RoleType.PRESIDENCY.name)
onNodeWithTag("editButton-0").performClick()
onNodeWithTag("role-${RoleType.PRESIDENCY.name}").assertIsSelected()
onNodeWithTag("role-${originalRole}").performClick()
onNodeWithTag("cancelButton").performClick()
onNodeWithTag("memberItem-${member.user.uid}").assertTextContains(RoleType.PRESIDENCY.name)
}
}

@Test
fun deleteMember() {
with(composeTestRule) {
val member = assoMembers[1]
onNodeWithTag("memberItem-${assoMembers[0].user.uid}").assertIsDisplayed()
onNodeWithTag("deleteMemberButton-0").performClick()
onNodeWithText("You cannot remove yourself").assertIsDisplayed()
onNodeWithTag("deleteMemberButton-1").performClick()
onNodeWithText("Are you sure you want to remove ${member.user.name} from the association?")
.assertIsDisplayed()
onNodeWithTag("cancelButton").performClick()
onNodeWithTag("deleteMemberButton-1").performClick()
onNodeWithTag("confirmButton").performClick()
onNodeWithTag("memberItem-${member.user.uid}").assertDoesNotExist()
}
}

@Test
fun goBack() {
with(composeTestRule) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,10 @@ class UserAPI(private val db: SupabaseClient, cachePath: Path) : SupabaseApi() {
}) {
filter {
eq("user_id", userId)
eq("role_id", roleIDToChange.toString().drop(1).dropLast(1))
eq("role_id", roleIDToChange!!["uid"].toString().drop(1).dropLast(1))
}
}

onSuccess()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
package com.github.se.assocify.ui.composables

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

/**
* A container to make a scrollable content pullable to refresh.
*
* This box is meant to be used as a wrapper around a vertically scrolling element, such as a Column
* or LazyColumn. It will allow the user to pull down on the content to refresh it. The box will
* automatically show a loading indicator when the content is refreshing.
*
* The box will take up the entire size of its parent (typically a Scaffold), and will apply the
* padding values to the content inside the box.
*
* NOTE: Pass the scaffold padding values to the box itself, NOT the content inside the box.
*
* @param refreshing Whether the content is currently refreshing.
* @param onRefresh The callback to call when the user pulls down to refresh.
* @param paddingValues The padding values to apply to the container.
*/
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun PullDownRefreshBox(
refreshing: Boolean,
onRefresh: () -> Unit,
paddingValues: PaddingValues? = null,
modifier: Modifier = Modifier,
content: @Composable () -> Unit = {},
) {
val pullRefreshState = rememberPullRefreshState(refreshing, onRefresh)

Box(
modifier =
modifier
.padding(paddingValues ?: PaddingValues(0.dp))
.fillMaxSize()
.pullRefresh(pullRefreshState)) {
content()
PullRefreshIndicator(refreshing, pullRefreshState, Modifier.align(Alignment.TopCenter))
}
}
package com.github.se.assocify.ui.composables

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

/**
* A container to make a scrollable content pullable to refresh.
*
* This box is meant to be used as a wrapper around a vertically scrolling element, such as a Column
* or LazyColumn. It will allow the user to pull down on the content to refresh it. The box will
* automatically show a loading indicator when the content is refreshing.
*
* The box will take up the entire size of its parent (typically a Scaffold), and will apply the
* padding values to the content inside the box.
*
* NOTE: Pass the scaffold padding values to the box itself, NOT the content inside the box.
*
* @param refreshing Whether the content is currently refreshing.
* @param onRefresh The callback to call when the user pulls down to refresh.
* @param paddingValues The padding values to apply to the container.
*/
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun PullDownRefreshBox(
refreshing: Boolean,
onRefresh: () -> Unit,
paddingValues: PaddingValues? = null,
modifier: Modifier = Modifier,
content: @Composable () -> Unit = {},
) {
val pullRefreshState = rememberPullRefreshState(refreshing, onRefresh)

Box(
modifier =
modifier
.padding(paddingValues ?: PaddingValues(0.dp))
.fillMaxSize()
.pullRefresh(pullRefreshState)) {
content()
PullRefreshIndicator(refreshing, pullRefreshState, Modifier.align(Alignment.TopCenter))
}
}
Loading

0 comments on commit 2f0f590

Please sign in to comment.