Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.moneymong.moneymong.design_system.component.tag
import androidx.annotation.DrawableRes
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
Expand All @@ -13,16 +14,19 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.moneymong.moneymong.design_system.R
import com.moneymong.moneymong.design_system.theme.Blue04
import com.moneymong.moneymong.design_system.theme.Body2
import com.moneymong.moneymong.design_system.theme.Body3
import com.moneymong.moneymong.design_system.theme.Gray03
import com.moneymong.moneymong.design_system.theme.Gray05
import com.moneymong.moneymong.design_system.theme.Gray06
import com.moneymong.moneymong.design_system.theme.Gray08
import com.moneymong.moneymong.design_system.theme.White
import com.moneymong.moneymong.ui.noRippleClickable

Expand Down Expand Up @@ -64,38 +68,56 @@ fun MDSTag(
fun MDSOutlineTag(
modifier: Modifier = Modifier,
text: String,
selected: Boolean = false,
@DrawableRes iconResource: Int? = null,
onClick: () -> Unit,
onClick: () -> Unit = {},
) {
Row(
modifier = modifier
.border(
width = 1.4.dp,
color = Gray03,
color = if (selected) Blue04 else Gray03,
shape = RoundedCornerShape(size = Int.MAX_VALUE.dp)
)
.clip(RoundedCornerShape(size = Int.MAX_VALUE.dp))
.background(
color = White,
shape = RoundedCornerShape(size = Int.MAX_VALUE.dp)
)
.clickable(
enabled = iconResource == null,
onClick = onClick
)
.padding(horizontal = 12.dp, vertical = 6.dp),
horizontalArrangement = Arrangement.spacedBy(2.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = text,
color = Gray06,
color = if (selected) Gray08 else Gray06,
style = Body3,
)
if (iconResource != null) {
Icon(
modifier = Modifier
.size(18.dp)
.noRippleClickable(onClick),
painter = painterResource(id = iconResource),
contentDescription = "Tag icon",
tint = Gray05
)
when {
!selected && iconResource != null -> {
Icon(
modifier = Modifier
.size(18.dp)
.noRippleClickable(onClick),
painter = painterResource(id = iconResource),
contentDescription = "Tag icon",
tint = Gray05
)
}

selected -> {
Icon(
modifier = Modifier
.size(18.dp),
painter = painterResource(id = R.drawable.ic_check),
contentDescription = "Tag icon",
tint = Blue04
)
}
}
}
}
Expand All @@ -116,7 +138,7 @@ fun MDSTagPreview() {
text = "tag",
backgroundColor = Blue04,
contentColor = White,
iconResource = com.moneymong.moneymong.design_system.R.drawable.ic_pencil
iconResource = R.drawable.ic_pencil
)
}
}
Expand All @@ -130,11 +152,13 @@ fun MDSOutlineTagPreview() {
) {
MDSOutlineTag(
text = "tag",
selected = false,
onClick = {},
)
MDSOutlineTag(
text = "tag",
iconResource = com.moneymong.moneymong.design_system.R.drawable.ic_close_default,
selected = true,
iconResource = R.drawable.ic_close_default,
onClick = {},
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.moneymong.moneymong.model.agency

data class CategoryReadResponse(
val agencyId: Long,
val categories: List<CategoryResponse>,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.moneymong.moneymong.model.agency.AgencyJoinResponse
import com.moneymong.moneymong.model.agency.AgencyRegisterRequest
import com.moneymong.moneymong.model.agency.CategoryCreateRequest
import com.moneymong.moneymong.model.agency.CategoryCreateResponse
import com.moneymong.moneymong.model.agency.CategoryReadResponse
import com.moneymong.moneymong.model.agency.MyAgencyResponse
import com.moneymong.moneymong.model.agency.RegisterAgencyResponse
import com.moneymong.moneymong.model.member.InvitationCodeResponse
Expand Down Expand Up @@ -40,6 +41,11 @@ interface AgencyApi {
@Query("keyword") name: String
): Result<List<AgencyGetResponse>>

@GET("api/v1/agencies/categories")
suspend fun fetchCategories(
@Query("agencyId") agencyId: Long
): Result<CategoryReadResponse>

// POST
@POST("/api/v2/agencies/invitation-code")
suspend fun agencyCodeNumbers(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.moneymong.moneymong.model.agency.AgencyJoinResponse
import com.moneymong.moneymong.model.agency.AgencyRegisterRequest
import com.moneymong.moneymong.model.agency.CategoryCreateRequest
import com.moneymong.moneymong.model.agency.CategoryCreateResponse
import com.moneymong.moneymong.model.agency.CategoryReadResponse
import com.moneymong.moneymong.model.agency.MyAgencyResponse
import com.moneymong.moneymong.model.agency.RegisterAgencyResponse

Expand All @@ -17,4 +18,5 @@ interface AgencyRemoteDataSource {
suspend fun fetchAgencyByName(agencyName: String): Result<List<AgencyGetResponse>>
suspend fun agencyCodeNumbers(data: AgencyJoinRequest): Result<AgencyJoinResponse>
suspend fun createCategory(request: CategoryCreateRequest): Result<CategoryCreateResponse>
suspend fun fetchCategories(agencyId: Long): Result<CategoryReadResponse>
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.moneymong.moneymong.model.agency.AgencyJoinResponse
import com.moneymong.moneymong.model.agency.AgencyRegisterRequest
import com.moneymong.moneymong.model.agency.CategoryCreateRequest
import com.moneymong.moneymong.model.agency.CategoryCreateResponse
import com.moneymong.moneymong.model.agency.CategoryReadResponse
import com.moneymong.moneymong.model.agency.MyAgencyResponse
import com.moneymong.moneymong.model.agency.RegisterAgencyResponse
import com.moneymong.moneymong.network.api.AgencyApi
Expand Down Expand Up @@ -41,4 +42,8 @@ class AgencyRemoteDataSourceImpl @Inject constructor(
override suspend fun createCategory(request: CategoryCreateRequest): Result<CategoryCreateResponse> {
return agencyApi.createCategory(request = request)
}

override suspend fun fetchCategories(agencyId: Long): Result<CategoryReadResponse> {
return agencyApi.fetchCategories(agencyId = agencyId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.moneymong.moneymong.model.agency.AgencyJoinResponse
import com.moneymong.moneymong.model.agency.AgencyRegisterRequest
import com.moneymong.moneymong.model.agency.CategoryCreateRequest
import com.moneymong.moneymong.model.agency.CategoryCreateResponse
import com.moneymong.moneymong.model.agency.CategoryReadResponse
import com.moneymong.moneymong.model.agency.MyAgencyResponse
import com.moneymong.moneymong.model.agency.RegisterAgencyResponse
import kotlinx.coroutines.delay
Expand Down Expand Up @@ -42,6 +43,10 @@ class AgencyRemoteDataSourceMock : AgencyRemoteDataSource {
return Result.success(CategoryCreateResponse(agencyId = 1L, name = "category"))
}

override suspend fun fetchCategories(agencyId: Long): Result<CategoryReadResponse> {
return Result.success(CategoryReadResponse(agencyId = agencyId, categories = emptyList()))
}

private companion object {
val agenciesMockOfSuccess = listOf(
Result.success(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.moneymong.moneymong.model.agency.AgencyJoinResponse
import com.moneymong.moneymong.model.agency.AgencyRegisterRequest
import com.moneymong.moneymong.model.agency.CategoryCreateRequest
import com.moneymong.moneymong.model.agency.CategoryCreateResponse
import com.moneymong.moneymong.model.agency.CategoryReadResponse
import com.moneymong.moneymong.model.agency.MyAgencyResponse
import com.moneymong.moneymong.model.agency.RegisterAgencyResponse
import kotlinx.coroutines.flow.Flow
Expand Down Expand Up @@ -54,4 +55,7 @@ class AgencyRepositoryImpl @Inject constructor(

override suspend fun createCategory(request: CategoryCreateRequest): Result<CategoryCreateResponse> =
agencyRemoteDataSource.createCategory(request = request)

override suspend fun fetchCategories(agencyId: Long): Result<CategoryReadResponse> =
agencyRemoteDataSource.fetchCategories(agencyId = agencyId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.moneymong.moneymong.model.agency.AgencyJoinResponse
import com.moneymong.moneymong.model.agency.AgencyRegisterRequest
import com.moneymong.moneymong.model.agency.CategoryCreateRequest
import com.moneymong.moneymong.model.agency.CategoryCreateResponse
import com.moneymong.moneymong.model.agency.CategoryReadResponse
import com.moneymong.moneymong.model.agency.MyAgencyResponse
import com.moneymong.moneymong.model.agency.RegisterAgencyResponse
import kotlinx.coroutines.flow.Flow
Expand All @@ -21,4 +22,5 @@ interface AgencyRepository {
suspend fun saveAgencyId(agencyId: Int)
suspend fun fetchAgencyId(): Int
suspend fun createCategory(request: CategoryCreateRequest): Result<CategoryCreateResponse>
suspend fun fetchCategories(agencyId: Long): Result<CategoryReadResponse>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.moneymong.moneymong.domain.usecase.agency

import com.moneymong.moneymong.domain.repository.agency.AgencyRepository
import com.moneymong.moneymong.model.agency.CategoryReadResponse
import javax.inject.Inject

class FetchCategoriesUseCase @Inject constructor(
private val agencyRepository: AgencyRepository
) {
suspend operator fun invoke(agencyId: Long): Result<CategoryReadResponse> =
agencyRepository.fetchCategories(agencyId = agencyId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -89,7 +88,8 @@ import kotlinx.coroutines.launch
import org.orbitmvi.orbit.compose.collectAsState
import org.orbitmvi.orbit.compose.collectSideEffect

@OptIn(ExperimentalGlideComposeApi::class, ExperimentalMaterial3Api::class,
@OptIn(
ExperimentalGlideComposeApi::class, ExperimentalMaterial3Api::class,
ExperimentalLayoutApi::class
)
@Composable
Expand Down Expand Up @@ -191,7 +191,10 @@ fun LedgerManualScreen(
onDismissRequest = {
scope.launch {
sheetState.hide()
}.invokeOnCompletion { viewModel.onDismissBottomSheet() }
}.invokeOnCompletion {
viewModel.onDismissBottomSheet()
viewModel.onChangeCategoryValue(TextFieldValue())
}
},
onChangeCategoryValue = viewModel::onChangeCategoryValue,
onCategoryCreate = viewModel::createCategory,
Expand Down Expand Up @@ -360,13 +363,17 @@ fun LedgerManualScreen(
}
Spacer(modifier = Modifier.height(8.dp))
FlowRow(
horizontalArrangement = Arrangement.spacedBy(10.dp)
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalArrangement = Arrangement.spacedBy(10.dp),
) {
MDSOutlineTag(
text = "Test", // TODO
iconResource = drawable.ic_close_default,
onClick = {},
)
state.categories.forEach { category ->
val isSelected = category == state.selectedCategory
MDSOutlineTag(
text = category.name,
selected = isSelected,
onClick = { viewModel.onClickCategory(category) },
)
}
}
Spacer(modifier = Modifier.height(24.dp))
Text(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ data class LedgerManualState(
val errorMessage: String = "",
val showBottomSheet: Boolean = false,
val categoryValue: TextFieldValue = TextFieldValue(),
val categories: List<CategoryResponse>? = null,
val categories: List<CategoryResponse> = emptyList(),
val selectedCategory: CategoryResponse? = null
) : State {

val enabled: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import com.moneymong.moneymong.ui.isValidPaymentDate
import com.moneymong.moneymong.ui.isValidPaymentTime
import com.moneymong.moneymong.ui.validateValue
import com.moneymong.moneymong.domain.usecase.agency.FetchAgencyIdUseCase
import com.moneymong.moneymong.domain.usecase.agency.FetchCategoriesUseCase
import com.moneymong.moneymong.domain.usecase.ledger.PostLedgerTransactionUseCase
import com.moneymong.moneymong.domain.usecase.ocr.PostFileUploadUseCase
import com.moneymong.moneymong.domain.usecase.user.FetchUserNicknameUseCase
import com.moneymong.moneymong.model.agency.CategoryCreateRequest
import com.moneymong.moneymong.model.agency.CategoryResponse
import com.moneymong.moneymong.model.ledger.FundType
import com.moneymong.moneymong.model.ledger.LedgerTransactionRequest
import com.moneymong.moneymong.model.ocr.FileUploadRequest
Expand All @@ -32,10 +34,12 @@ class LedgerManualViewModel @Inject constructor(
private val fetchAgencyIdUseCase: FetchAgencyIdUseCase,
private val fetchUserNicknameUseCase: FetchUserNicknameUseCase,
private val createCategoryUseCase: CreateCategoryUseCase,
private val fetchCategoriesUseCase: FetchCategoriesUseCase,
) : BaseViewModel<LedgerManualState, LedgerManualSideEffect>(LedgerManualState()) {

init {
fetchUserInfo()
fetchCategories()
}

@OptIn(OrbitExperimental::class)
Expand Down Expand Up @@ -98,23 +102,31 @@ class LedgerManualViewModel @Inject constructor(

fun createCategory() = intent {
val request =
CategoryCreateRequest(agencyId = state.agencyId.toLong(), name = state.categoryValue.text)
CategoryCreateRequest(
agencyId = state.agencyId.toLong(),
name = state.categoryValue.text
)

createCategoryUseCase(request)
.onSuccess {
reduce {
state.copy(
showBottomSheet = false,
categoryValue = TextFieldValue(),
)
}
fetchCategories()
reduce { state.copy(showBottomSheet = false) }
}.onFailure {
reduce {
state.copy(
showErrorDialog = true,
errorMessage = it.message ?: MoneyMongError.UnExpectedError.message
)
}
}.also { onChangeCategoryValue(TextFieldValue()) }
}

fun fetchCategories() = intent {
fetchCategoriesUseCase(agencyId = state.agencyId.toLong())
.onSuccess {
reduce {
state.copy(categories = it.categories)
}
}
}

Expand Down Expand Up @@ -215,6 +227,10 @@ class LedgerManualViewModel @Inject constructor(
}
}

fun onClickCategory(category: CategoryResponse) = intent {
reduce { state.copy(selectedCategory = category) }
}

private fun trimStartWithZero(value: TextFieldValue) =
if (value.text.isNotEmpty() && value.text.all { it == '0' }) {
value.copy(text = "0")
Expand Down
Loading