ability to cancel future bookings

This commit is contained in:
androidlover5842
2026-02-04 16:45:15 +05:30
parent e1250a0f32
commit f9b09e2376

View File

@@ -18,11 +18,15 @@ import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Error
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.QrCode
import androidx.compose.material.icons.filled.ReceiptLong
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -31,6 +35,7 @@ import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.AlertDialog
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -53,6 +58,7 @@ import com.android.trisolarispms.data.api.core.ApiClient
import com.android.trisolarispms.data.api.core.ApiConstants
import com.android.trisolarispms.data.api.core.FirebaseAuthTokenProvider
import com.android.trisolarispms.data.api.model.BookingBillingMode
import com.android.trisolarispms.data.api.model.BookingCancelRequest
import com.android.trisolarispms.data.api.model.BookingDetailsResponse
import com.android.trisolarispms.data.api.model.BookingExpectedDatesRequest
import com.android.trisolarispms.ui.booking.BookingDatePickerDialog
@@ -91,10 +97,15 @@ fun BookingDetailsTabsScreen(
val scope = rememberCoroutineScope()
val staysState by staysViewModel.state.collectAsState()
val detailsState by detailsViewModel.state.collectAsState()
val actionsMenuExpanded = remember { mutableStateOf(false) }
val showCancelConfirm = remember { mutableStateOf(false) }
val cancelLoading = remember { mutableStateOf(false) }
val cancelError = remember { mutableStateOf<String?>(null) }
val canModifyDocuments = canManageDocuments && when (detailsState.details?.status) {
"OPEN", "CHECKED_IN" -> true
else -> false
}
val canCancelBooking = detailsState.details?.status?.uppercase() == "OPEN"
LaunchedEffect(propertyId, bookingId, guestId) {
staysViewModel.load(propertyId, bookingId)
@@ -107,7 +118,34 @@ fun BookingDetailsTabsScreen(
BackTopBarScaffold(
title = "Details",
onBack = onBack
onBack = onBack,
actions = {
if (canCancelBooking) {
IconButton(onClick = { actionsMenuExpanded.value = true }) {
Icon(Icons.Default.MoreVert, contentDescription = "More options")
}
DropdownMenu(
expanded = actionsMenuExpanded.value,
onDismissRequest = { actionsMenuExpanded.value = false }
) {
DropdownMenuItem(
text = { Text("Cancel Booking") },
leadingIcon = {
Icon(
imageVector = Icons.Default.Error,
contentDescription = null,
tint = MaterialTheme.colorScheme.error
)
},
onClick = {
actionsMenuExpanded.value = false
cancelError.value = null
showCancelConfirm.value = true
}
)
}
}
}
) { padding ->
Column(
modifier = Modifier
@@ -179,6 +217,74 @@ fun BookingDetailsTabsScreen(
}
}
}
if (showCancelConfirm.value && canCancelBooking) {
AlertDialog(
onDismissRequest = {
if (!cancelLoading.value) {
showCancelConfirm.value = false
}
},
icon = {
Icon(
imageVector = Icons.Default.Error,
contentDescription = null,
tint = MaterialTheme.colorScheme.error
)
},
title = { Text("Cancel booking?") },
text = {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text("This will cancel the OPEN booking.")
cancelError.value?.let { message ->
Text(
text = message,
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodySmall
)
}
}
},
confirmButton = {
TextButton(
enabled = !cancelLoading.value,
onClick = {
scope.launch {
cancelLoading.value = true
cancelError.value = null
try {
val response = ApiClient.create().cancelBooking(
propertyId = propertyId,
bookingId = bookingId,
body = BookingCancelRequest()
)
if (response.isSuccessful) {
showCancelConfirm.value = false
onBack()
} else {
cancelError.value = "Cancel failed: ${response.code()}"
}
} catch (e: Exception) {
cancelError.value = e.localizedMessage ?: "Cancel failed"
} finally {
cancelLoading.value = false
}
}
}
) {
Text(if (cancelLoading.value) "Cancelling..." else "Cancel Booking")
}
},
dismissButton = {
TextButton(
enabled = !cancelLoading.value,
onClick = { showCancelConfirm.value = false }
) {
Text("Keep Booking")
}
}
)
}
}
@Composable