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

feat(class): mời người dùng vào class #85

Merged
merged 5 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.pwhs.quickmem.data.dto.classes

import com.google.gson.annotations.SerializedName

data class InviteToClassRequestDto(
@SerializedName("classId")
val classId: String,
@SerializedName("username")
val username: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.pwhs.quickmem.data.dto.classes

import com.google.gson.annotations.SerializedName

data class InviteToClassResponseDto(
@SerializedName("message")
val message: String,
@SerializedName("status")
val status: Boolean,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.pwhs.quickmem.data.mapper.classes

import com.pwhs.quickmem.data.dto.classes.InviteToClassRequestDto
import com.pwhs.quickmem.domain.model.classes.InviteToClassRequestModel

fun InviteToClassRequestModel.toDto() = InviteToClassRequestDto(
classId = classId,
username = username
)

fun InviteToClassRequestDto.toModel() = InviteToClassRequestModel(
classId = classId,
username = username
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.pwhs.quickmem.data.mapper.classes

import com.pwhs.quickmem.data.dto.classes.InviteToClassResponseDto
import com.pwhs.quickmem.domain.model.classes.InviteToClassResponseModel

fun InviteToClassResponseDto.toModel() = InviteToClassResponseModel(
message = message,
status = status
)
nqmgaming marked this conversation as resolved.
Show resolved Hide resolved

fun InviteToClassResponseModel.toDto() = InviteToClassResponseDto(
message = message,
status = status
)
nqmgaming marked this conversation as resolved.
Show resolved Hide resolved
8 changes: 8 additions & 0 deletions app/src/main/java/com/pwhs/quickmem/data/remote/ApiService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import com.pwhs.quickmem.data.dto.classes.DeleteStudySetsRequestDto
import com.pwhs.quickmem.data.dto.classes.ExitClassRequestDto
import com.pwhs.quickmem.data.dto.classes.GetClassByOwnerResponseDto
import com.pwhs.quickmem.data.dto.classes.GetClassDetailResponseDto
import com.pwhs.quickmem.data.dto.classes.InviteToClassRequestDto
import com.pwhs.quickmem.data.dto.classes.InviteToClassResponseDto
import com.pwhs.quickmem.data.dto.classes.JoinClassRequestDto
import com.pwhs.quickmem.data.dto.classes.RemoveMembersRequestDto
import com.pwhs.quickmem.data.dto.classes.SaveRecentAccessClassRequestDto
Expand Down Expand Up @@ -549,6 +551,12 @@ interface ApiService {
@Path("userId") userId: String
): List<GetClassByOwnerResponseDto>

@POST("class/invite")
suspend fun inviteUserToClass(
@Header("Authorization") token: String,
@Body inviteToClassRequestDto: InviteToClassRequestDto
): InviteToClassResponseDto

// Streak
@GET("streak/{userId}")
suspend fun getStreaksByUserId(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import com.pwhs.quickmem.domain.model.classes.DeleteStudySetsRequestModel
import com.pwhs.quickmem.domain.model.classes.ExitClassRequestModel
import com.pwhs.quickmem.domain.model.classes.GetClassByOwnerResponseModel
import com.pwhs.quickmem.domain.model.classes.GetClassDetailResponseModel
import com.pwhs.quickmem.domain.model.classes.InviteToClassRequestModel
import com.pwhs.quickmem.domain.model.classes.InviteToClassResponseModel
import com.pwhs.quickmem.domain.model.classes.JoinClassRequestModel
import com.pwhs.quickmem.domain.model.classes.RemoveMembersRequestModel
import com.pwhs.quickmem.domain.model.classes.SaveRecentAccessClassRequestModel
Expand Down Expand Up @@ -279,4 +281,22 @@ class ClassRepositoryImpl @Inject constructor(
}
}
}

override suspend fun inviteToClass(
token: String,
inviteToClassRequestModel: InviteToClassRequestModel
): Flow<Resources<InviteToClassResponseModel>> {
return flow {
emit(Resources.Loading())
try {
val response = apiService.inviteUserToClass(
token, inviteToClassRequestModel.toDto()
)
emit(Resources.Success(response.toModel()))
} catch (e: Exception) {
Timber.e(e)
emit(Resources.Error(e.toString()))
}
}
}
nqmgaming marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.pwhs.quickmem.domain.model.classes

data class InviteToClassRequestModel(
val classId: String,
val username: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.pwhs.quickmem.domain.model.classes

data class InviteToClassResponseModel(
val message: String,
val status: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import com.pwhs.quickmem.domain.model.classes.DeleteStudySetsRequestModel
import com.pwhs.quickmem.domain.model.classes.ExitClassRequestModel
import com.pwhs.quickmem.domain.model.classes.GetClassByOwnerResponseModel
import com.pwhs.quickmem.domain.model.classes.GetClassDetailResponseModel
import com.pwhs.quickmem.domain.model.classes.InviteToClassRequestModel
import com.pwhs.quickmem.domain.model.classes.InviteToClassResponseModel
import com.pwhs.quickmem.domain.model.classes.JoinClassRequestModel
import com.pwhs.quickmem.domain.model.classes.RemoveMembersRequestModel
import com.pwhs.quickmem.domain.model.classes.SaveRecentAccessClassRequestModel
Expand Down Expand Up @@ -91,4 +93,9 @@ interface ClassRepository {
token: String,
userId: String
): Flow<Resources<List<GetClassByOwnerResponseModel>>>

suspend fun inviteToClass(
token: String,
inviteToClassRequestModel: InviteToClassRequestModel
): Flow<Resources<InviteToClassResponseModel>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.pwhs.quickmem.domain.model.users.ClassMemberModel
import com.pwhs.quickmem.domain.model.users.UserResponseModel
import com.pwhs.quickmem.presentation.app.classes.detail.component.ClassDetailBottomSheet
import com.pwhs.quickmem.presentation.app.classes.detail.component.ClassDetailTopAppBar
import com.pwhs.quickmem.presentation.app.classes.detail.component.InviteClassBottomSheet
import com.pwhs.quickmem.presentation.app.classes.detail.folders.FoldersTabScreen
import com.pwhs.quickmem.presentation.app.classes.detail.members.MembersTabScreen
import com.pwhs.quickmem.presentation.app.classes.detail.study_sets.StudySetsTabScreen
Expand Down Expand Up @@ -204,6 +205,10 @@ fun ClassDetailScreen(
ClassDetailUiEvent.OnNavigateToRemoveMembers -> {

}

ClassDetailUiEvent.InviteToClassSuccess -> {
Toast.makeText(context, "Invite to class success", Toast.LENGTH_SHORT).show()
}
}
}
}
Expand All @@ -220,6 +225,11 @@ fun ClassDetailScreen(
resultNavigator.navigateBack(true)
},
title = uiState.title,
username = uiState.username,
errorMessage = uiState.errorMessage,
onUsernameChanged = {
viewModel.onEvent(ClassDetailUiAction.OnChangeUsername(it))
},
isLoading = uiState.isLoading,
isAllowMember = uiState.allowMember,
userResponseModel = uiState.userResponseModel,
Expand Down Expand Up @@ -268,6 +278,9 @@ fun ClassDetailScreen(
onJoinClass = {
viewModel.onEvent(ClassDetailUiAction.OnJoinClass)
},
onInviteClass = {
viewModel.onEvent(ClassDetailUiAction.OnInviteClass)
},
onReportClass = {
navigator.navigate(
ReportScreenDestination(
Expand All @@ -292,6 +305,9 @@ fun ClassDetail(
modifier: Modifier = Modifier,
isOwner: Boolean,
title: String = "",
username: String = "",
onUsernameChanged: (String) -> Unit = {},
errorMessage: String = "",
isLoading: Boolean = false,
isMember: Boolean = false,
isAllowMember: Boolean = false,
Expand All @@ -307,6 +323,7 @@ fun ClassDetail(
onEditClass: () -> Unit = {},
onExitClass: () -> Unit = {},
onJoinClass: () -> Unit = {},
onInviteClass: () -> Unit = {},
onRemoveMembers: (String) -> Unit = {},
onDeleteClass: () -> Unit = {},
onRefresh: () -> Unit = {},
Expand All @@ -324,6 +341,7 @@ fun ClassDetail(
val sheetShowMoreState = rememberModalBottomSheetState()
var showDeleteConfirmationDialog by remember { mutableStateOf(false) }
var showExitConfirmationDialog by remember { mutableStateOf(false) }
var showInviteClassBottomSheet by remember { mutableStateOf(false) }
val context = LocalContext.current

Scaffold(
Expand Down Expand Up @@ -456,6 +474,27 @@ fun ClassDetail(
dismissButtonTitle = "Cancel",
)
}

if (showInviteClassBottomSheet) {
InviteClassBottomSheet(
username = username,
errorMessage = errorMessage,
onUsernameChanged = onUsernameChanged,
showInviteClassBottomSheet = showInviteClassBottomSheet,
sheetShowMoreState = sheetShowMoreState,
onDismissRequest = {
showInviteClassBottomSheet = false
onUsernameChanged("")
},
nqmgaming marked this conversation as resolved.
Show resolved Hide resolved
onSubmitClick = {
onInviteClass()
// if (!isLoading && errorMessage.isEmpty()) {
// showInviteClassBottomSheet = false
// }
}
nqmgaming marked this conversation as resolved.
Show resolved Hide resolved
)
}

ClassDetailBottomSheet(
onAddStudySetToClass = onNavigateAddStudySets,
onAddFolderToClass = onNavigateAddFolder,
Expand All @@ -468,7 +507,10 @@ fun ClassDetail(
showExitConfirmationDialog = true
showMoreBottomSheet = false
},
onShareClass = {},
onInviteClass = {
showInviteClassBottomSheet = true
showMoreBottomSheet = false
},
onReportClass = {
onReportClass()
showMoreBottomSheet = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ sealed class ClassDetailUiAction {
data object OnNavigateToAddFolder : ClassDetailUiAction()
data object OnNavigateToAddStudySets : ClassDetailUiAction()
data object OnJoinClass : ClassDetailUiAction()
data class OnChangeUsername(val username: String) : ClassDetailUiAction()
data object ExitClass : ClassDetailUiAction()
data object OnInviteClass : ClassDetailUiAction()
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ sealed class ClassDetailUiEvent {
data object ClassDeleted : ClassDetailUiEvent()
data object NavigateToEditClass : ClassDetailUiEvent()
data object ExitClass : ClassDetailUiEvent()
data object InviteToClassSuccess : ClassDetailUiEvent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ data class ClassDetailUiState(
val allowSet: Boolean = false,
val allowMember: Boolean = false,
val isMember: Boolean = false,
val username: String = "",
val errorMessage: String = "",
val statusInvite : Boolean = false,
nqmgaming marked this conversation as resolved.
Show resolved Hide resolved
val userResponseModel: UserResponseModel = UserResponseModel(),
val studySets: List<GetStudySetResponseModel> = emptyList(),
val folders: List<GetFolderResponseModel> = emptyList(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.pwhs.quickmem.core.utils.Resources
import com.pwhs.quickmem.domain.model.classes.DeleteFolderRequestModel
import com.pwhs.quickmem.domain.model.classes.DeleteStudySetsRequestModel
import com.pwhs.quickmem.domain.model.classes.ExitClassRequestModel
import com.pwhs.quickmem.domain.model.classes.InviteToClassRequestModel
import com.pwhs.quickmem.domain.model.classes.JoinClassRequestModel
import com.pwhs.quickmem.domain.model.classes.RemoveMembersRequestModel
import com.pwhs.quickmem.domain.model.classes.SaveRecentAccessClassRequestModel
Expand Down Expand Up @@ -113,6 +114,19 @@ class ClassDetailViewModel @Inject constructor(
is ClassDetailUiAction.OnDeleteFolderInClass -> {
deleteFolderInClass(event.folderId)
}

is ClassDetailUiAction.OnChangeUsername -> {
_uiState.update {
it.copy(
username = event.username,
errorMessage = ""
)
}
}

ClassDetailUiAction.OnInviteClass -> {
inviteToClass()
}
}
}

Expand Down Expand Up @@ -415,4 +429,78 @@ class ClassDetailViewModel @Inject constructor(
}
}
}

private fun inviteToClass() {
viewModelScope.launch {
val token = tokenManager.accessToken.firstOrNull() ?: ""
val classId = _uiState.value.id
val username = _uiState.value.username
if (username.isEmpty()) {
_uiState.update {
it.copy(
errorMessage = "Username cannot be empty"
)
}
return@launch
}
if (username.length < 4) {
_uiState.update {
it.copy(
errorMessage = "Username must be at least 4 characters"
)
}
return@launch
}

classRepository.inviteToClass(
token,
InviteToClassRequestModel(classId, username)
).collectLatest { resource ->
when (resource) {
is Resources.Loading -> {
_uiState.update {
it.copy(
isLoading = true
)
}
Timber.d("Loading")
}

is Resources.Success -> {
_uiState.update {
it.copy(
isLoading = false,
statusInvite = resource.data?.status == true
)
}
if (_uiState.value.statusInvite == true) {
_uiEvent.send(ClassDetailUiEvent.InviteToClassSuccess)
} else {
_uiState.update {
it.copy(
errorMessage = resource.data?.message ?: "An error occurred"
)
}
}
Timber.d("Success")
}

is Resources.Error -> {
_uiState.update {
it.copy(
errorMessage = resource.message ?: "An error occurred",
isLoading = false
)
}
_uiEvent.send(
ClassDetailUiEvent.ShowError(
resource.message ?: "An error occurred"
)
)
Timber.d("Error")
}
nqmgaming marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
}
Loading