Skip to content

Commit d754978

Browse files
authored
Merge pull request #4 from Noostak/feature/#3-api-detail-add
[Feature/#3] : 캘린더 optionId, 시간 조회 duration 필드 추가
2 parents b24f731 + 7ab73c3 commit d754978

16 files changed

Lines changed: 116 additions & 35 deletions

File tree

data/src/main/java/com/sopt/data/dto/response/ResponseGetCalendarDto.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ data class CalendarAppointmentDayDto(
1919

2020
@Serializable
2121
data class CalendarAppointmentDto(
22-
@SerialName("id") val id: Long,
22+
@SerialName("appointmentId") val appointmentId: Long,
23+
@SerialName("optionId") val optionId: Long,
2324
@SerialName("name") val name: String,
2425
@SerialName("date") val date: String,
2526
@SerialName("startTime") val startTime: String,

data/src/main/java/com/sopt/data/dto/response/ResponseGetTimeTableDto.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ data class ResponseGetTimeTableDto(
1212

1313
@Serializable
1414
data class ResponseAppointmentScheduleDto(
15+
@SerialName("duration") val duration: Long,
1516
@SerialName("appointmentHostSelectionTimes") val appointmentHostSelectionTimes: List<BaseTimeDto>,
1617
@SerialName("appointmentMembersInfo") val appointmentMembersInfo: List<ResponseAppointmentMembersInfoDto?>
1718
)

data/src/main/java/com/sopt/data/mapper/ResponseGetCalendarDtoMapper.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ fun CalendarAppointmentDayDto.toCalendarAppointmentDayEntity() = CalendarAppoint
2020
)
2121

2222
fun CalendarAppointmentDto.toCalendarAppointmentEntity() = CalendarAppointmentEntity(
23-
id = id,
23+
appointmentId = appointmentId,
24+
optionId = optionId,
2425
name = name,
2526
date = date,
2627
startTime = startTime,

data/src/main/java/com/sopt/data/mapper/ResponseGetTimeTableDtoMapper.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fun ResponseGetTimeTableDto.toTimeTableEntity() = TimeTableEntity(
1515
)
1616

1717
fun ResponseAppointmentScheduleDto.toAppointmentScheduleEntity() = AppointmentScheduleEntity(
18+
duration = duration,
1819
appointmentHostSelectionTimes = appointmentHostSelectionTimes.map { it.toTimeEntity() },
1920
appointmentMembersInfo = appointmentMembersInfo.map {
2021
it?.toAppointmentMembersInfoEntity() ?: AppointmentMembersInfoEntity(

domain/src/main/java/com/sopt/domain/entity/CalendarEntity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ data class CalendarAppointmentDayEntity(
1313
)
1414

1515
data class CalendarAppointmentEntity(
16-
val id: Long,
16+
val appointmentId: Long,
17+
val optionId: Long,
1718
val name: String,
1819
val date: String,
1920
val startTime: String,

domain/src/main/java/com/sopt/domain/entity/TimeTableEntity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ data class TimeTableEntity(
88
)
99

1010
data class AppointmentScheduleEntity(
11+
val duration: Long,
1112
val appointmentHostSelectionTimes: List<TimeEntity>,
1213
val appointmentMembersInfo: List<AppointmentMembersInfoEntity>
1314
)

presentation/src/main/java/com/sopt/presentation/appointment/AppointmentRoute.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fun AppointmentRoute(
6969
appointmentId: Long,
7070
appointmentName: String,
7171
navigateUp: () -> Unit,
72-
navigateToAppointmentCheck: (Long, Long, String, List<TimeEntity>) -> Unit,
72+
navigateToAppointmentCheck: (Long, Long, String, List<TimeEntity>, Long) -> Unit,
7373
navigateToAppointmentConfirm: (Long, Long, Long, String, Boolean) -> Unit,
7474
appointmentViewModel: AppointmentViewModel = hiltViewModel()
7575
) {
@@ -85,7 +85,8 @@ fun AppointmentRoute(
8585
sideEffect.groupId,
8686
sideEffect.appointmentsId,
8787
sideEffect.appointmentName,
88-
sideEffect.availablePeriods
88+
sideEffect.availablePeriods,
89+
sideEffect.duration
8990
)
9091
}
9192

@@ -122,7 +123,8 @@ fun AppointmentRoute(
122123
groupId,
123124
appointmentId,
124125
appointmentName,
125-
(getTimeTableState as UiState.Success).data.appointmentSchedule.appointmentHostSelectionTimes
126+
(getTimeTableState as UiState.Success).data.appointmentSchedule.appointmentHostSelectionTimes,
127+
(getTimeTableState as UiState.Success).data.appointmentSchedule.duration
126128
)
127129
}
128130
}

presentation/src/main/java/com/sopt/presentation/appointment/AppointmentSideEffect.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ sealed class AppointmentSideEffect {
88
val groupId: Long,
99
val appointmentsId: Long,
1010
val appointmentName: String,
11-
val availablePeriods: List<TimeEntity>
11+
val availablePeriods: List<TimeEntity>,
12+
val duration: Long
1213
) : AppointmentSideEffect()
1314

1415
data class NavigateToAppointmentConfirm(

presentation/src/main/java/com/sopt/presentation/appointment/appointmentCheck/AppointmentCheckRoute.kt

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.sopt.presentation.appointment.appointmentCheck
22

3+
import androidx.compose.animation.AnimatedVisibility
4+
import androidx.compose.animation.slideInVertically
5+
import androidx.compose.animation.slideOutVertically
36
import androidx.compose.foundation.layout.Box
47
import androidx.compose.foundation.layout.Column
58
import androidx.compose.foundation.layout.fillMaxSize
@@ -8,15 +11,20 @@ import androidx.compose.foundation.layout.navigationBarsPadding
811
import androidx.compose.foundation.layout.padding
912
import androidx.compose.foundation.layout.statusBarsPadding
1013
import androidx.compose.material3.Scaffold
14+
import androidx.compose.material3.SnackbarHost
15+
import androidx.compose.material3.SnackbarHostState
1116
import androidx.compose.material3.Text
1217
import androidx.compose.runtime.Composable
1318
import androidx.compose.runtime.LaunchedEffect
19+
import androidx.compose.runtime.MutableState
1420
import androidx.compose.runtime.getValue
1521
import androidx.compose.runtime.mutableStateOf
1622
import androidx.compose.runtime.remember
23+
import androidx.compose.runtime.rememberCoroutineScope
1724
import androidx.compose.runtime.setValue
1825
import androidx.compose.ui.Alignment
1926
import androidx.compose.ui.Modifier
27+
import androidx.compose.ui.platform.LocalContext
2028
import androidx.compose.ui.res.dimensionResource
2129
import androidx.compose.ui.res.stringResource
2230
import androidx.compose.ui.text.style.TextAlign
@@ -27,12 +35,16 @@ import androidx.hilt.navigation.compose.hiltViewModel
2735
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2836
import com.sopt.core.designsystem.component.button.NoostakBottomButton
2937
import com.sopt.core.designsystem.component.dialog.NoostakDialog
38+
import com.sopt.core.designsystem.component.snackbar.NoostakSnackBar
39+
import com.sopt.core.designsystem.component.snackbar.SNACK_BAR_DURATION
3040
import com.sopt.core.designsystem.component.timetable.NoostakEditableTimeTable
3141
import com.sopt.core.designsystem.component.topappbar.NoostakTopAppBar
3242
import com.sopt.core.designsystem.theme.NoostakAndroidTheme
3343
import com.sopt.core.designsystem.theme.NoostakTheme
3444
import com.sopt.domain.entity.TimeEntity
3545
import com.sopt.presentation.R
46+
import kotlinx.coroutines.delay
47+
import kotlinx.coroutines.launch
3648
import timber.log.Timber
3749

3850
@Composable
@@ -41,14 +53,30 @@ fun AppointmentCheckRoute(
4153
appointmentId: Long,
4254
appointmentName: String,
4355
availablePeriods: List<TimeEntity>,
56+
duration: Long,
4457
navigateUp: () -> Unit,
4558
navigateToAppointment: (Long, Long, String) -> Unit,
4659
navigateToGroupDetail: (Long) -> Unit,
4760
appointmentCheckViewModel: AppointmentCheckViewModel = hiltViewModel()
4861
) {
62+
val context = LocalContext.current
4963
val showErrorDialog by appointmentCheckViewModel.showErrorDialog.collectAsStateWithLifecycle()
5064
var selectedData by remember { mutableStateOf(emptyList<TimeEntity>()) }
5165
val rememberedAvailablePeriods = remember { availablePeriods }
66+
val snackBarHostState = remember { SnackbarHostState() }
67+
val coroutineScope = rememberCoroutineScope()
68+
val snackBarVisible = remember { mutableStateOf(false) }
69+
70+
val onShowFailureSnackBar: (message: String) -> Unit = {
71+
coroutineScope.launch {
72+
snackBarVisible.value = true
73+
val job = launch { snackBarHostState.showSnackbar(message = it) }
74+
delay(SNACK_BAR_DURATION)
75+
job.cancel()
76+
snackBarVisible.value = false
77+
}
78+
}
79+
5280
LaunchedEffect(key1 = appointmentCheckViewModel.sideEffects) {
5381
appointmentCheckViewModel.sideEffects.collect { sideEffect ->
5482
when (sideEffect) {
@@ -69,6 +97,10 @@ fun AppointmentCheckRoute(
6997
sideEffect.show,
7098
sideEffect.dialogType
7199
)
100+
101+
is AppointmentCheckSideEffect.ShowSnackBar -> onShowFailureSnackBar(
102+
context.getString(sideEffect.message)
103+
)
72104
}
73105
}
74106
}
@@ -80,13 +112,16 @@ fun AppointmentCheckRoute(
80112
onSelectedDataChange = { selectedData = it },
81113
onBackButtonClick = appointmentCheckViewModel::navigateToGroupDetail,
82114
onConfirmButtonClick = {
115+
// TODO: selectedData가 duration 이하인지 체크하는 로직 추가
83116
appointmentCheckViewModel.postTimeTable(
84117
groupId,
85118
appointmentId,
86119
appointmentName,
87120
selectedData
88121
)
89-
}
122+
},
123+
snackBarHostState = snackBarHostState,
124+
snackBarVisible = snackBarVisible
90125
)
91126

92127
if (showErrorDialog.first) {
@@ -115,7 +150,9 @@ fun AppointmentCheckScreen(
115150
availablePeriods: List<TimeEntity>,
116151
onSelectedDataChange: (List<TimeEntity>) -> Unit = {},
117152
onBackButtonClick: (Long) -> Unit,
118-
onConfirmButtonClick: () -> Unit
153+
onConfirmButtonClick: () -> Unit,
154+
snackBarHostState: SnackbarHostState,
155+
snackBarVisible: MutableState<Boolean>
119156
) {
120157
Scaffold(
121158
modifier = Modifier
@@ -127,6 +164,26 @@ fun AppointmentCheckScreen(
127164
isIconVisible = true,
128165
onBackButtonClick = { onBackButtonClick(groupId) }
129166
)
167+
},
168+
snackbarHost = {
169+
AnimatedVisibility(
170+
visible = snackBarVisible.value,
171+
enter = slideInVertically(initialOffsetY = { it }),
172+
exit = slideOutVertically(targetOffsetY = { it })
173+
) {
174+
SnackbarHost(
175+
modifier = Modifier.padding(bottom = dimensionResource(id = R.dimen.bottom_padding_snack_bar_non_exist_code)),
176+
hostState = snackBarHostState,
177+
snackbar = { snackBarData ->
178+
NoostakSnackBar(
179+
message = snackBarData.visuals.message,
180+
textStyle = NoostakTheme.typography.c3SemiBold,
181+
textColor = NoostakTheme.colors.red01,
182+
backgroundColor = NoostakTheme.colors.pink
183+
)
184+
}
185+
)
186+
}
130187
}
131188
) { innerPadding ->
132189
Box(
@@ -195,7 +252,9 @@ fun PreviewAppointmentConfirmScreen() {
195252
)
196253
),
197254
onBackButtonClick = {},
198-
onConfirmButtonClick = {}
255+
onConfirmButtonClick = {},
256+
snackBarHostState = SnackbarHostState(),
257+
snackBarVisible = remember { mutableStateOf(true) }
199258
)
200259
}
201260
}

presentation/src/main/java/com/sopt/presentation/appointment/appointmentCheck/AppointmentCheckViewModel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,6 @@ sealed class AppointmentCheckSideEffect {
105105
data class NavigateToGroupDetail(val groupId: Long) : AppointmentCheckSideEffect()
106106
data class ShowErrorDialog(val show: Boolean, val dialogType: DialogType) :
107107
AppointmentCheckSideEffect()
108+
109+
data class ShowSnackBar(val message: Int) : AppointmentCheckSideEffect()
108110
}

0 commit comments

Comments
 (0)