diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d7df3eb2..37525e6c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -45,6 +45,9 @@
+
diff --git a/data/src/main/java/com/nexters/boolti/data/datasource/GiftDataSource.kt b/data/src/main/java/com/nexters/boolti/data/datasource/GiftDataSource.kt
index 6e02b0d1..bd08713b 100644
--- a/data/src/main/java/com/nexters/boolti/data/datasource/GiftDataSource.kt
+++ b/data/src/main/java/com/nexters/boolti/data/datasource/GiftDataSource.kt
@@ -16,7 +16,7 @@ internal class GiftDataSource @Inject constructor(
suspend fun approveGiftPayment(request: GiftApproveRequest): ApproveGiftPaymentResponse =
service.approveGiftPayment(request)
- suspend fun getGift(giftId: String): GiftResponse = service.getGift(giftId)
+ suspend fun getGift(giftUuid: String): GiftResponse = service.getGift(giftUuid)
suspend fun getGiftImages(): List = service.getGiftImages()
}
\ No newline at end of file
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 53d1be08..8eaa5a0f 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
@@ -17,8 +17,8 @@ internal interface GiftService {
@POST("/app/api/v1/order/gift-approve-payment")
suspend fun approveGiftPayment(@Body request: GiftApproveRequest): ApproveGiftPaymentResponse
- @GET("/app/api/v1/gift/{giftId}")
- suspend fun getGift(@Path("giftId") giftId: String): GiftResponse
+ @GET("/app/api/v1/gift/{giftUuid}")
+ suspend fun getGift(@Path("giftUuid") giftUuid: String): GiftResponse
@GET("/app/api/v1/gift/img-list")
suspend fun getGiftImages(): List
diff --git a/data/src/main/java/com/nexters/boolti/data/network/request/GiftReceiveRequest.kt b/data/src/main/java/com/nexters/boolti/data/network/request/GiftReceiveRequest.kt
index 567ffa3c..1f766d0a 100644
--- a/data/src/main/java/com/nexters/boolti/data/network/request/GiftReceiveRequest.kt
+++ b/data/src/main/java/com/nexters/boolti/data/network/request/GiftReceiveRequest.kt
@@ -1,5 +1,5 @@
package com.nexters.boolti.data.network.request
data class GiftReceiveRequest(
- val giftId: String,
+ val giftUuid: String,
)
\ No newline at end of file
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 4125ccd3..3afade57 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
@@ -8,12 +8,14 @@ data class ApproveGiftPaymentResponse(
val orderId: String,
val reservationId: String,
val giftId: String,
+ val giftUuid: String,
) {
fun toDomain(): ApproveGiftPayment {
return ApproveGiftPayment(
orderId = orderId,
reservationId = reservationId,
- giftId = giftId
+ giftId = giftId,
+ giftUuid = giftUuid,
)
}
}
\ No newline at end of file
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 0ce94fec..d331171f 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
@@ -1,32 +1,39 @@
package com.nexters.boolti.data.network.response
+import com.nexters.boolti.data.util.toLocalDate
import com.nexters.boolti.domain.model.Gift
import kotlinx.serialization.Serializable
@Serializable
data class GiftResponse(
val id: String,
+ val giftUuid: String,
val orderId: String,
val reservationId: String,
val giftImgId: String,
+ val giftImgPath: String,
val message: String,
val senderName: String,
val senderPhoneNumber: String,
val recipientName: String,
val recipientPhoneNumber: String,
+ val salesEndTime: String,
val isDone: Boolean,
) {
fun toDomain(): Gift {
return Gift(
id = id,
+ uuid = giftUuid,
orderId = orderId,
reservationId = reservationId,
giftImgId = giftImgId,
+ imagePath = giftImgPath,
message = message,
senderName = senderName,
senderPhoneNumber = senderPhoneNumber,
recipientName = recipientName,
recipientPhoneNumber = recipientPhoneNumber,
+ salesEndTime = salesEndTime.toLocalDate(),
isDone = isDone,
)
}
diff --git a/data/src/main/java/com/nexters/boolti/data/repository/GiftRepositoryImpl.kt b/data/src/main/java/com/nexters/boolti/data/repository/GiftRepositoryImpl.kt
index 795fc14e..4faa3ca5 100644
--- a/data/src/main/java/com/nexters/boolti/data/repository/GiftRepositoryImpl.kt
+++ b/data/src/main/java/com/nexters/boolti/data/repository/GiftRepositoryImpl.kt
@@ -15,16 +15,16 @@ import javax.inject.Inject
internal class GiftRepositoryImpl @Inject constructor(
private val dataSource: GiftDataSource
) : GiftRepository {
- override fun receiveGift(giftId: String): Flow = flow {
- emit(dataSource.receiveGift(GiftReceiveRequest(giftId)))
+ override fun receiveGift(giftUuid: String): Flow = flow {
+ emit(dataSource.receiveGift(GiftReceiveRequest(giftUuid)))
}
override fun approveGiftPayment(request: GiftApproveRequest): Flow = flow {
emit(dataSource.approveGiftPayment(request).toDomain())
}
- override fun getGift(giftId: String): Flow = flow {
- emit(dataSource.getGift(giftId).toDomain())
+ override fun getGift(giftUuid: String): Flow = flow {
+ emit(dataSource.getGift(giftUuid).toDomain())
}
override fun getGiftImages(): Flow> = flow {
diff --git a/domain/src/main/java/com/nexters/boolti/domain/model/ApproveGiftPayment.kt b/domain/src/main/java/com/nexters/boolti/domain/model/ApproveGiftPayment.kt
index 0b12f78f..33041985 100644
--- a/domain/src/main/java/com/nexters/boolti/domain/model/ApproveGiftPayment.kt
+++ b/domain/src/main/java/com/nexters/boolti/domain/model/ApproveGiftPayment.kt
@@ -4,4 +4,5 @@ data class ApproveGiftPayment(
val orderId: String,
val reservationId: String,
val giftId: String,
+ val giftUuid: 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 e8f7956b..f0cbdaab 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
@@ -1,14 +1,19 @@
package com.nexters.boolti.domain.model
+import java.time.LocalDate
+
data class Gift(
val id: String,
+ val uuid: String,
val orderId: String,
val reservationId: String,
val giftImgId: String,
+ val imagePath: String,
val message: String,
val senderName: String,
val senderPhoneNumber: String,
val recipientName: String,
val recipientPhoneNumber: String,
+ val salesEndTime: LocalDate,
val isDone: Boolean,
)
diff --git a/domain/src/main/java/com/nexters/boolti/domain/repository/GiftRepository.kt b/domain/src/main/java/com/nexters/boolti/domain/repository/GiftRepository.kt
index 39ffbd94..e860bcfd 100644
--- a/domain/src/main/java/com/nexters/boolti/domain/repository/GiftRepository.kt
+++ b/domain/src/main/java/com/nexters/boolti/domain/repository/GiftRepository.kt
@@ -7,11 +7,11 @@ import com.nexters.boolti.domain.request.GiftApproveRequest
import kotlinx.coroutines.flow.Flow
interface GiftRepository {
- fun receiveGift(giftId: String): Flow
+ fun receiveGift(giftUuid: String): Flow
fun approveGiftPayment(request: GiftApproveRequest): Flow
- fun getGift(giftId: String): Flow
+ fun getGift(giftUuid: String): Flow
fun getGiftImages(): Flow>
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 54738dcd..c4f8259f 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -109,6 +109,7 @@ firebase-dynamic-links = { module = "com.google.firebase:firebase-dynamic-links-
zoomable = { module = "net.engawapg.lib:zoomable", version.ref = "zoomable" }
zxing-android-embedded = { module = "com.journeyapps:zxing-android-embedded", version.ref = "zxing" }
kakao-login = { group = "com.kakao.sdk", name = "v2-user", version.ref = "kakao" }
+kakao-share = { group = "com.kakao.sdk", name = "v2-share", version.ref = "kakao" }
retrofit2-kotlinx-serialization-converter = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version.ref = "serializationConverter" }
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts
index ac7568e4..b884ff72 100644
--- a/presentation/build.gradle.kts
+++ b/presentation/build.gradle.kts
@@ -18,6 +18,7 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
buildConfigField("String", "PACKAGE_NAME", "\"${libs.versions.packageName.get()}\"")
+ buildConfigField("String", "DEV_SUBDOMAIN", getLocalProperty("DEV_SUBDOMAIN"))
}
buildTypes {
@@ -81,6 +82,7 @@ dependencies {
implementation(libs.lottie)
implementation(libs.bundles.coil)
api(libs.kakao.login)
+ implementation(libs.kakao.share)
implementation(libs.timber)
implementation(libs.zxing.android.embedded)
diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/MainDestination.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/MainDestination.kt
index 4fbfab36..f5d80ba1 100644
--- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/MainDestination.kt
+++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/MainDestination.kt
@@ -39,15 +39,15 @@ sealed class MainDestination(val route: String) {
)
}
- data object GiftComplete : MainDestination(route = "giftComplete?reservationId={reservationId}&giftId={giftId}") {
+ data object GiftComplete : MainDestination(route = "giftComplete?reservationId={reservationId}&giftUuid={giftUuid}") {
val arguments = listOf(
navArgument(reservationId) { type = NavType.StringType },
)
fun createRoute(
reservationId: String,
- giftId: String,
- ): String = "giftComplete?reservationId=$reservationId&giftId=$giftId"
+ giftUuid: String,
+ ): String = "giftComplete?reservationId=$reservationId&giftUuid=$giftUuid"
}
data object TicketDetail : MainDestination(route = "tickets") {
diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftNavigation.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftNavigation.kt
index e00f5d04..9ac4b6d2 100644
--- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftNavigation.kt
+++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/gift/GiftNavigation.kt
@@ -18,8 +18,8 @@ fun NavGraphBuilder.addGiftScreen(
modifier = modifier,
popBackStack = popBackStack,
navigateToBusiness = { navigateTo(MainDestination.Business.route) },
- navigateToComplete = { reservationId, giftId ->
- navigateTo(MainDestination.GiftComplete.createRoute(reservationId, giftId))
+ navigateToComplete = { reservationId, giftUuid ->
+ navigateTo(MainDestination.GiftComplete.createRoute(reservationId, giftUuid))
}
)
}
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 b9523333..c5f87a25 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
@@ -81,7 +81,7 @@ import com.nexters.boolti.tosspayments.TossPaymentWidgetActivity.Companion.RESUL
fun GiftScreen(
popBackStack: () -> Unit,
navigateToBusiness: () -> Unit,
- navigateToComplete: (reservationId: String, giftId: String) -> Unit,
+ navigateToComplete: (reservationId: String, giftUuid: String) -> Unit,
modifier: Modifier = Modifier,
viewModel: GiftViewModel = hiltViewModel(),
) {
@@ -100,10 +100,10 @@ fun GiftScreen(
val reservationId =
intent.getStringExtra("reservationId")
?: return@rememberLauncherForActivityResult
- val giftId = intent.getStringExtra("giftId")
+ val giftUuid = intent.getStringExtra("giftUuid")
?: return@rememberLauncherForActivityResult
- navigateToComplete(reservationId, giftId)
+ navigateToComplete(reservationId, giftUuid)
}
RESULT_SOLD_OUT -> showTicketSoldOutDialog = true
diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/giftcomplete/GiftCompleteScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/giftcomplete/GiftCompleteScreen.kt
index 1d880622..70d39490 100644
--- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/giftcomplete/GiftCompleteScreen.kt
+++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/giftcomplete/GiftCompleteScreen.kt
@@ -1,5 +1,6 @@
package com.nexters.boolti.presentation.screen.giftcomplete
+import android.content.Context
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
@@ -33,8 +34,16 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.kakao.sdk.share.ShareClient
+import com.kakao.sdk.template.model.Button
+import com.kakao.sdk.template.model.Content
+import com.kakao.sdk.template.model.FeedTemplate
+import com.kakao.sdk.template.model.Link
+import com.nexters.boolti.domain.model.Gift
import com.nexters.boolti.domain.model.PaymentType
import com.nexters.boolti.domain.model.ReservationDetail
+import com.nexters.boolti.presentation.BuildConfig
import com.nexters.boolti.presentation.R
import com.nexters.boolti.presentation.extension.cardCodeToCompanyName
import com.nexters.boolti.presentation.screen.payment.PaymentToolbar
@@ -48,6 +57,7 @@ import com.nexters.boolti.presentation.theme.Grey95
import com.nexters.boolti.presentation.theme.KakaoYellow
import com.nexters.boolti.presentation.theme.marginHorizontal
import com.nexters.boolti.presentation.theme.point4
+import timber.log.Timber
@Composable
fun GiftCompleteScreen(
@@ -57,6 +67,7 @@ fun GiftCompleteScreen(
) {
val reservation by viewModel.reservation.collectAsStateWithLifecycle()
val gift by viewModel.gift.collectAsStateWithLifecycle()
+ val context = LocalContext.current
BackHandler(onBack = onClickClose)
@@ -70,6 +81,11 @@ fun GiftCompleteScreen(
.padding(innerPadding)
.padding(horizontal = marginHorizontal)
) {
+ val month = gift?.salesEndTime?.month?.value ?: 0
+ val day = gift?.salesEndTime?.dayOfMonth ?: 0
+ val dateText = stringResource(id = R.string.gift_expiration_date, month, day)
+ val buttonsText = stringResource(id = R.string.gift_check)
+
Text(
modifier = Modifier.padding(vertical = 20.dp),
text = stringResource(id = R.string.gift_complete_note),
@@ -93,7 +109,15 @@ fun GiftCompleteScreen(
shape = RoundedCornerShape(4.dp),
colors = ButtonDefaults.outlinedButtonColors(containerColor = KakaoYellow),
contentPadding = PaddingValues(horizontal = 20.dp),
- onClick = { TODO() }
+ onClick = {
+ if (ShareClient.instance.isKakaoTalkSharingAvailable(context)) {
+ gift?.let {
+ sendMessage(context, it, dateText, buttonsText)
+ }
+ } else {
+ // TODO: 카카오톡 미설치 케이스 (아직은 고려 X)
+ }
+ }
) {
Box(
modifier = Modifier.fillMaxWidth(),
@@ -129,6 +153,44 @@ fun GiftCompleteScreen(
}
}
+private fun sendMessage(context: Context, gift: Gift, dateText: String, buttonText: String) {
+ val subDomain = if (BuildConfig.DEBUG) BuildConfig.DEV_SUBDOMAIN else ""
+ val giftUrl = "https://${subDomain}boolti.in/gift/${gift.uuid}"
+
+ val defaultFeed = FeedTemplate(
+ content = Content(
+ title = "To. ${gift.recipientName}",
+ description = dateText,
+ imageUrl = gift.imagePath,
+ link = Link(
+ webUrl = giftUrl,
+ mobileWebUrl = giftUrl
+ )
+ ),
+ buttons = listOf(
+ Button(
+ buttonText,
+ Link(
+ webUrl = giftUrl,
+ mobileWebUrl = giftUrl
+ )
+ ),
+ )
+ )
+
+ ShareClient.instance.shareDefault(context, defaultFeed) { sharingResult, error ->
+ if (error != null) {
+ FirebaseCrashlytics.getInstance().recordException(error)
+ Timber.e(error)
+ } else if (sharingResult != null) {
+ context.startActivity(sharingResult.intent)
+
+ Timber.w("Warning Msg: ${sharingResult.warningMsg}")
+ Timber.w("Argument Msg: ${sharingResult.argumentMsg}")
+ }
+ }
+}
+
@Composable
private fun InfoRow(
modifier: Modifier = Modifier,
diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/giftcomplete/GiftCompleteViewModel.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/giftcomplete/GiftCompleteViewModel.kt
index a1891a96..60da49c3 100644
--- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/giftcomplete/GiftCompleteViewModel.kt
+++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/giftcomplete/GiftCompleteViewModel.kt
@@ -19,8 +19,8 @@ class GiftCompleteViewModel @Inject constructor(
private val reservationId: String = requireNotNull(savedStateHandle["reservationId"]) {
"reservationId 가 전달되지 않았습니다."
}
- private val giftId: String = requireNotNull(savedStateHandle["giftId"]) {
- "giftId 가 전달되지 않았습니다."
+ private val giftUuid: String = requireNotNull(savedStateHandle["giftUuid"]) {
+ "giftUuid 가 전달되지 않았습니다."
}
val reservation = ticketingRepository
@@ -31,7 +31,7 @@ class GiftCompleteViewModel @Inject constructor(
initialValue = null,
)
- val gift = giftRepository.getGift(giftId)
+ val gift = giftRepository.getGift(giftUuid)
.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml
index 66b43c7b..26be2cd3 100644
--- a/presentation/src/main/res/values/strings.xml
+++ b/presentation/src/main/res/values/strings.xml
@@ -178,6 +178,8 @@
받는 분 선택하기
선택된 선물 이미지
선물 편지에 포함될 이미지
+ %d월 %d일까지 불티앱에서 선물을 등록해주세요.
+ 선물 확인하기
- 선물 등록 기간은 해당 공연의 티켓 판매 기간까지입니다.
- 마이 > 결제 내역 > 결제 내역 상세에서 선물을 취소할 수 있습니다.
diff --git a/tosspayments/src/main/java/com/nexters/boolti/tosspayments/PaymentEvent.kt b/tosspayments/src/main/java/com/nexters/boolti/tosspayments/PaymentEvent.kt
index 0d1fffcc..b54f48f3 100644
--- a/tosspayments/src/main/java/com/nexters/boolti/tosspayments/PaymentEvent.kt
+++ b/tosspayments/src/main/java/com/nexters/boolti/tosspayments/PaymentEvent.kt
@@ -4,7 +4,7 @@ sealed interface PaymentEvent {
data class Approved(
val orderId: String,
val reservationId: String,
- val giftId: String = "",
+ val giftUuid: String = "",
) : PaymentEvent
data object TicketSoldOut : PaymentEvent
diff --git a/tosspayments/src/main/java/com/nexters/boolti/tosspayments/TossPaymentWidgetActivity.kt b/tosspayments/src/main/java/com/nexters/boolti/tosspayments/TossPaymentWidgetActivity.kt
index bd938282..6b96cc11 100644
--- a/tosspayments/src/main/java/com/nexters/boolti/tosspayments/TossPaymentWidgetActivity.kt
+++ b/tosspayments/src/main/java/com/nexters/boolti/tosspayments/TossPaymentWidgetActivity.kt
@@ -135,7 +135,7 @@ class TossPaymentWidgetActivity : AppCompatActivity() {
val intent = Intent().apply {
putExtra("orderId", event.orderId)
putExtra("reservationId", event.reservationId)
- putExtra("giftId", event.giftId)
+ putExtra("giftUuid", event.giftUuid)
}
setResult(RESULT_SUCCESS, intent)
finish()
diff --git a/tosspayments/src/main/java/com/nexters/boolti/tosspayments/TossPaymentsWidgetViewModel.kt b/tosspayments/src/main/java/com/nexters/boolti/tosspayments/TossPaymentsWidgetViewModel.kt
index eef5abc3..d78154c3 100644
--- a/tosspayments/src/main/java/com/nexters/boolti/tosspayments/TossPaymentsWidgetViewModel.kt
+++ b/tosspayments/src/main/java/com/nexters/boolti/tosspayments/TossPaymentsWidgetViewModel.kt
@@ -125,7 +125,7 @@ class TossPaymentsWidgetViewModel @Inject constructor(
event(PaymentEvent.TicketSoldOut)
}
}.singleOrNull()?.let {
- event(PaymentEvent.Approved(it.orderId, it.reservationId, it.giftId))
+ event(PaymentEvent.Approved(it.orderId, it.reservationId, it.giftUuid))
}
}