diff --git a/data/src/main/java/com/nexters/boolti/data/network/api/GiftService.kt b/data/src/main/java/com/nexters/boolti/data/network/api/GiftService.kt index 243306ce..914133cf 100644 --- a/data/src/main/java/com/nexters/boolti/data/network/api/GiftService.kt +++ b/data/src/main/java/com/nexters/boolti/data/network/api/GiftService.kt @@ -18,7 +18,7 @@ internal interface GiftService { @POST("/app/api/v1/order/gift-approve-payment") suspend fun approveGiftPayment(@Body request: GiftApproveRequest): ApproveGiftPaymentResponse - @POST + @POST("/app/api/v1/order/free-gift-reservation") suspend fun createFreeGift(@Body request: FreeGiftRequest): ApproveGiftPaymentResponse @GET("/app/api/v1/gift/{giftUuid}") diff --git a/data/src/main/java/com/nexters/boolti/data/network/response/ApproveGiftPaymentResponse.kt b/data/src/main/java/com/nexters/boolti/data/network/response/ApproveGiftPaymentResponse.kt index 3afade57..49275d8e 100644 --- a/data/src/main/java/com/nexters/boolti/data/network/response/ApproveGiftPaymentResponse.kt +++ b/data/src/main/java/com/nexters/boolti/data/network/response/ApproveGiftPaymentResponse.kt @@ -5,7 +5,7 @@ import kotlinx.serialization.Serializable @Serializable data class ApproveGiftPaymentResponse( - val orderId: String, + val orderId: String = "-1", // 무료 티켓일 경우 orderId가 null val reservationId: String, val giftId: String, val giftUuid: String, diff --git a/data/src/main/java/com/nexters/boolti/data/network/response/GiftResponse.kt b/data/src/main/java/com/nexters/boolti/data/network/response/GiftResponse.kt index d331171f..6d0e5dc5 100644 --- a/data/src/main/java/com/nexters/boolti/data/network/response/GiftResponse.kt +++ b/data/src/main/java/com/nexters/boolti/data/network/response/GiftResponse.kt @@ -8,7 +8,7 @@ import kotlinx.serialization.Serializable data class GiftResponse( val id: String, val giftUuid: String, - val orderId: String, + val orderId: String?, val reservationId: String, val giftImgId: String, val giftImgPath: String, diff --git a/domain/src/main/java/com/nexters/boolti/domain/model/Gift.kt b/domain/src/main/java/com/nexters/boolti/domain/model/Gift.kt index f0cbdaab..46d211ae 100644 --- a/domain/src/main/java/com/nexters/boolti/domain/model/Gift.kt +++ b/domain/src/main/java/com/nexters/boolti/domain/model/Gift.kt @@ -5,7 +5,7 @@ import java.time.LocalDate data class Gift( val id: String, val uuid: String, - val orderId: String, + val orderId: String?, val reservationId: String, val giftImgId: String, val imagePath: String, diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftEvent.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftEvent.kt index cee24ce1..c8f564e9 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftEvent.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftEvent.kt @@ -1,7 +1,7 @@ package com.nexters.boolti.presentation.screen.gift sealed interface GiftEvent { - data class GiftSuccess(val reservationId: String, val showId: String) : GiftEvent + data class GiftSuccess(val reservationId: String, val giftUuid: String) : GiftEvent data class ProgressPayment(val userId: String, val orderId: String) : GiftEvent data object NoRemainingQuantity : GiftEvent } \ No newline at end of file diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftScreen.kt index e48b3ad9..efaddea5 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftScreen.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftScreen.kt @@ -3,24 +3,15 @@ package com.nexters.boolti.presentation.screen.gift import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts 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.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -34,26 +25,18 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.RectangleShape -import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import coil.compose.AsyncImage import com.nexters.boolti.domain.model.Currency -import com.nexters.boolti.domain.model.ImagePair import com.nexters.boolti.presentation.BuildConfig import com.nexters.boolti.presentation.R import com.nexters.boolti.presentation.component.BtAppBar @@ -67,8 +50,6 @@ import com.nexters.boolti.presentation.screen.ticketing.PaymentFailureDialog import com.nexters.boolti.presentation.screen.ticketing.RefundPolicySection import com.nexters.boolti.presentation.screen.ticketing.Section import com.nexters.boolti.presentation.screen.ticketing.TicketInfoSection -import com.nexters.boolti.presentation.theme.BooltiTheme -import com.nexters.boolti.presentation.theme.Grey10 import com.nexters.boolti.presentation.theme.Grey40 import com.nexters.boolti.presentation.theme.Grey70 import com.nexters.boolti.presentation.theme.marginHorizontal @@ -115,7 +96,9 @@ fun GiftScreen( viewModel.events .collect { event -> when (event) { - is GiftEvent.GiftSuccess -> {} + is GiftEvent.GiftSuccess -> { + navigateToComplete(event.reservationId, event.giftUuid) + } is GiftEvent.ProgressPayment -> { val selectedImage = uiState.selectedImage ?: return@collect @@ -297,7 +280,7 @@ fun GiftScreen( ticketName = uiState.ticketName, ticketCount = uiState.ticketCount, totalPrice = uiState.totalPrice, - onClick = viewModel::pay, + onClick = { viewModel.pay(uiState.totalPrice == 0) }, onDismiss = { showConfirmDialog = false }, ) } diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftViewModel.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftViewModel.kt index 88276e8d..5b0089df 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftViewModel.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope import com.nexters.boolti.domain.model.ImagePair import com.nexters.boolti.domain.repository.GiftRepository import com.nexters.boolti.domain.repository.TicketingRepository +import com.nexters.boolti.domain.request.FreeGiftRequest import com.nexters.boolti.domain.request.OrderIdRequest import com.nexters.boolti.domain.request.TicketingInfoRequest import com.nexters.boolti.domain.usecase.GetRefundPolicyUsecase @@ -15,7 +16,6 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onEach @@ -117,8 +117,38 @@ class GiftViewModel @Inject constructor( _uiState.update { it.copy(selectedImage = image) } } - fun pay() { - // TODO : 무료 케이스 처리 + fun pay(isFree: Boolean) { + if (isFree) { + val state = uiState.value + + giftRepository.sendFreeGift( + FreeGiftRequest( + amount = 0, + showId = showId, + salesTicketTypeId = salesTicketTypeId, + ticketCount = state.ticketCount, + senderName = state.senderName, + senderPhoneNumber = state.senderContact, + recipientName = state.receiverName, + recipientPhoneNumber = state.receiverContact, + message = state.message, + giftImageId = state.selectedImage?.id ?: state.giftImages.first().id + ) + ) + .onStart { _uiState.update { it.copy(loading = true) } } + .onEach { giftPayment -> + sendEvent( + GiftEvent.GiftSuccess( + reservationId = giftPayment.reservationId, + giftUuid = giftPayment.giftUuid + ) + ) + } + .onCompletion { _uiState.update { it.copy(loading = false) } } + .launchIn(viewModelScope + recordExceptionHandler) + + return + } ticketingRepository.requestOrderId(OrderIdRequest(showId, salesTicketTypeId, ticketCount)) .onStart { _uiState.update { it.copy(loading = true) } }