Skip to content

Commit 783b829

Browse files
committed
[NDGL-118] feature: 내 여행 관련 API 연동
- 내 여행 전체 일정 수정 - 내 여행 장소 한건 추가 - 내 여행 장소 정보 수정(메모, 비용)
1 parent 6287c38 commit 783b829

12 files changed

Lines changed: 557 additions & 273 deletions

File tree

data/travel/src/main/java/com/yapp/ndgl/data/travel/api/UserTravelApi.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
package com.yapp.ndgl.data.travel.api
22

33
import com.yapp.ndgl.data.core.model.BaseResponse
4+
import com.yapp.ndgl.data.travel.model.AddItineraryRequest
5+
import com.yapp.ndgl.data.travel.model.AddItineraryResponse
46
import com.yapp.ndgl.data.travel.model.BulkUpdateStartTimeRequest
57
import com.yapp.ndgl.data.travel.model.UpcomingTravelList
68
import com.yapp.ndgl.data.travel.model.UpcomingTravelResponse
79
import com.yapp.ndgl.data.travel.model.UpdateItineraryRequest
10+
import com.yapp.ndgl.data.travel.model.UpdateTravelPlaceRequest
811
import com.yapp.ndgl.data.travel.model.UserTravelTemplateContentInfo
912
import com.yapp.ndgl.data.travel.model.UserTravelTemplateItinerary
1013
import retrofit2.http.Body
1114
import retrofit2.http.GET
1215
import retrofit2.http.PATCH
16+
import retrofit2.http.POST
1317
import retrofit2.http.PUT
1418
import retrofit2.http.Path
1519
import retrofit2.http.Query
@@ -41,6 +45,19 @@ interface UserTravelApi {
4145
@Body request: BulkUpdateStartTimeRequest,
4246
): BaseResponse<Unit>
4347

