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