diff --git a/.gitignore b/.gitignore index e5187b24..056a7926 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Created by https://www.toptal.com/developers/gitignore/api/android,androidstudio,macos,windows,linux,kotlin # Edit at https://www.toptal.com/developers/gitignore?templates=android,androidstudio,macos,windows,linux,kotlin +GEMINI.md + ### Android ### # Gradle files .gradle/ diff --git a/app/src/main/java/com/poti/android/domain/model/history/ParticipantDetail.kt b/app/src/main/java/com/poti/android/domain/model/history/ParticipantDetail.kt index e4bdafa8..7a723da2 100644 --- a/app/src/main/java/com/poti/android/domain/model/history/ParticipantDetail.kt +++ b/app/src/main/java/com/poti/android/domain/model/history/ParticipantDetail.kt @@ -4,10 +4,12 @@ import com.poti.android.domain.type.ParticipantStatusType data class ParticipantDetail( val participationId: Long, + val partyId: Long, + val orderNumber: String, val partySummary: PartySummary, val memberPayments: List, val paymentInfo: PaymentInfo, - val shippingInfo: ShippingInfo, + val shippingInfo: ParticipantShippingInfo, ) data class MemberPayment( @@ -19,7 +21,18 @@ data class PaymentInfo( val shippingFee: Int, val totalAmount: Int, val depositStatus: ParticipantStatusType, - val bank: String, - val accountNumber: String, - val depositDeadline: String, + val bank: String?, + val accountNumber: String?, + val depositDeadline: String?, +) + +data class ParticipantShippingInfo( + val shippingMethod: String, + val receiver: String, + val zipcode: String, + val address: String, + val phone: String, + val carrier: String?, + val trackingNumber: String?, + val shippingStatus: ParticipantStatusType, ) diff --git a/app/src/main/java/com/poti/android/presentation/history/component/DepositInfoSection.kt b/app/src/main/java/com/poti/android/presentation/history/component/DepositInfoSection.kt deleted file mode 100644 index 7a0ed410..00000000 --- a/app/src/main/java/com/poti/android/presentation/history/component/DepositInfoSection.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.poti.android.presentation.history.component - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.poti.android.R -import com.poti.android.core.common.util.screenWidthDp -import com.poti.android.core.designsystem.component.display.PotiItemOptionType -import com.poti.android.core.designsystem.theme.PotiTheme -import com.poti.android.presentation.history.participant.model.DepositInfoUiModel -import com.poti.android.presentation.history.participant.model.DepositItemUiModel - -@Composable -fun DepositInfoSection( - info: DepositInfoUiModel, - modifier: Modifier = Modifier, -) { - Column( - modifier = modifier - .fillMaxWidth() - .padding(horizontal = screenWidthDp(16.dp)), - ) { - Text( - text = stringResource(id = R.string.history_deposit_info_title), - style = PotiTheme.typography.body16sb, - color = PotiTheme.colors.black, - modifier = Modifier.padding(bottom = 20.dp), - ) - - PriceDetail(items = info.items, totalAmount = info.totalAmount) - - if (info.accountNumber != null && info.dueDate != null) { - HistoryCalloutInfo( - text = info.accountNumber, - copyable = true, - modifier = Modifier.padding(top = 28.dp, bottom = 8.dp), - ) - - HistoryCalloutInfo( - text = info.dueDate, - copyable = false, - modifier = Modifier.padding(bottom = 28.dp), - ) - - HistoryStateLabel( - sizeType = StateLabelSize.LARGE, - stageType = info.stage, - statusType = info.status, - modifier = Modifier.align(Alignment.End), - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun DepositInfoSectionPreview() { - PotiTheme { - DepositInfoSection( - info = DepositInfoUiModel( - items = listOf( - DepositItemUiModel( - name = "해린 포토카드", - price = 15000, - type = PotiItemOptionType.MEMBER, - ), - DepositItemUiModel( - name = "GS25 반값택배", - price = 1800, - type = PotiItemOptionType.DELIVERY, - ), - ), - totalAmount = 16800, - accountNumber = "카카오뱅크 3333-01-1234567", - dueDate = "2024.12.31 23:59까지", - stage = StateLabelStage.DEPOSIT, - status = StateLabelStatus.WAIT, - ), - ) - } -} diff --git a/app/src/main/java/com/poti/android/presentation/history/recruiter/component/ParticipantManagementHeader.kt b/app/src/main/java/com/poti/android/presentation/history/component/HistoryDetailContentHeader.kt similarity index 53% rename from app/src/main/java/com/poti/android/presentation/history/recruiter/component/ParticipantManagementHeader.kt rename to app/src/main/java/com/poti/android/presentation/history/component/HistoryDetailContentHeader.kt index 9e165247..cbfcf639 100644 --- a/app/src/main/java/com/poti/android/presentation/history/recruiter/component/ParticipantManagementHeader.kt +++ b/app/src/main/java/com/poti/android/presentation/history/component/HistoryDetailContentHeader.kt @@ -1,4 +1,4 @@ -package com.poti.android.presentation.history.recruiter.component +package com.poti.android.presentation.history.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -11,7 +11,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.poti.android.R @@ -20,10 +19,10 @@ import com.poti.android.core.common.util.screenWidthDp import com.poti.android.core.designsystem.theme.PotiTheme @Composable -fun ParticipantManagementHeader( - participantCount: Int, - onHeaderClick: () -> Unit, +fun HistoryDetailContentHeader( + text: String, modifier: Modifier = Modifier, + onHeaderClick: (() -> Unit)? = null, ) { Row( modifier = modifier @@ -31,26 +30,28 @@ fun ParticipantManagementHeader( .padding( start = screenWidthDp(16.dp), end = screenWidthDp(4.dp), - ) - .padding(vertical = 8.dp), + ), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, ) { Text( - text = stringResource(id = R.string.history_recruiter_participant_management_title, participantCount), + text = text, style = PotiTheme.typography.body16sb, color = PotiTheme.colors.black, + modifier = Modifier.padding(vertical = 20.dp), ) - Icon( - painter = painterResource(id = R.drawable.ic_arrow_right_lg), - contentDescription = null, - tint = PotiTheme.colors.gray700, - modifier = Modifier - .padding(10.dp) - .size(24.dp) - .noRippleClickable(onHeaderClick), - ) + onHeaderClick?.let { + Icon( + painter = painterResource(id = R.drawable.ic_arrow_right_lg), + contentDescription = null, + tint = PotiTheme.colors.gray700, + modifier = Modifier + .padding(10.dp) + .size(24.dp) + .noRippleClickable(onHeaderClick), + ) + } } } @@ -58,30 +59,8 @@ fun ParticipantManagementHeader( @Composable private fun ParticipantManagementHeaderEmptyPreview() { PotiTheme { - ParticipantManagementHeader( - participantCount = 0, - onHeaderClick = {}, - ) - } -} - -@Preview(showBackground = true, name = "Participants 5") -@Composable -private fun ParticipantManagementHeaderMultiPreview() { - PotiTheme { - ParticipantManagementHeader( - participantCount = 5, - onHeaderClick = {}, - ) - } -} - -@Preview(showBackground = true, name = "Participants 99+") -@Composable -private fun ParticipantManagementHeaderManyPreview() { - PotiTheme { - ParticipantManagementHeader( - participantCount = 100, + HistoryDetailContentHeader( + text = "입금 정보", onHeaderClick = {}, ) } diff --git a/app/src/main/java/com/poti/android/presentation/history/component/HistoryStateLabel.kt b/app/src/main/java/com/poti/android/presentation/history/component/HistoryStateLabel.kt deleted file mode 100644 index 7ae111e6..00000000 --- a/app/src/main/java/com/poti/android/presentation/history/component/HistoryStateLabel.kt +++ /dev/null @@ -1,155 +0,0 @@ -package com.poti.android.presentation.history.component - -import androidx.annotation.StringRes -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.poti.android.R -import com.poti.android.core.designsystem.theme.PotiTheme -import com.poti.android.core.designsystem.theme.PotiTheme.colors - -enum class StateLabelSize { - LARGE, - SMALL, -} - -enum class StateLabelStage( - @StringRes val text: Int, -) { - DEPOSIT(R.string.history_participant_stage_deposit), - DELIVERY(R.string.history_participant_stage_delivery), - RECRUIT(R.string.history_participant_stage_recruit), -} - -enum class StateLabelStatus( - @StringRes val text: Int, -) { - WAIT(R.string.history_participant_stage_wait), - ING(R.string.history_participant_stage_ing), - CHECK(R.string.history_participant_stage_check), - START(R.string.history_participant_stage_start), - DONE(R.string.history_participant_stage_done), -} - -@Composable -fun HistoryStateLabel( - sizeType: StateLabelSize, - stageType: StateLabelStage, - statusType: StateLabelStatus, - modifier: Modifier = Modifier, -) { - val (text, style, color) = - getTextInfo(sizeType, stageType, statusType) - - Text( - text = text, - style = style, - color = color, - modifier = modifier, - ) -} - -@Composable -private fun getTextInfo( - sizeType: StateLabelSize, - stageType: StateLabelStage, - statusType: StateLabelStatus, -): Triple { - val text = stringResource( - id = R.string.history_participant_stage_and_status_format, - stringResource(stageType.text), - stringResource(statusType.text), - ) - - val style = when (sizeType) { - StateLabelSize.LARGE -> PotiTheme.typography.body16sb - StateLabelSize.SMALL -> PotiTheme.typography.body14sb - } - - val color = getStateColor(stageType, statusType, sizeType) - - return Triple(text, style, color) -} - -@Composable -private fun getStateColor( - stage: StateLabelStage, - status: StateLabelStatus, - size: StateLabelSize, -): Color { - val isLarge = size == StateLabelSize.LARGE - val defaultColor = colors.gray700 - - return when (stage to status) { - // DEPOSIT 단계 - StateLabelStage.DEPOSIT to StateLabelStatus.WAIT -> - if (isLarge) colors.sementicRed else defaultColor - - StateLabelStage.DEPOSIT to StateLabelStatus.CHECK -> - if (isLarge) colors.poti600 else colors.sementicRed - - StateLabelStage.DEPOSIT to StateLabelStatus.DONE -> - if (isLarge) defaultColor else colors.poti600 - - // DELIVERY 단계 - StateLabelStage.DELIVERY to StateLabelStatus.WAIT -> - if (isLarge) colors.sementicRed else defaultColor - - StateLabelStage.DELIVERY to StateLabelStatus.START -> colors.poti600 - StateLabelStage.DELIVERY to StateLabelStatus.DONE -> defaultColor - - // RECRUIT 단계 - StateLabelStage.RECRUIT to StateLabelStatus.ING -> colors.sementicRed - StateLabelStage.RECRUIT to StateLabelStatus.DONE -> colors.poti600 - - else -> defaultColor - } -} - -@Preview(showBackground = true) -@Composable -private fun HistoryStateLabelPreview() { - PotiTheme { - Column( - verticalArrangement = Arrangement.spacedBy(10.dp), - ) { - HistoryStateLabel( - sizeType = StateLabelSize.SMALL, - stageType = StateLabelStage.DEPOSIT, - statusType = StateLabelStatus.WAIT, - ) - HistoryStateLabel( - sizeType = StateLabelSize.SMALL, - stageType = StateLabelStage.DEPOSIT, - statusType = StateLabelStatus.CHECK, - ) - HistoryStateLabel( - sizeType = StateLabelSize.LARGE, - stageType = StateLabelStage.DEPOSIT, - statusType = StateLabelStatus.CHECK, - ) - HistoryStateLabel( - sizeType = StateLabelSize.LARGE, - stageType = StateLabelStage.DEPOSIT, - statusType = StateLabelStatus.WAIT, - ) - HistoryStateLabel( - sizeType = StateLabelSize.LARGE, - stageType = StateLabelStage.DELIVERY, - statusType = StateLabelStatus.WAIT, - ) - HistoryStateLabel( - sizeType = StateLabelSize.LARGE, - stageType = StateLabelStage.RECRUIT, - statusType = StateLabelStatus.ING, - ) - } - } -} diff --git a/app/src/main/java/com/poti/android/presentation/history/component/PriceDetail.kt b/app/src/main/java/com/poti/android/presentation/history/component/PriceDetail.kt deleted file mode 100644 index ec47f286..00000000 --- a/app/src/main/java/com/poti/android/presentation/history/component/PriceDetail.kt +++ /dev/null @@ -1,91 +0,0 @@ -package com.poti.android.presentation.history.component - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.poti.android.R -import com.poti.android.core.common.extension.toMoneyString -import com.poti.android.core.designsystem.component.display.PotiDivider -import com.poti.android.core.designsystem.component.display.PotiDividerStyle -import com.poti.android.core.designsystem.component.display.PotiItemOptionType -import com.poti.android.core.designsystem.component.display.PotiListOptionPrice -import com.poti.android.core.designsystem.component.display.PotiListOptionPriceSize -import com.poti.android.core.designsystem.theme.PotiTheme -import com.poti.android.presentation.history.participant.model.DepositItemUiModel - -@Composable -fun PriceDetail( - items: List, - totalAmount: Int, - modifier: Modifier = Modifier, -) { - Column( - modifier = modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - items.forEach { item -> - PotiListOptionPrice( - itemOptionType = item.type, - itemOptionText = item.name, - priceText = stringResource( - R.string.history_participant_detail_won_unit_format, - item.price.toMoneyString(), - ), - sizeType = PotiListOptionPriceSize.SMALL, - ) - } - - PotiDivider(styleType = PotiDividerStyle.SMALL) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = stringResource(id = R.string.history_total_deposit_amount), - style = PotiTheme.typography.body14m, - color = PotiTheme.colors.gray800, - ) - - Text( - text = stringResource( - R.string.history_participant_detail_won_unit_format, - totalAmount.toMoneyString(), - ), - style = PotiTheme.typography.body16sb, - color = PotiTheme.colors.black, - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun PriceDetailPreview() { - PotiTheme { - PriceDetail( - items = listOf( - DepositItemUiModel( - name = "해린 포토카드", - price = 15000, - type = PotiItemOptionType.MEMBER, - ), - DepositItemUiModel( - name = "GS25 반값택배", - price = 1800, - type = PotiItemOptionType.DELIVERY, - ), - ), - totalAmount = 16800, - ) - } -} diff --git a/app/src/main/java/com/poti/android/presentation/history/model/CommonUiModel.kt b/app/src/main/java/com/poti/android/presentation/history/model/CommonUiModel.kt deleted file mode 100644 index 9ac15db0..00000000 --- a/app/src/main/java/com/poti/android/presentation/history/model/CommonUiModel.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.poti.android.presentation.history.model - -import com.poti.android.presentation.history.component.StateLabelStage -import com.poti.android.presentation.history.component.StateLabelStatus - -data class PartySummaryUiModel( - val imageUrl: String, - val artist: String, - val title: String, - val partyStage: StateLabelStage, - val partyStatus: StateLabelStatus, -) - -data class ProgressUiModel( - val guideText: String, - val step: Int, -) diff --git a/app/src/main/java/com/poti/android/presentation/history/navigation/HistoryNavigation.kt b/app/src/main/java/com/poti/android/presentation/history/navigation/HistoryNavigation.kt index 8ef5bf26..63b2e2ea 100644 --- a/app/src/main/java/com/poti/android/presentation/history/navigation/HistoryNavigation.kt +++ b/app/src/main/java/com/poti/android/presentation/history/navigation/HistoryNavigation.kt @@ -70,7 +70,11 @@ fun NavGraphBuilder.historyNavGraph( ) } composable { - ParticipantDetailRoute(modifier = Modifier.padding(paddingValues)) + ParticipantDetailRoute( + onPopBackStack = navController::popBackStack, + onNavigateToPartyDetail = navController::navigateToPartyDetail, + modifier = Modifier.padding(paddingValues), + ) } composable { RecruiterDetailRoute( diff --git a/app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt b/app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt index 98ca5dac..26893aff 100644 --- a/app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt +++ b/app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt @@ -1,13 +1,195 @@ package com.poti.android.presentation.history.participant +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.poti.android.R +import com.poti.android.core.common.extension.onSuccess +import com.poti.android.core.common.util.HandleSideEffects +import com.poti.android.core.common.util.screenWidthDp +import com.poti.android.core.designsystem.component.button.ActionButtonType +import com.poti.android.core.designsystem.component.button.PotiActionButton +import com.poti.android.core.designsystem.component.display.PotiDivider +import com.poti.android.core.designsystem.component.display.PotiDividerStyle +import com.poti.android.core.designsystem.component.navigation.PotiHeaderPage +import com.poti.android.presentation.history.component.HistoryDetailContentHeader +import com.poti.android.presentation.history.component.PartyInfoSection +import com.poti.android.presentation.history.component.ProgressStatusSection +import com.poti.android.presentation.history.participant.component.DeliveryStatusContent +import com.poti.android.presentation.history.participant.component.DepositStatusContent +import com.poti.android.presentation.history.participant.component.HistoryDeliveryConfirmModal +import com.poti.android.presentation.history.participant.component.HistoryDeliveryReviewModal +import com.poti.android.presentation.history.participant.component.HistoryDepositBottomSheet +import com.poti.android.presentation.history.participant.model.ParticipantButtonState +import com.poti.android.presentation.history.participant.model.ParticipantDetailOverlayState +import com.poti.android.presentation.history.participant.model.ParticipantDetailUiEffect +import com.poti.android.presentation.history.participant.model.ParticipantDetailUiIntent +import com.poti.android.presentation.history.participant.model.ParticipantDetailUiModel @Composable -fun ParticipantDetailRoute(modifier: Modifier = Modifier) { - ParticipantDetailScreen(modifier = modifier) +fun ParticipantDetailRoute( + onPopBackStack: () -> Unit, + onNavigateToPartyDetail: (Long) -> Unit, + modifier: Modifier = Modifier, + viewModel: ParticipantViewModel = hiltViewModel(), +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + HandleSideEffects(viewModel.sideEffect) { effect -> + when (effect) { + ParticipantDetailUiEffect.NavigateBack -> onPopBackStack() + is ParticipantDetailUiEffect.NavigateToPartyDetail -> onNavigateToPartyDetail(effect.partyId) + } + } + + uiState.participantDetailState.onSuccess { participantDetail -> + ParticipantDetailScreen( + participantDetail = participantDetail, + overlayState = uiState.overlayState, + onBackClick = onPopBackStack, + onDetailClick = { + viewModel.processIntent(ParticipantDetailUiIntent.OnPartyDetailClick(participantDetail.partyId)) + }, + onActionButtonClick = { buttonState -> + if (buttonState == ParticipantButtonState.DEPOSIT_DONE) { + viewModel.processIntent(ParticipantDetailUiIntent.OnDepositCompleteClick) + } else { + viewModel.processIntent(ParticipantDetailUiIntent.OnDeliveredClick) + } + }, + onOverlayClose = { viewModel.processIntent(ParticipantDetailUiIntent.CloseOverlay) }, + onSubmitDeposit = { depositor, depositTime -> + viewModel.processIntent(ParticipantDetailUiIntent.SubmitDeposit(depositor, depositTime)) + }, + onConfirmDelivery = { viewModel.processIntent(ParticipantDetailUiIntent.ConfirmDelivery) }, + onSubmitReview = { rating -> viewModel.processIntent(ParticipantDetailUiIntent.SubmitReview(rating)) }, + onSkipReview = { viewModel.processIntent(ParticipantDetailUiIntent.SkipReview) }, + modifier = modifier, + ) + } } @Composable -private fun ParticipantDetailScreen(modifier: Modifier = Modifier) { +private fun ParticipantDetailScreen( + participantDetail: ParticipantDetailUiModel, + overlayState: ParticipantDetailOverlayState, + onBackClick: () -> Unit, + onDetailClick: () -> Unit, + onActionButtonClick: (ParticipantButtonState) -> Unit, + onOverlayClose: () -> Unit, + onSubmitDeposit: (String, String) -> Unit, + onConfirmDelivery: () -> Unit, + onSubmitReview: (Int) -> Unit, + onSkipReview: () -> Unit, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier.fillMaxSize()) { + PotiHeaderPage( + onNavigationClick = onBackClick, + title = stringResource(id = R.string.history_ongoing_title), + ) + + Column( + modifier = Modifier + .weight(1f) + .verticalScroll(rememberScrollState()) + .padding(bottom = 50.dp), + ) { + PartyInfoSection( + orderNumber = participantDetail.orderNumber, + partySummary = participantDetail.partySummary, + onDetailClick = onDetailClick, + modifier = Modifier.padding(horizontal = screenWidthDp(8.dp)), + ) + + ProgressStatusSection( + progressStatus = participantDetail.partySummary.partyStatus, + statusMessage = participantDetail.partySummary.statusMessage, + modifier = Modifier.padding(horizontal = screenWidthDp(16.dp)), + ) + + PotiDivider( + styleType = PotiDividerStyle.LARGE, + modifier = Modifier.padding(top = 24.dp), + ) + + HistoryDetailContentHeader(text = stringResource(R.string.history_participant_field_type_deposit)) + + DepositStatusContent( + memberPayments = participantDetail.memberPayments, + shippingInfo = participantDetail.shippingInfo, + paymentInfo = participantDetail.paymentInfo, + participantStatusType = participantDetail.paymentInfo.depositStatus, + ) + + PotiDivider(PotiDividerStyle.LARGE) + + HistoryDetailContentHeader(text = stringResource(R.string.history_shipping_info_title)) + + DeliveryStatusContent( + shippingInfo = participantDetail.shippingInfo, + participantStatusType = participantDetail.shippingInfo.shippingStatus, + ) + } + + when (participantDetail.buttonState) { + ParticipantButtonState.DEPOSIT_DONE -> { + PotiActionButton( + text = stringResource(R.string.history_deposit_done_button), + onClick = { onActionButtonClick(ParticipantButtonState.DEPOSIT_DONE) }, + type = ActionButtonType.SECONDARY_MAIN, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = screenWidthDp(16.dp), vertical = 4.dp), + ) + } + ParticipantButtonState.DELIVERY_RECEIVED -> { + PotiActionButton( + text = stringResource(R.string.history_delivery_done_button), + onClick = { onActionButtonClick(ParticipantButtonState.DELIVERY_RECEIVED) }, + type = ActionButtonType.SECONDARY_MAIN, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = screenWidthDp(16.dp), vertical = 4.dp), + ) + } + ParticipantButtonState.NONE -> {} + } + } + + when (overlayState) { + ParticipantDetailOverlayState.DepositBottomSheet -> { + HistoryDepositBottomSheet( + onDismissRequest = onOverlayClose, + onConfirmClick = onSubmitDeposit, + ) + } + ParticipantDetailOverlayState.DeliveryConfirmModal -> { + HistoryDeliveryConfirmModal( + onConfirm = onConfirmDelivery, + onDismiss = onOverlayClose, + ) + } + is ParticipantDetailOverlayState.DeliveryReviewModal -> { + HistoryDeliveryReviewModal( + recruiterName = overlayState.recruiterName, + recruiterProfileUrl = overlayState.recruiterProfileUrl, + partnerRating = overlayState.partnerRating, + onConfirm = onSubmitReview, + onSkip = onSkipReview, + onDismissRequest = onOverlayClose, + ) + } + ParticipantDetailOverlayState.None -> {} + } } diff --git a/app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt b/app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt index e36f5e5b..c95976ea 100644 --- a/app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt +++ b/app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt @@ -1,9 +1,134 @@ package com.poti.android.presentation.history.participant -import androidx.lifecycle.ViewModel +import androidx.lifecycle.SavedStateHandle +import androidx.navigation.toRoute +import com.poti.android.core.base.BaseViewModel +import com.poti.android.core.common.state.ApiState +import com.poti.android.domain.model.history.MemberPayment +import com.poti.android.domain.model.history.PartySummary +import com.poti.android.domain.type.ParticipantStatusType +import com.poti.android.domain.type.PartyStatusType +import com.poti.android.presentation.history.navigation.HistoryRoute +import com.poti.android.presentation.history.participant.model.ParticipantButtonState +import com.poti.android.presentation.history.participant.model.ParticipantDetailOverlayState +import com.poti.android.presentation.history.participant.model.ParticipantDetailUiEffect +import com.poti.android.presentation.history.participant.model.ParticipantDetailUiIntent +import com.poti.android.presentation.history.participant.model.ParticipantDetailUiModel +import com.poti.android.presentation.history.participant.model.ParticipantDetailUiState +import com.poti.android.presentation.history.participant.model.ParticipantShippingUiModel +import com.poti.android.presentation.history.participant.model.PaymentInfoUiModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel -class ParticipantViewModel @Inject constructor() : ViewModel() { +class ParticipantViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, +) : BaseViewModel( + initialState = ParticipantDetailUiState(), + ) { + private val participantId: Long = savedStateHandle.toRoute().participantId + + init { + getParticipantDetail(participantId) + } + + override fun processIntent(intent: ParticipantDetailUiIntent) { + when (intent) { + is ParticipantDetailUiIntent.LoadDetail -> getParticipantDetail(intent.recruitId) + ParticipantDetailUiIntent.OnBackClick -> sendEffect(ParticipantDetailUiEffect.NavigateBack) + is ParticipantDetailUiIntent.OnPartyDetailClick -> + sendEffect(ParticipantDetailUiEffect.NavigateToPartyDetail(intent.partyId)) + + ParticipantDetailUiIntent.OnDepositCompleteClick -> { + updateState { copy(overlayState = ParticipantDetailOverlayState.DepositBottomSheet) } + } + + ParticipantDetailUiIntent.CloseOverlay -> { + updateState { copy(overlayState = ParticipantDetailOverlayState.None) } + } + + is ParticipantDetailUiIntent.SubmitDeposit -> patchSubmitDeposit(intent.depositor, intent.depositTime) + + ParticipantDetailUiIntent.OnDeliveredClick -> { + updateState { copy(overlayState = ParticipantDetailOverlayState.DeliveryConfirmModal) } + } + + ParticipantDetailUiIntent.ConfirmDelivery -> { + // TODO: 배송 수령 확인 API 호출 및 주최자 정보 획득 + // 성공 시 리뷰 모달로 전환하며 데이터 전달 + updateState { + copy( + overlayState = ParticipantDetailOverlayState.DeliveryReviewModal( + recruiterName = "장원영", // 더미 데이터 + recruiterProfileUrl = "", // 더미 데이터 + partnerRating = "4.5", // 더미 데이터 + ), + ) + } + } + + ParticipantDetailUiIntent.SkipReview -> { + // TODO: 리뷰 건너뛰기 처리 (필요시 API 호출) + updateState { copy(overlayState = ParticipantDetailOverlayState.None) } + } + + is ParticipantDetailUiIntent.SubmitReview -> { + // TODO: 리뷰 제출 API 호출 + updateState { copy(overlayState = ParticipantDetailOverlayState.None) } + } + } + } + + private fun getParticipantDetail(participantId: Long) = launchScope { + updateState { + copy( + participantDetailState = ApiState.Success( + ParticipantDetailUiModel( + participationId = 1, + partyId = 1, + orderNumber = "참여번호 poti-1", + partySummary = PartySummary( + imageUrl = "", + artist = "아이브(아이브)", + title = "러브다이브 위드뮤", + partyStatus = PartyStatusType.CLOSED, + statusMessage = "다른 참여자를 기다리고 있어요", + ), + memberPayments = listOf( + MemberPayment( + memberName = "멤버1", + price = 9000, + ), + ), + paymentInfo = PaymentInfoUiModel( + shippingFee = 9000, + totalAmount = 18000, + depositStatus = ParticipantStatusType.DELIVERED, + accountInfo = "카카오뱅크 3333-19-1234123 이포티", + depositDeadline = "2026-01-01 23:50 까지", + ), + shippingInfo = ParticipantShippingUiModel( + shippingMethod = "일반택", + deliveryTrackingInfo = "우체국 20203344656423232", + receiver = "이포티", + addressInfo = "이포티\n(01234) 서울특별시 솝트구 다솝로 456\n010-1234-5678", + carrier = null, + trackingNumber = null, + shippingStatus = ParticipantStatusType.DELIVERED, + ), + buttonState = ParticipantButtonState.DELIVERY_RECEIVED, + ), + ), + ) + } + } + + private fun patchSubmitDeposit( + depositor: String, + depositTime: String, + ) = launchScope { + // TODO: 입금 확인 요청 API 호출 + // 성공 시 overlayState = None 및 데이터 갱신 + updateState { copy(overlayState = ParticipantDetailOverlayState.None) } + } } diff --git a/app/src/main/java/com/poti/android/presentation/history/participant/component/DeliveryStatusContent.kt b/app/src/main/java/com/poti/android/presentation/history/participant/component/DeliveryStatusContent.kt new file mode 100644 index 00000000..6a555c6e --- /dev/null +++ b/app/src/main/java/com/poti/android/presentation/history/participant/component/DeliveryStatusContent.kt @@ -0,0 +1,75 @@ +package com.poti.android.presentation.history.participant.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.poti.android.R +import com.poti.android.core.common.util.screenWidthDp +import com.poti.android.core.designsystem.component.display.PotiItemOption +import com.poti.android.core.designsystem.component.display.PotiItemOptionSize +import com.poti.android.core.designsystem.component.display.PotiItemOptionType +import com.poti.android.core.designsystem.theme.PotiTheme +import com.poti.android.domain.type.ParticipantStatusType +import com.poti.android.presentation.history.mapper.color +import com.poti.android.presentation.history.mapper.labelResId +import com.poti.android.presentation.history.mapper.statusColor +import com.poti.android.presentation.history.participant.model.ParticipantShippingUiModel + +@Composable +fun DeliveryStatusContent( + shippingInfo: ParticipantShippingUiModel, + participantStatusType: ParticipantStatusType, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .fillMaxWidth() + .padding(horizontal = screenWidthDp(16.dp)) + .padding(bottom = 24.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + Text( + text = shippingInfo.addressInfo, + style = PotiTheme.typography.body14m, + color = PotiTheme.colors.black, + ) + + PotiItemOption( + optionType = PotiItemOptionType.DELIVERY, + sizeType = PotiItemOptionSize.SMALL, + text = stringResource(R.string.history_delivery_method), + ) + + when (participantStatusType) { + ParticipantStatusType.READY, ParticipantStatusType.DELIVERED -> { + Text( + text = stringResource(participantStatusType.labelResId), + color = participantStatusType.statusColor.color, + style = PotiTheme.typography.body16sb, + modifier = Modifier.align(Alignment.End), + ) + } + ParticipantStatusType.SHIPPED -> { + HistoryCalloutInfo( + text = shippingInfo.deliveryTrackingInfo, + copyable = true, + modifier = Modifier.padding(top = 8.dp, bottom = 16.dp), + ) + Text( + text = stringResource(participantStatusType.labelResId), + color = participantStatusType.statusColor.color, + style = PotiTheme.typography.body16sb, + modifier = Modifier.align(Alignment.End), + ) + } + else -> {} + } + } +} diff --git a/app/src/main/java/com/poti/android/presentation/history/participant/component/DepositStatusContent.kt b/app/src/main/java/com/poti/android/presentation/history/participant/component/DepositStatusContent.kt new file mode 100644 index 00000000..a759cfed --- /dev/null +++ b/app/src/main/java/com/poti/android/presentation/history/participant/component/DepositStatusContent.kt @@ -0,0 +1,118 @@ +package com.poti.android.presentation.history.participant.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.poti.android.R +import com.poti.android.core.common.extension.toMoneyString +import com.poti.android.core.common.util.screenWidthDp +import com.poti.android.core.designsystem.component.display.PotiDivider +import com.poti.android.core.designsystem.component.display.PotiDividerStyle +import com.poti.android.core.designsystem.component.display.PotiItemOptionType +import com.poti.android.core.designsystem.component.display.PotiListOptionPrice +import com.poti.android.core.designsystem.component.display.PotiListOptionPriceSize +import com.poti.android.core.designsystem.theme.PotiTheme +import com.poti.android.domain.model.history.MemberPayment +import com.poti.android.domain.type.ParticipantStatusType +import com.poti.android.presentation.history.mapper.color +import com.poti.android.presentation.history.mapper.labelResId +import com.poti.android.presentation.history.mapper.statusColor +import com.poti.android.presentation.history.participant.model.ParticipantShippingUiModel +import com.poti.android.presentation.history.participant.model.PaymentInfoUiModel + +@Composable +fun DepositStatusContent( + memberPayments: List, + shippingInfo: ParticipantShippingUiModel, + paymentInfo: PaymentInfoUiModel, + participantStatusType: ParticipantStatusType, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .padding(horizontal = screenWidthDp(16.dp)) + .padding(bottom = 24.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + memberPayments.forEach { member -> + PotiListOptionPrice( + itemOptionType = PotiItemOptionType.MEMBER, + itemOptionText = member.memberName, + priceText = stringResource(R.string.party_option_price_won, member.price.toMoneyString()), + sizeType = PotiListOptionPriceSize.SMALL, + ) + } + + PotiListOptionPrice( + itemOptionType = PotiItemOptionType.DELIVERY, + itemOptionText = shippingInfo.shippingMethod, + priceText = stringResource(R.string.party_option_price_won, paymentInfo.shippingFee.toMoneyString()), + sizeType = PotiListOptionPriceSize.SMALL, + ) + + PotiDivider(PotiDividerStyle.SMALL) + + PotiListOptionPrice( + itemOptionType = PotiItemOptionType.PRICE, + itemOptionText = stringResource(R.string.history_participant_detail_total_deposit_label), + priceText = stringResource(R.string.party_option_price_won, paymentInfo.totalAmount.toMoneyString()), + sizeType = PotiListOptionPriceSize.LARGE, + ) + + when (participantStatusType) { + ParticipantStatusType.RECRUITING -> {} + ParticipantStatusType.WAIT_PAY, ParticipantStatusType.WAIT_PAY_CHECK -> { + DepositInfo( + depositInfo = paymentInfo.accountInfo, + deadline = paymentInfo.depositDeadline, + modifier = Modifier.padding(vertical = 20.dp), + ) + + Text( + text = stringResource(participantStatusType.labelResId), + color = participantStatusType.statusColor.color, + style = PotiTheme.typography.body16sb, + modifier = Modifier.align(Alignment.End), + ) + } + ParticipantStatusType.PAID, ParticipantStatusType.READY, ParticipantStatusType.SHIPPED, ParticipantStatusType.DELIVERED -> { + Text( + text = stringResource(participantStatusType.labelResId), + color = participantStatusType.statusColor.color, + style = PotiTheme.typography.body16sb, + modifier = Modifier + .padding(top = 20.dp) + .align(Alignment.End), + ) + } + } + } +} + +@Composable +fun DepositInfo( + depositInfo: String, + deadline: String?, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier, + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + HistoryCalloutInfo( + text = depositInfo, + copyable = true, + ) + deadline?.let { + HistoryCalloutInfo( + text = deadline, + ) + } + } +} diff --git a/app/src/main/java/com/poti/android/presentation/history/component/HistoryCalloutInfo.kt b/app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryCalloutInfo.kt similarity index 97% rename from app/src/main/java/com/poti/android/presentation/history/component/HistoryCalloutInfo.kt rename to app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryCalloutInfo.kt index 5ac4794c..c55503e1 100644 --- a/app/src/main/java/com/poti/android/presentation/history/component/HistoryCalloutInfo.kt +++ b/app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryCalloutInfo.kt @@ -1,4 +1,4 @@ -package com.poti.android.presentation.history.component +package com.poti.android.presentation.history.participant.component import android.content.ClipData import androidx.compose.foundation.background diff --git a/app/src/main/java/com/poti/android/presentation/history/component/HistoryDeliveryModal.kt b/app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDeliveryModal.kt similarity index 98% rename from app/src/main/java/com/poti/android/presentation/history/component/HistoryDeliveryModal.kt rename to app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDeliveryModal.kt index d8132b35..762ea7cc 100644 --- a/app/src/main/java/com/poti/android/presentation/history/component/HistoryDeliveryModal.kt +++ b/app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDeliveryModal.kt @@ -1,4 +1,4 @@ -package com.poti.android.presentation.history.component +package com.poti.android.presentation.history.participant.component import androidx.compose.foundation.border import androidx.compose.foundation.clickable diff --git a/app/src/main/java/com/poti/android/presentation/history/component/HistoryDepositBottomSheet.kt b/app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDepositBottomSheet.kt similarity index 96% rename from app/src/main/java/com/poti/android/presentation/history/component/HistoryDepositBottomSheet.kt rename to app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDepositBottomSheet.kt index f6e353f1..1ff7e642 100644 --- a/app/src/main/java/com/poti/android/presentation/history/component/HistoryDepositBottomSheet.kt +++ b/app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDepositBottomSheet.kt @@ -1,4 +1,4 @@ -package com.poti.android.presentation.history.component +package com.poti.android.presentation.history.participant.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -47,6 +47,7 @@ fun HistoryDepositBottomSheet( .padding(horizontal = 16.dp), ) }, + enabled = depositor.isNotBlank() && depositTime.isNotBlank(), ) } diff --git a/app/src/main/java/com/poti/android/presentation/history/participant/model/Contract.kt b/app/src/main/java/com/poti/android/presentation/history/participant/model/Contract.kt index f95ae892..ac1fc9eb 100644 --- a/app/src/main/java/com/poti/android/presentation/history/participant/model/Contract.kt +++ b/app/src/main/java/com/poti/android/presentation/history/participant/model/Contract.kt @@ -7,6 +7,7 @@ import com.poti.android.core.common.state.ApiState data class ParticipantDetailUiState( val participantDetailState: ApiState = ApiState.Loading, + val overlayState: ParticipantDetailOverlayState = ParticipantDetailOverlayState.None, ) : UiState sealed interface ParticipantDetailUiIntent : UiIntent { @@ -14,10 +15,16 @@ sealed interface ParticipantDetailUiIntent : UiIntent { data object OnBackClick : ParticipantDetailUiIntent - data object OnPartyDetailClick : ParticipantDetailUiIntent + data class OnPartyDetailClick(val partyId: Long) : ParticipantDetailUiIntent + + data object OnDepositCompleteClick : ParticipantDetailUiIntent + + data object CloseOverlay : ParticipantDetailUiIntent data class SubmitDeposit(val depositor: String, val depositTime: String) : ParticipantDetailUiIntent + data object OnDeliveredClick : ParticipantDetailUiIntent + data object ConfirmDelivery : ParticipantDetailUiIntent data class SubmitReview(val rating: Int) : ParticipantDetailUiIntent @@ -28,5 +35,5 @@ sealed interface ParticipantDetailUiIntent : UiIntent { sealed interface ParticipantDetailUiEffect : UiEffect { data object NavigateBack : ParticipantDetailUiEffect - data class NavigateToPartyDetail(val recruitId: Long) : ParticipantDetailUiEffect + data class NavigateToPartyDetail(val partyId: Long) : ParticipantDetailUiEffect } diff --git a/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantButtonState.kt b/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantButtonState.kt new file mode 100644 index 00000000..b89850e0 --- /dev/null +++ b/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantButtonState.kt @@ -0,0 +1,7 @@ +package com.poti.android.presentation.history.participant.model + +enum class ParticipantButtonState { + DEPOSIT_DONE, + DELIVERY_RECEIVED, + NONE, +} diff --git a/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailOverlayState.kt b/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailOverlayState.kt new file mode 100644 index 00000000..8dc01dc0 --- /dev/null +++ b/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailOverlayState.kt @@ -0,0 +1,15 @@ +package com.poti.android.presentation.history.participant.model + +sealed interface ParticipantDetailOverlayState { + data object None : ParticipantDetailOverlayState + + data object DepositBottomSheet : ParticipantDetailOverlayState + + data object DeliveryConfirmModal : ParticipantDetailOverlayState + + data class DeliveryReviewModal( + val recruiterName: String, + val recruiterProfileUrl: String, + val partnerRating: String, + ) : ParticipantDetailOverlayState +} diff --git a/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt b/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt index e51e78e1..965ac77c 100644 --- a/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt +++ b/app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt @@ -1,78 +1,79 @@ package com.poti.android.presentation.history.participant.model -import androidx.annotation.StringRes -import com.poti.android.core.designsystem.component.display.PotiItemOptionType +import com.poti.android.domain.model.history.MemberPayment +import com.poti.android.domain.model.history.ParticipantDetail +import com.poti.android.domain.model.history.PartySummary import com.poti.android.domain.type.ParticipantStatusType -import com.poti.android.presentation.history.component.StateLabelStage -import com.poti.android.presentation.history.component.StateLabelStatus -import com.poti.android.presentation.history.model.PartySummaryUiModel -import com.poti.android.presentation.history.model.ProgressUiModel +import com.poti.android.domain.type.PartyStatusType data class ParticipantDetailUiModel( - val recruitId: Long, - val userState: ParticipantStatusType, - val partySummaryInfo: PartySummaryUiModel, - val progressInfo: ProgressUiModel, - val depositInfo: DepositInfoUiModel, - val shippingInfo: ShippingInfoUiModel, - val recruiterName: String, - val recruiterProfileUrl: String, - val recruiterRating: String, - @StringRes val topBarTitleResId: Int, - val actionButtonState: ActionButtonState, - val activeModal: ParticipantDetailModalUiModel, - val isTrackingInfoVisible: Boolean, - val isParticipantStatusVisible: Boolean, + val participationId: Long, + val partyId: Long, + val orderNumber: String, + val partySummary: PartySummary, + val memberPayments: List, + val paymentInfo: PaymentInfoUiModel, + val shippingInfo: ParticipantShippingUiModel, + val buttonState: ParticipantButtonState, ) -sealed interface ActionButtonState { - data object Gone : ActionButtonState - - data class Visible( - @StringRes val textResId: Int, - val actionType: ParticipantDetailActionType, - ) : ActionButtonState -} - -enum class ParticipantDetailActionType { - OPEN_DEPOSIT_INPUT, - OPEN_DELIVERY_CONFIRM, -} - -sealed interface ParticipantDetailModalUiModel { - data object None : ParticipantDetailModalUiModel - - data object DepositInput : ParticipantDetailModalUiModel - - data object DeliveryConfirm : ParticipantDetailModalUiModel - - data class DeliveryReview( - val recruiterName: String, - val recruiterProfileUrl: String, - val recruiterRating: String, - ) : ParticipantDetailModalUiModel -} - -data class DepositInfoUiModel( - val items: List, +data class PaymentInfoUiModel( + val shippingFee: Int, val totalAmount: Int, - val accountNumber: String?, - val dueDate: String?, - val stage: StateLabelStage, - val status: StateLabelStatus, + val depositStatus: ParticipantStatusType, + val accountInfo: String, + val depositDeadline: String?, ) -data class DepositItemUiModel( - val name: String, - val price: Int, - val type: PotiItemOptionType, -) - -data class ShippingInfoUiModel( - val recipient: String, - val zipcode: String, - val address: String, - val phone: String, - val deliveryMethod: String, +data class ParticipantShippingUiModel( + val shippingMethod: String, + val deliveryTrackingInfo: String, + val receiver: String, + val addressInfo: String, + val carrier: String?, val trackingNumber: String?, + val shippingStatus: ParticipantStatusType, ) + +fun ParticipantDetail.toUiModel(): ParticipantDetailUiModel { + return ParticipantDetailUiModel( + participationId = this.participationId, + partyId = this.partyId, + orderNumber = this.orderNumber, + partySummary = this.partySummary, + memberPayments = this.memberPayments, + paymentInfo = PaymentInfoUiModel( + shippingFee = this.paymentInfo.shippingFee, + totalAmount = this.paymentInfo.totalAmount, + depositStatus = this.paymentInfo.depositStatus, + accountInfo = if (this.paymentInfo.bank != null && this.paymentInfo.accountNumber != null) { + "${this.paymentInfo.bank} ${this.paymentInfo.accountNumber} ${this.shippingInfo.receiver}" + } else { + "-" + }, + depositDeadline = this.paymentInfo.depositDeadline, + ), + shippingInfo = ParticipantShippingUiModel( + shippingMethod = this.shippingInfo.shippingMethod, + deliveryTrackingInfo = if (this.shippingInfo.trackingNumber != null) { + "${this.shippingInfo.shippingMethod} ${this.shippingInfo.trackingNumber}" + } else { + this.shippingInfo.shippingMethod + }, + receiver = this.shippingInfo.receiver, + addressInfo = "${this.shippingInfo.receiver}\n(${this.shippingInfo.zipcode}) ${this.shippingInfo.address}\n${this.shippingInfo.phone}", + carrier = this.shippingInfo.carrier, + trackingNumber = this.shippingInfo.trackingNumber, + shippingStatus = this.shippingInfo.shippingStatus, + ), + buttonState = when { + this.partySummary.partyStatus == PartyStatusType.CLOSED && this.paymentInfo.depositStatus == ParticipantStatusType.WAIT_PAY -> { + ParticipantButtonState.DEPOSIT_DONE + } + this.shippingInfo.shippingStatus == ParticipantStatusType.SHIPPED -> { + ParticipantButtonState.DELIVERY_RECEIVED + } + else -> ParticipantButtonState.NONE + }, + ) +} diff --git a/app/src/main/java/com/poti/android/presentation/history/recruiter/RecruiterDetailScreen.kt b/app/src/main/java/com/poti/android/presentation/history/recruiter/RecruiterDetailScreen.kt index 2fda5721..fce74404 100644 --- a/app/src/main/java/com/poti/android/presentation/history/recruiter/RecruiterDetailScreen.kt +++ b/app/src/main/java/com/poti/android/presentation/history/recruiter/RecruiterDetailScreen.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment @@ -25,10 +24,10 @@ import com.poti.android.core.designsystem.component.display.PotiDividerStyle import com.poti.android.core.designsystem.component.display.PotiEmptyStateInline import com.poti.android.core.designsystem.component.navigation.PotiHeaderPage import com.poti.android.core.designsystem.theme.PotiTheme +import com.poti.android.presentation.history.component.HistoryDetailContentHeader import com.poti.android.presentation.history.component.PartyInfoSection import com.poti.android.presentation.history.component.ProgressStatusSection import com.poti.android.presentation.history.recruiter.component.HistoryParticipantOverview -import com.poti.android.presentation.history.recruiter.component.ParticipantManagementHeader import com.poti.android.presentation.history.recruiter.model.RecruiterDetailUiEffect import com.poti.android.presentation.history.recruiter.model.RecruiterDetailUiIntent import com.poti.android.presentation.history.recruiter.model.RecruiterDetailUiModel @@ -71,17 +70,15 @@ private fun RecruiterDetailScreen( onParticipantManageDetailClick: () -> Unit, modifier: Modifier = Modifier, ) { - Scaffold( + Column( modifier = modifier.fillMaxSize(), - topBar = { - PotiHeaderPage( - onNavigationClick = onBackClick, - title = stringResource(id = R.string.history_ongoing_title), - ) - }, - ) { paddingValues -> + ) { + PotiHeaderPage( + onNavigationClick = onBackClick, + title = stringResource(id = R.string.history_ongoing_title), + ) + LazyColumn( - modifier = Modifier.padding(paddingValues), horizontalAlignment = Alignment.CenterHorizontally, contentPadding = PaddingValues(bottom = 50.dp), ) { @@ -110,8 +107,8 @@ private fun RecruiterDetailScreen( } item { - ParticipantManagementHeader( - participantCount = recruiterDetail.participantCount, + HistoryDetailContentHeader( + text = stringResource(id = R.string.history_recruiter_participant_management_title, recruiterDetail.participantCount), onHeaderClick = onParticipantManageDetailClick, ) } diff --git a/app/src/main/res/drawable/ic_price.xml b/app/src/main/res/drawable/ic_price.xml index 47f4c920..865d6c02 100644 --- a/app/src/main/res/drawable/ic_price.xml +++ b/app/src/main/res/drawable/ic_price.xml @@ -1,9 +1,20 @@ + android:width="21dp" + android:height="21dp" + android:viewportWidth="21" + android:viewportHeight="21"> + android:pathData="M2.554,12.188L9.979,4.763A0.875,0.875 0,0 1,11.216 4.763L14.929,8.476A0.875,0.875 75.863,0 1,14.929 9.713L7.504,17.138A0.875,0.875 89.569,0 1,6.267 17.138L2.554,13.425A0.875,0.875 81.25,0 1,2.554 12.188z" + android:strokeWidth="1.3125" + android:fillColor="#00000000" + android:strokeColor="#7C7C83"/> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bb69aeff..23708606 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -196,6 +196,7 @@ 배송업체 송장번호를 입력해주세요 송장번호 + 배송방법 모집 내역