Add delete actions for rooms and room types

This commit is contained in:
androidlover5842
2026-01-27 05:04:27 +05:30
parent 4642102ff5
commit 30fcc43f42
5 changed files with 121 additions and 9 deletions

View File

@@ -9,6 +9,7 @@ import com.android.trisolarispms.data.api.model.RoomUpdateRequest
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
@@ -33,6 +34,12 @@ interface RoomApi {
@Body body: RoomUpdateRequest
): Response<RoomDto>
@DELETE("properties/{propertyId}/rooms/{roomId}")
suspend fun deleteRoom(
@Path("propertyId") propertyId: String,
@Path("roomId") roomId: String
): Response<Unit>
@GET("properties/{propertyId}/rooms/board")
suspend fun getRoomBoard(@Path("propertyId") propertyId: String): Response<RoomBoardDto>

View File

@@ -10,7 +10,9 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Done
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -22,6 +24,7 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
@@ -52,6 +55,7 @@ fun RoomFormScreen(
val state by viewModel.state.collectAsState()
val typesState by roomTypesViewModel.state.collectAsState()
var expanded by remember { mutableStateOf(false) }
var showDeleteConfirm by remember { mutableStateOf(false) }
LaunchedEffect(formKey, roomId, roomData) {
viewModel.reset()
@@ -85,6 +89,11 @@ fun RoomFormScreen(
}) {
Icon(Icons.Default.Done, contentDescription = "Save")
}
if (roomId != null) {
IconButton(onClick = { showDeleteConfirm = true }) {
Icon(Icons.Default.Delete, contentDescription = "Delete Room")
}
}
},
colors = TopAppBarDefaults.topAppBarColors()
)
@@ -174,6 +183,27 @@ fun RoomFormScreen(
}
}
if (showDeleteConfirm && roomId != null) {
AlertDialog(
onDismissRequest = { showDeleteConfirm = false },
title = { Text("Delete room?") },
text = { Text("This will remove the room. Continue?") },
confirmButton = {
TextButton(onClick = {
showDeleteConfirm = false
viewModel.deleteRoom(propertyId, roomId, onSave)
}) {
Text("Delete")
}
},
dismissButton = {
TextButton(onClick = { showDeleteConfirm = false }) {
Text("Cancel")
}
}
)
}
}
@Composable

View File

@@ -124,4 +124,26 @@ class RoomFormViewModel : ViewModel() {
}
}
}
fun deleteRoom(propertyId: String, roomId: String, onDone: () -> Unit) {
if (roomId.isBlank()) {
_state.update { it.copy(error = "Room ID is missing") }
return
}
viewModelScope.launch {
_state.update { it.copy(isLoading = true, error = null) }
try {
val api = ApiClient.create()
val response = api.deleteRoom(propertyId, roomId)
if (response.isSuccessful) {
_state.update { it.copy(isLoading = false, success = true) }
onDone()
} else {
_state.update { it.copy(isLoading = false, error = "Delete failed: ${response.code()}") }
}
} catch (e: Exception) {
_state.update { it.copy(isLoading = false, error = e.localizedMessage ?: "Delete failed") }
}
}
}
}

View File

@@ -11,7 +11,9 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Done
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
@@ -20,14 +22,17 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.remember
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
@@ -45,6 +50,7 @@ fun EditRoomTypeScreen(
) {
val state by viewModel.state.collectAsState()
val amenityState by amenityViewModel.state.collectAsState()
val showDeleteConfirm = remember { mutableStateOf(false) }
LaunchedEffect(roomType.id) {
viewModel.setRoomType(roomType)
@@ -66,6 +72,11 @@ fun EditRoomTypeScreen(
IconButton(onClick = { viewModel.submitUpdate(propertyId, roomType.id.orEmpty(), onSave) }) {
Icon(Icons.Default.Done, contentDescription = "Save")
}
if (!roomType.id.isNullOrBlank()) {
IconButton(onClick = { showDeleteConfirm.value = true }) {
Icon(Icons.Default.Delete, contentDescription = "Delete Room Type")
}
}
},
colors = TopAppBarDefaults.topAppBarColors()
)
@@ -131,6 +142,14 @@ fun EditRoomTypeScreen(
)
Spacer(modifier = Modifier.height(12.dp))
OutlinedTextField(
value = state.otaAliases,
onValueChange = viewModel::onAliasesChange,
label = { Text("OTA Aliases (comma separated)") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(12.dp))
Text(text = "Amenities", style = MaterialTheme.typography.titleSmall)
if (amenityState.items.isEmpty()) {
Text(text = "No amenities available", style = MaterialTheme.typography.bodySmall)
@@ -150,19 +169,31 @@ fun EditRoomTypeScreen(
}
}
}
Spacer(modifier = Modifier.height(12.dp))
OutlinedTextField(
value = state.otaAliases,
onValueChange = viewModel::onAliasesChange,
label = { Text("OTA Aliases (comma separated)") },
modifier = Modifier.fillMaxWidth()
)
state.error?.let {
Spacer(modifier = Modifier.height(12.dp))
Text(text = it, color = MaterialTheme.colorScheme.error)
}
}
}
if (showDeleteConfirm.value && !roomType.id.isNullOrBlank()) {
AlertDialog(
onDismissRequest = { showDeleteConfirm.value = false },
title = { Text("Delete room type?") },
text = { Text("This will remove the room type. Continue?") },
confirmButton = {
TextButton(onClick = {
showDeleteConfirm.value = false
viewModel.deleteRoomType(propertyId, roomType.id.orEmpty(), onSave)
}) {
Text("Delete")
}
},
dismissButton = {
TextButton(onClick = { showDeleteConfirm.value = false }) {
Text("Cancel")
}
}
)
}
}

View File

@@ -110,4 +110,26 @@ class RoomTypeFormViewModel : ViewModel() {
}
}
}
fun deleteRoomType(propertyId: String, roomTypeId: String, onDone: () -> Unit) {
if (roomTypeId.isBlank()) {
_state.update { it.copy(error = "Room type ID is missing") }
return
}
viewModelScope.launch {
_state.update { it.copy(isLoading = true, error = null) }
try {
val api = ApiClient.create()
val response = api.deleteRoomType(propertyId, roomTypeId)
if (response.isSuccessful) {
_state.update { it.copy(isLoading = false, success = true) }
onDone()
} else {
_state.update { it.copy(isLoading = false, error = "Delete failed: ${response.code()}") }
}
} catch (e: Exception) {
_state.update { it.copy(isLoading = false, error = e.localizedMessage ?: "Delete failed") }
}
}
}
}