48+
@PATCH("/api/v1/travels/{id}/itinerary/{userTravelPlaceId}")
49+
suspend fun updateTravelPlace(
50+
@Path("id") id: Long,
51+
@Path("userTravelPlaceId") userTravelPlaceId: Long,
52+
@Body request: UpdateTravelPlaceRequest,
53+
): BaseResponse<Unit>
54+
55+
@POST("/api/v1/travels/{id}/itinerary")
56+
suspend fun addItinerary(
57+
@Path("id") id: Long,
58+
@Body request: AddItineraryRequest,
59+
): BaseResponse<AddItineraryResponse>
60+
4461
@PUT("/api/v1/travels/{id}/itinerary")
4562
suspend fun updateItinerary(
4663
@Path("id") id: Long,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.yapp.ndgl.data.travel.model
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class AddItineraryRequest(
8+
val googlePlaceId: String,
9+
val day: Int,
10+
val sequence: Int,
11+
val startTime: String? = null,
12+
val estimatedDuration: String? = null,
13+
val memo: String? = null,
14+
@SerialName("budget")
15+
val cost: Int? = null,
16+
val distanceKm: Double? = null,
17+
val transportation: List<TransportationItem>? = null,
18+
)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.yapp.ndgl.data.travel.model
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class AddItineraryResponse(
8+
val id: Long,
9+
val day: Int,
10+
val sequence: Int,
11+
val startTime: String? = null,
12+
val estimatedDuration: Int,
13+
val memo: String? = null,
14+
@SerialName("budget")
15+
val cost: Int? = null,
16+
val distanceKm: Double? = null,
17+
val transportation: List<Transportation>? = null,
18+
val travelerTips: List<String>? = null,
19+
val planB: List<PlanBPlace>? = null,
20+
val place: ItineraryPlace,
21+
) {
22+
@Serializable
23+
data class Transportation(
24+
val mode: TransportCategory,
25+
val timeMin: Int,
26+
)
27+
28+
@Serializable
29+
data class PlanBPlace(
30+
val googlePlaceId: String,
31+
val name: String,
32+
val thumbnail: String? = null,
33+
val category: PlaceCategory,
34+
)
35+
36+
@Serializable
37+
data class ItineraryPlace(
38+
val googlePlaceId: String,
39+
val thumbnail: String? = null,
40+
val latitude: Double,
41+
val longitude: Double,
42+
val name: String,
43+
val regularOpeningHours: String? = null,
44+
val googleMapsUri: String? = null,
45+
val category: PlaceCategory,
46+
val priceRange: String? = null,
47+
)
48+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.yapp.ndgl.data.travel.model
2+
3+
import kotlinx.serialization.Serializable
4+
5+
@Serializable
6+
data class TransportationItem(
7+
val mode: TransportCategory,
8+
val timeMin: Int,
9+
)

data/travel/src/main/java/com/yapp/ndgl/data/travel/model/UpdateItineraryRequest.kt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,14 @@ data class UpdateItineraryRequest(
1010

1111
@Serializable
1212
data class ItineraryUpdateItem(
13-
val placeId: Long,
13+
val googlePlaceId: String,
1414
val day: Int,
1515
val sequence: Int,
16-
val startTime: String,
16+
val startTime: String? = null,
1717
val estimatedDuration: Int,
18-
@SerialName("travelerTip")
19-
val memo: String?,
18+
val memo: String? = null,
19+
@SerialName("budget")
20+
val cost: Int? = null,
2021
val distanceKm: Double? = null,
2122
val transportation: List<TransportationItem>? = null,
2223
)
23-
24-
@Serializable
25-
data class TransportationItem(
26-
val mode: TransportCategory,
27-
val timeMin: Int,
28-
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.yapp.ndgl.data.travel.model
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class UpdateTravelPlaceRequest(
8+
val memo: String? = null,
9+
@SerialName("budget")
10+
val cost: Int? = null,
11+
)

data/travel/src/main/java/com/yapp/ndgl/data/travel/model/UserTravelTemplateItinerary.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.yapp.ndgl.data.travel.model
22

3+
import kotlinx.serialization.SerialName
34
import kotlinx.serialization.Serializable
45

56
@Serializable
@@ -14,6 +15,8 @@ data class UserTravelTemplateItinerary(
1415
val startTime: String? = null,
1516
val estimatedDuration: Int,
1617
val memo: String? = null,
18+
@SerialName("budget")
19+
val cost: Int? = null,
1720
val distanceKm: Double? = null,
1821
val transportation: List<Transportation>? = null,
1922
val travelerTips: List<String>? = null,

data/travel/src/main/java/com/yapp/ndgl/data/travel/repository/UserTravelRepository.kt

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import com.yapp.ndgl.data.travel.api.UserTravelApi
66
import com.yapp.ndgl.data.travel.model.AddItineraryRequest
77
import com.yapp.ndgl.data.travel.model.AddPlaceEvent
88
import com.yapp.ndgl.data.travel.model.BulkUpdateStartTimeRequest
9+
import com.yapp.ndgl.data.travel.model.ChangePlaceEvent
910
import com.yapp.ndgl.data.travel.model.ItineraryUpdateItem
1011
import com.yapp.ndgl.data.travel.model.StartTimeUpdateItem
12+
import com.yapp.ndgl.data.travel.model.TransportationItem
1113
import com.yapp.ndgl.data.travel.model.TravelCreatedEvent
1214
import com.yapp.ndgl.data.travel.model.UpcomingTravelList
1315
import com.yapp.ndgl.data.travel.model.UpcomingTravelResponse
@@ -41,6 +43,13 @@ class UserTravelRepository @Inject constructor(
4143
)
4244
val travelCreatedEvent: SharedFlow<TravelCreatedEvent> = _travelCreatedEvent.asSharedFlow()
4345

46+
private val _changePlaceEvent = MutableSharedFlow<ChangePlaceEvent>(
47+
replay = 0,
48+
extraBufferCapacity = 1,
49+
onBufferOverflow = BufferOverflow.DROP_OLDEST,
50+
)
51+
val changePlaceEvent: SharedFlow<ChangePlaceEvent> = _changePlaceEvent.asSharedFlow()
52+
4453
suspend fun emitAddPlaceEvent(event: AddPlaceEvent) {
4554
_addPlaceEvent.emit(event)
4655
}
@@ -49,6 +58,10 @@ class UserTravelRepository @Inject constructor(
4958
_travelCreatedEvent.emit(event)
5059
}
5160

61+
suspend fun emitChangePlaceEvent(event: ChangePlaceEvent) {
62+
_changePlaceEvent.emit(event)
63+
}
64+
5265
suspend fun getUpcomingTravel(): UpcomingTravelResponse? {
5366
return try {
5467
userTravelApi.getUpcomingTravel().getData()
@@ -128,18 +141,20 @@ class UserTravelRepository @Inject constructor(
128141
estimatedDuration: String? = null,
129142
cost: Int? = null,
130143
memo: String? = null,
131-
) {
132-
userTravelApi.addItinerary(
133-
id = travelId,
134-
request = AddItineraryRequest(
135-
googlePlaceId = googlePlaceId,
136-
day = day,
137-
sequence = sequence,
138-
startTime = startTime,
139-
estimatedDuration = estimatedDuration,
140-
cost = cost,
141-
memo = memo,
142-
),
143-
).getData()
144-
}
144+
distanceKm: Double? = null,
145+
transportation: List<TransportationItem>? = null,
146+
) = userTravelApi.addItinerary(
147+
id = travelId,
148+
request = AddItineraryRequest(
149+
googlePlaceId = googlePlaceId,
150+
day = day,
151+
sequence = sequence,
152+
startTime = startTime,
153+
estimatedDuration = estimatedDuration,
154+
cost = cost,
155+
memo = memo,
156+
distanceKm = distanceKm,
157+
transportation = transportation,
158+
),
159+
).getData()
145160
}

feature/travel/src/main/java/com/yapp/ndgl/feature/travel/model/TransportSegment.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package com.yapp.ndgl.feature.travel.model
22

3+
import com.yapp.ndgl.data.travel.model.TransportationItem
34
import java.util.Locale.getDefault
5+
import kotlin.math.roundToInt
46
import kotlin.time.Duration
57

68
data class TransportSegment(
79
val googlePlaceId: String,
810
val type: TransportType,
9-
val duration: Duration,
11+
val duration: Duration, // m 단위
1012
val distance: Int,
1113
) {
14+
val distanceKm: Double
15+
get() = (distance / 100.0).roundToInt() / 10.0
16+
1217
fun formatDistance(): String {
1318
return when {
1419
distance >= 1000 -> {
@@ -23,4 +28,11 @@ data class TransportSegment(
2328
else -> "${distance}m"
2429
}
2530
}
31+
32+
fun toTransportationItem(): TransportationItem {
33+
return TransportationItem(
34+
mode = type.toTransportCategory(),
35+
timeMin = duration.inWholeMinutes.toInt(),
36+
)
37+
}
2638
}

feature/travel/src/main/java/com/yapp/ndgl/feature/travel/traveldetail/TravelDetailContract.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import kotlin.time.Duration.Companion.hours
1515
data class TravelDetailState(
1616
val contentInfo: ContentInfo = ContentInfo(),
1717
val countryCode: String = "",
18+
val creatorName: String = "",
19+
val startDate: String = "",
1820
val days: Int = 1,
1921
val selectedDay: Int = 1,
2022
val itineraries: List<Itinerary> = emptyList(),
@@ -45,7 +47,7 @@ data class TravelDetailState(
4547
val representativeLatLng: LatLng
4648
get() {
4749
val currentDayPlaces = itineraries.getOrNull(selectedDay - 1)?.places
48-
val firstPlaceInSelectedDay = currentDayPlaces?.firstOrNull()
50+
val firstPlaceInSelectedDay = currentDayPlaces?.lastOrNull()
4951

5052
if (firstPlaceInSelectedDay != null) {
5153
return LatLng(firstPlaceInSelectedDay.placeInfo.latitude, firstPlaceInSelectedDay.placeInfo.longitude)
@@ -54,7 +56,7 @@ data class TravelDetailState(
5456
return itineraries
5557
.flatMap { it.places }
5658
.firstOrNull()
57-
?.let { LatLng(it.placeInfo.latitude, it.placeInfo.longitude) } ?: LatLng(37.5665, 126.9780) // 모든 일차가 비어 있다면 '서울' 좌표 반환
59+
?.let { LatLng(it.placeInfo.latitude, it.placeInfo.longitude) } ?: LatLng(37.5665, 126.9780) // FIXME: 모든 일차가 비어 있다면 '서울' 좌표 반환
5860
}
5961

6062
// 헤더(0) + stickyHeader(1) + 맵 아이템(2) = 3개가 장소 아이템 앞에 위치
@@ -138,6 +140,8 @@ sealed interface TravelDetailSideEffect : UiSideEffect {
138140
val googlePlaceId: String,
139141
val tipContent: TipContent?,
140142
val alternativePlaces: List<AlternativePlace>?,
143+
val day: Int,
144+
val itineraryId: Long,
141145
) : TravelDetailSideEffect
142146

143147
data class NavigateToBrowser(val url: String) : TravelDetailSideEffect
@@ -150,4 +154,5 @@ sealed interface TravelDetailSideEffect : UiSideEffect {
150154

151155
data object NavigateToMyTravel : TravelDetailSideEffect
152156
data class ScrollToPlace(val placeId: Long) : TravelDetailSideEffect
157+
data class AnimatePlaceChange(val googlePlaceId: String) : TravelDetailSideEffect
153158
}

0 commit comments

Comments
 (0)