From 30fcc43f42cd9da7f2f2daf4bde56f71e5637b78 Mon Sep 17 00:00:00 2001 From: androidlover5842 Date: Tue, 27 Jan 2026 05:04:27 +0530 Subject: [PATCH] Add delete actions for rooms and room types --- .../android/trisolarispms/data/api/RoomApi.kt | 7 +++ .../trisolarispms/ui/room/RoomFormScreen.kt | 30 ++++++++++++ .../ui/room/RoomFormViewModel.kt | 22 +++++++++ .../ui/roomtype/EditRoomTypeScreen.kt | 49 +++++++++++++++---- .../ui/roomtype/RoomTypeFormViewModel.kt | 22 +++++++++ 5 files changed, 121 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/android/trisolarispms/data/api/RoomApi.kt b/app/src/main/java/com/android/trisolarispms/data/api/RoomApi.kt index 9e211f1..26229c8 100644 --- a/app/src/main/java/com/android/trisolarispms/data/api/RoomApi.kt +++ b/app/src/main/java/com/android/trisolarispms/data/api/RoomApi.kt @@ -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 + @DELETE("properties/{propertyId}/rooms/{roomId}") + suspend fun deleteRoom( + @Path("propertyId") propertyId: String, + @Path("roomId") roomId: String + ): Response + @GET("properties/{propertyId}/rooms/board") suspend fun getRoomBoard(@Path("propertyId") propertyId: String): Response diff --git a/app/src/main/java/com/android/trisolarispms/ui/room/RoomFormScreen.kt b/app/src/main/java/com/android/trisolarispms/ui/room/RoomFormScreen.kt index 151cad7..eeb5444 100644 --- a/app/src/main/java/com/android/trisolarispms/ui/room/RoomFormScreen.kt +++ b/app/src/main/java/com/android/trisolarispms/ui/room/RoomFormScreen.kt @@ -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 diff --git a/app/src/main/java/com/android/trisolarispms/ui/room/RoomFormViewModel.kt b/app/src/main/java/com/android/trisolarispms/ui/room/RoomFormViewModel.kt index 541606e..c55edaf 100644 --- a/app/src/main/java/com/android/trisolarispms/ui/room/RoomFormViewModel.kt +++ b/app/src/main/java/com/android/trisolarispms/ui/room/RoomFormViewModel.kt @@ -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") } + } + } + } } diff --git a/app/src/main/java/com/android/trisolarispms/ui/roomtype/EditRoomTypeScreen.kt b/app/src/main/java/com/android/trisolarispms/ui/roomtype/EditRoomTypeScreen.kt index d1754f6..79b7d13 100644 --- a/app/src/main/java/com/android/trisolarispms/ui/roomtype/EditRoomTypeScreen.kt +++ b/app/src/main/java/com/android/trisolarispms/ui/roomtype/EditRoomTypeScreen.kt @@ -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") + } + } + ) + } } diff --git a/app/src/main/java/com/android/trisolarispms/ui/roomtype/RoomTypeFormViewModel.kt b/app/src/main/java/com/android/trisolarispms/ui/roomtype/RoomTypeFormViewModel.kt index 1455461..42a653e 100644 --- a/app/src/main/java/com/android/trisolarispms/ui/roomtype/RoomTypeFormViewModel.kt +++ b/app/src/main/java/com/android/trisolarispms/ui/roomtype/RoomTypeFormViewModel.kt @@ -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") } + } + } + } }