mainscreen: split codes

This commit is contained in:
androidlover5842
2026-02-02 06:02:38 +05:30
parent 99ce18a435
commit 0f0db0dcf5
11 changed files with 850 additions and 760 deletions

View File

@@ -3,56 +3,14 @@ package com.android.trisolarispms
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.compose.BackHandler
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.LaunchedEffect
import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.trisolarispms.auth.AuthzPolicy
import com.android.trisolarispms.auth.Role
import com.android.trisolarispms.auth.toRoleNameList
import com.android.trisolarispms.auth.toRoleSet
import com.android.trisolarispms.ui.AppRoute
import com.android.trisolarispms.ui.auth.AuthScreen
import com.android.trisolarispms.ui.auth.AuthViewModel
import com.android.trisolarispms.ui.auth.NameScreen
import com.android.trisolarispms.ui.auth.UnauthorizedScreen
import com.android.trisolarispms.ui.booking.BookingCreateScreen
import com.android.trisolarispms.ui.guest.GuestInfoScreen
import com.android.trisolarispms.ui.guest.GuestSignatureScreen
import com.android.trisolarispms.ui.booking.BookingExpectedDatesScreen
import com.android.trisolarispms.ui.roomstay.ManageRoomStayRatesScreen
import com.android.trisolarispms.ui.roomstay.ManageRoomStaySelectScreen
import com.android.trisolarispms.ui.roomstay.ManageRoomStaySelection
import com.android.trisolarispms.ui.roomstay.BookingRoomStaysScreen
import com.android.trisolarispms.ui.roomstay.BookingDetailsTabsScreen
import com.android.trisolarispms.ui.home.HomeScreen
import com.android.trisolarispms.ui.payment.BookingPaymentsScreen
import com.android.trisolarispms.ui.property.AddPropertyScreen
import com.android.trisolarispms.ui.room.RoomFormScreen
import com.android.trisolarispms.ui.room.RoomsScreen
import com.android.trisolarispms.ui.card.IssueTemporaryCardScreen
import com.android.trisolarispms.ui.card.CardInfoScreen
import com.android.trisolarispms.ui.roomimage.RoomImagesScreen
import com.android.trisolarispms.ui.roomimage.ImageTagsScreen
import com.android.trisolarispms.ui.roomimage.AddImageTagScreen
import com.android.trisolarispms.ui.roomimage.EditImageTagScreen
import com.android.trisolarispms.ui.roomstay.ActiveRoomStaysScreen
import com.android.trisolarispms.ui.razorpay.RazorpaySettingsScreen
import com.android.trisolarispms.ui.razorpay.RazorpayQrScreen
import com.android.trisolarispms.ui.users.PropertyUsersScreen
import com.android.trisolarispms.ui.users.PropertyAccessCodeScreen
import com.android.trisolarispms.ui.users.SuperAdminUserDirectoryScreen
import com.android.trisolarispms.ui.roomtype.AddAmenityScreen
import com.android.trisolarispms.ui.roomtype.AddRoomTypeScreen
import com.android.trisolarispms.ui.roomtype.AmenitiesScreen
import com.android.trisolarispms.ui.roomtype.EditAmenityScreen
import com.android.trisolarispms.ui.roomtype.EditRoomTypeScreen
import com.android.trisolarispms.ui.roomtype.RatePlanCalendarScreen
import com.android.trisolarispms.ui.roomtype.RoomTypesScreen
import com.android.trisolarispms.ui.theme.TrisolarisPMSTheme
class MainActivity : ComponentActivity() {
@@ -64,674 +22,17 @@ class MainActivity : ComponentActivity() {
val authViewModel: AuthViewModel = viewModel()
val state by authViewModel.state.collectAsState()
if (state.unauthorized) {
UnauthorizedScreen(
when {
state.unauthorized -> UnauthorizedScreen(
message = state.error ?: "Not authorized. Contact admin.",
onSignOut = authViewModel::signOut
)
} else if (state.apiVerified && state.needsName) {
NameScreen(viewModel = authViewModel)
} else if (state.apiVerified) {
val route = remember { mutableStateOf<AppRoute>(AppRoute.Home) }
val refreshKey = remember { mutableStateOf(0) }
val selectedPropertyId = remember { mutableStateOf<String?>(null) }
val selectedPropertyName = remember { mutableStateOf<String?>(null) }
val selectedRoom = remember { mutableStateOf<com.android.trisolarispms.data.api.model.RoomDto?>(null) }
val selectedRoomType = remember { mutableStateOf<com.android.trisolarispms.data.api.model.RoomTypeDto?>(null) }
val selectedAmenity = remember { mutableStateOf<com.android.trisolarispms.data.api.model.AmenityDto?>(null) }
val selectedGuest = remember { mutableStateOf<com.android.trisolarispms.data.api.model.GuestDto?>(null) }
val selectedGuestPhone = remember { mutableStateOf<String?>(null) }
val selectedImageTag = remember { mutableStateOf<com.android.trisolarispms.data.api.model.RoomImageTagDto?>(null) }
val selectedManageRooms = remember { mutableStateOf<List<ManageRoomStaySelection>>(emptyList()) }
val roomFormKey = remember { mutableStateOf(0) }
val amenitiesReturnRoute = remember { mutableStateOf<AppRoute>(AppRoute.Home) }
val currentRoute = route.value
val authz = remember(state.isSuperAdmin, state.propertyRoles) {
AuthzPolicy(
isSuperAdmin = state.isSuperAdmin,
propertyRoles = state.propertyRoles
)
}
val singlePropertyId = state.propertyRoles.keys.firstOrNull()
val singlePropertyIsAdmin = singlePropertyId?.let(authz::isPropertyAdmin) ?: false
val allowedAccessCodeRoles: (String) -> List<String> = { propertyId ->
authz.allowedAccessCodeRoles(propertyId).toRoleNameList()
}
BackHandler(enabled = currentRoute != AppRoute.Home) {
when (currentRoute) {
AppRoute.Home -> Unit
AppRoute.AddProperty -> route.value = AppRoute.Home
AppRoute.SuperAdminUsers -> route.value = AppRoute.Home
is AppRoute.ActiveRoomStays -> {
val blockBack = authz.shouldBlockBackToHome(
propertyId = currentRoute.propertyId,
propertyCount = state.propertyRoles.size
)
if (!blockBack) {
route.value = AppRoute.Home
}
}
is AppRoute.PropertyUsers -> route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
is AppRoute.PropertyAccessCode -> route.value = AppRoute.PropertyUsers(
currentRoute.propertyId
)
is AppRoute.Rooms -> route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
is AppRoute.AddRoom -> route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.EditRoom -> route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.RoomTypes -> route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.AddRoomType -> route.value = AppRoute.RoomTypes(currentRoute.propertyId)
is AppRoute.EditRoomType -> route.value = AppRoute.RoomTypes(currentRoute.propertyId)
AppRoute.Amenities -> route.value = amenitiesReturnRoute.value
AppRoute.AddAmenity -> route.value = AppRoute.Amenities
is AppRoute.EditAmenity -> route.value = AppRoute.Amenities
AppRoute.ImageTags -> route.value = AppRoute.Home
AppRoute.AddImageTag -> route.value = AppRoute.ImageTags
is AppRoute.EditImageTag -> route.value = AppRoute.ImageTags
is AppRoute.RoomImages -> route.value = AppRoute.EditRoom(
currentRoute.propertyId,
currentRoute.roomId
)
is AppRoute.IssueTemporaryCard -> route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.CardInfo -> route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.RatePlanCalendar -> route.value = AppRoute.EditRoomType(
currentRoute.propertyId,
currentRoute.roomTypeId
)
is AppRoute.RazorpaySettings -> route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
is AppRoute.RazorpayQr -> route.value = AppRoute.BookingDetailsTabs(
currentRoute.propertyId,
currentRoute.bookingId,
null
)
is AppRoute.CreateBooking -> route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
is AppRoute.GuestInfo -> route.value = AppRoute.Home
is AppRoute.GuestSignature -> route.value = AppRoute.GuestInfo(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId
)
is AppRoute.ManageRoomStaySelect -> route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
is AppRoute.ManageRoomStayRates -> route.value = AppRoute.ManageRoomStaySelect(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.fromAt,
currentRoute.toAt
)
is AppRoute.ManageRoomStaySelectFromBooking -> route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
is AppRoute.ManageRoomStayRatesFromBooking -> route.value = AppRoute.ManageRoomStaySelectFromBooking(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId,
currentRoute.fromAt,
currentRoute.toAt
)
is AppRoute.BookingRoomStays -> route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
is AppRoute.BookingExpectedDates -> route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
is AppRoute.BookingDetailsTabs -> route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
is AppRoute.BookingPayments -> route.value = AppRoute.BookingDetailsTabs(
currentRoute.propertyId,
currentRoute.bookingId,
null
)
}
}
if (currentRoute == AppRoute.Home &&
!state.isSuperAdmin &&
!singlePropertyIsAdmin &&
state.propertyRoles.size == 1 &&
singlePropertyId != null
) {
LaunchedEffect(singlePropertyId) {
selectedPropertyId.value = singlePropertyId
route.value = AppRoute.ActiveRoomStays(
singlePropertyId,
selectedPropertyName.value ?: "Property"
)
}
}
when (currentRoute) {
AppRoute.Home -> HomeScreen(
userId = state.userId,
userName = state.userName,
isSuperAdmin = state.isSuperAdmin,
onUserDirectory = { route.value = AppRoute.SuperAdminUsers },
onLogout = authViewModel::signOut,
onAddProperty = { route.value = AppRoute.AddProperty },
onAmenities = {
amenitiesReturnRoute.value = AppRoute.Home
route.value = AppRoute.Amenities
},
onImageTags = { route.value = AppRoute.ImageTags },
refreshKey = refreshKey.value,
selectedPropertyId = selectedPropertyId.value,
onSelectProperty = { id, name ->
selectedPropertyId.value = id
selectedPropertyName.value = name
route.value = AppRoute.ActiveRoomStays(id, name)
},
onRefreshProfile = authViewModel::refreshMe,
showJoinProperty = state.propertyRoles.isEmpty() && !state.isSuperAdmin,
onJoinPropertySuccess = { joinedPropertyId, joinedRoles ->
refreshKey.value++
authViewModel.refreshMe()
val isAdmin = joinedRoles.toRoleSet().contains(Role.ADMIN)
val shouldAutoOpen = !state.isSuperAdmin && !isAdmin && state.propertyRoles.size <= 1
if (shouldAutoOpen) {
route.value = AppRoute.ActiveRoomStays(
joinedPropertyId,
selectedPropertyName.value ?: "Property"
)
}
}
)
AppRoute.AddProperty -> AddPropertyScreen(
onBack = { route.value = AppRoute.Home },
onCreated = {
refreshKey.value++
route.value = AppRoute.Home
}
)
is AppRoute.CreateBooking -> BookingCreateScreen(
propertyId = currentRoute.propertyId,
onBack = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
},
onCreated = { response, guest, phone ->
val bookingId = response.id.orEmpty()
val guestId = (guest?.id ?: response.guestId).orEmpty()
selectedGuest.value = guest
selectedGuestPhone.value = phone
if (bookingId.isNotBlank() && guestId.isNotBlank()) {
val fromAt = response.checkInAt?.takeIf { it.isNotBlank() }
?: response.expectedCheckInAt.orEmpty()
val toAt = response.expectedCheckOutAt?.takeIf { it.isNotBlank() }
route.value = AppRoute.ManageRoomStaySelectFromBooking(
propertyId = currentRoute.propertyId,
bookingId = bookingId,
guestId = guestId,
fromAt = fromAt,
toAt = toAt
)
} else {
route.value = AppRoute.Home
}
}
)
is AppRoute.GuestInfo -> GuestInfoScreen(
propertyId = currentRoute.propertyId,
guestId = currentRoute.guestId,
initialGuest = selectedGuest.value,
initialPhone = selectedGuestPhone.value,
onBack = { route.value = AppRoute.Home },
onSave = {
route.value = AppRoute.GuestSignature(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId
)
}
)
is AppRoute.GuestSignature -> GuestSignatureScreen(
propertyId = currentRoute.propertyId,
guestId = currentRoute.guestId,
onBack = {
route.value = AppRoute.GuestInfo(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId
)
},
onDone = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
}
)
is AppRoute.ActiveRoomStays -> ActiveRoomStaysScreen(
propertyId = currentRoute.propertyId,
propertyName = currentRoute.propertyName,
onBack = {
val blockBack = authz.shouldBlockBackToHome(
propertyId = currentRoute.propertyId,
propertyCount = state.propertyRoles.size
)
if (!blockBack) {
route.value = AppRoute.Home
}
},
showBack = !authz.shouldBlockBackToHome(
propertyId = currentRoute.propertyId,
propertyCount = state.propertyRoles.size
),
onViewRooms = { route.value = AppRoute.Rooms(currentRoute.propertyId) },
onCreateBooking = { route.value = AppRoute.CreateBooking(currentRoute.propertyId) },
canCreateBooking = authz.canCreateBookingFor(currentRoute.propertyId),
showRazorpaySettings = authz.canManageRazorpaySettings(currentRoute.propertyId),
onRazorpaySettings = { route.value = AppRoute.RazorpaySettings(currentRoute.propertyId) },
showUserAdmin = authz.canManagePropertyUsers(currentRoute.propertyId),
onUserAdmin = { route.value = AppRoute.PropertyUsers(currentRoute.propertyId) },
onLogout = authViewModel::signOut,
onManageRoomStay = { booking ->
val fromAt = booking.checkInAt?.takeIf { it.isNotBlank() }
?: booking.expectedCheckInAt.orEmpty()
val toAt = booking.expectedCheckOutAt?.takeIf { it.isNotBlank() }
?: booking.checkOutAt?.takeIf { it.isNotBlank() }
if (fromAt.isNotBlank()) {
route.value = AppRoute.ManageRoomStaySelect(
propertyId = currentRoute.propertyId,
bookingId = booking.id.orEmpty(),
fromAt = fromAt,
toAt = toAt
)
}
},
onViewBookingStays = { booking ->
route.value = AppRoute.BookingRoomStays(
propertyId = currentRoute.propertyId,
bookingId = booking.id.orEmpty()
)
},
onOpenBookingDetails = { booking ->
route.value = AppRoute.BookingDetailsTabs(
propertyId = currentRoute.propertyId,
bookingId = booking.id.orEmpty(),
guestId = booking.guestId
)
}
)
is AppRoute.RazorpaySettings -> RazorpaySettingsScreen(
propertyId = currentRoute.propertyId,
onBack = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
}
)
is AppRoute.RazorpayQr -> RazorpayQrScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
pendingAmount = currentRoute.pendingAmount,
guestPhone = currentRoute.guestPhone,
onBack = {
route.value = AppRoute.BookingDetailsTabs(
currentRoute.propertyId,
currentRoute.bookingId,
null
)
}
)
is AppRoute.ManageRoomStaySelect -> ManageRoomStaySelectScreen(
propertyId = currentRoute.propertyId,
bookingFromAt = currentRoute.fromAt,
bookingToAt = currentRoute.toAt,
onBack = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
},
onNext = { rooms ->
selectedManageRooms.value = rooms
route.value = AppRoute.ManageRoomStayRates(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
fromAt = currentRoute.fromAt,
toAt = currentRoute.toAt
)
}
)
is AppRoute.ManageRoomStaySelectFromBooking -> ManageRoomStaySelectScreen(
propertyId = currentRoute.propertyId,
bookingFromAt = currentRoute.fromAt,
bookingToAt = currentRoute.toAt,
onBack = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
},
onNext = { rooms ->
selectedManageRooms.value = rooms
route.value = AppRoute.ManageRoomStayRatesFromBooking(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
guestId = currentRoute.guestId,
fromAt = currentRoute.fromAt,
toAt = currentRoute.toAt
)
}
)
is AppRoute.ManageRoomStayRates -> ManageRoomStayRatesScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
checkInAt = currentRoute.fromAt,
checkOutAt = currentRoute.toAt,
selectedRooms = selectedManageRooms.value,
onBack = {
route.value = AppRoute.ManageRoomStaySelect(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.fromAt,
currentRoute.toAt
)
},
onDone = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
}
)
is AppRoute.ManageRoomStayRatesFromBooking -> ManageRoomStayRatesScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
checkInAt = currentRoute.fromAt,
checkOutAt = currentRoute.toAt,
selectedRooms = selectedManageRooms.value,
onBack = {
route.value = AppRoute.ManageRoomStaySelectFromBooking(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId,
currentRoute.fromAt,
currentRoute.toAt
)
},
onDone = {
route.value = AppRoute.GuestInfo(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId
)
}
)
is AppRoute.BookingRoomStays -> BookingRoomStaysScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
onBack = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
}
)
is AppRoute.BookingExpectedDates -> BookingExpectedDatesScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
status = currentRoute.status,
expectedCheckInAt = currentRoute.expectedCheckInAt,
expectedCheckOutAt = currentRoute.expectedCheckOutAt,
onBack = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
},
onDone = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
}
)
is AppRoute.BookingDetailsTabs -> BookingDetailsTabsScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
guestId = currentRoute.guestId,
onBack = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
},
onEditCheckout = { expectedCheckInAt, expectedCheckOutAt ->
route.value = AppRoute.BookingExpectedDates(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
status = "CHECKED_IN",
expectedCheckInAt = expectedCheckInAt,
expectedCheckOutAt = expectedCheckOutAt
)
},
onEditSignature = { guestId ->
route.value = AppRoute.GuestSignature(
currentRoute.propertyId,
currentRoute.bookingId,
guestId
)
},
onOpenRazorpayQr = { pendingAmount, guestPhone ->
route.value = AppRoute.RazorpayQr(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
pendingAmount = pendingAmount,
guestPhone = guestPhone
)
},
onOpenPayments = {
route.value = AppRoute.BookingPayments(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId
)
},
canManageDocuments = authz.canManageRazorpaySettings(currentRoute.propertyId)
)
is AppRoute.BookingPayments -> BookingPaymentsScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
canAddCash = authz.canAddBookingPayment(currentRoute.propertyId),
canDeleteCash = authz.canDeleteCashPayment(currentRoute.propertyId),
canRefund = authz.canRefundBookingPayment(currentRoute.propertyId),
onBack = {
route.value = AppRoute.BookingDetailsTabs(
currentRoute.propertyId,
currentRoute.bookingId,
null
)
}
)
AppRoute.SuperAdminUsers -> SuperAdminUserDirectoryScreen(
onBack = { route.value = AppRoute.Home }
)
is AppRoute.PropertyUsers -> PropertyUsersScreen(
propertyId = currentRoute.propertyId,
allowedRoleAssignments = authz
.allowedRoleAssignments(currentRoute.propertyId)
.toRoleNameList(),
canDisableAdmin = authz.canDisableAdmin(currentRoute.propertyId),
canDisableManager = authz.canDisableManager(currentRoute.propertyId),
onBack = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
},
onOpenAccessCode = {
route.value = AppRoute.PropertyAccessCode(currentRoute.propertyId)
}
)
is AppRoute.PropertyAccessCode -> PropertyAccessCodeScreen(
propertyId = currentRoute.propertyId,
allowedRoles = allowedAccessCodeRoles(currentRoute.propertyId),
onBack = { route.value = AppRoute.PropertyUsers(currentRoute.propertyId) }
)
is AppRoute.Rooms -> RoomsScreen(
propertyId = currentRoute.propertyId,
onBack = {
route.value = AppRoute.ActiveRoomStays(
currentRoute.propertyId,
selectedPropertyName.value ?: "Property"
)
},
onAddRoom = {
roomFormKey.value++
route.value = AppRoute.AddRoom(currentRoute.propertyId)
},
onViewRoomTypes = { route.value = AppRoute.RoomTypes(currentRoute.propertyId) },
onViewCardInfo = { route.value = AppRoute.CardInfo(currentRoute.propertyId) },
canManageRooms = authz.canManageProperty(currentRoute.propertyId),
canViewCardInfo = authz.canViewCardInfo(currentRoute.propertyId),
canIssueTemporaryCard = authz.canIssueTemporaryCard(currentRoute.propertyId),
onEditRoom = {
selectedRoom.value = it
roomFormKey.value++
route.value = AppRoute.EditRoom(currentRoute.propertyId, it.id ?: "")
},
onIssueTemporaryCard = {
if (it.id != null && authz.canIssueTemporaryCard(currentRoute.propertyId)) {
selectedRoom.value = it
route.value = AppRoute.IssueTemporaryCard(currentRoute.propertyId, it.id)
}
}
)
is AppRoute.RoomTypes -> RoomTypesScreen(
propertyId = currentRoute.propertyId,
onBack = { route.value = AppRoute.Rooms(currentRoute.propertyId) },
onAdd = { route.value = AppRoute.AddRoomType(currentRoute.propertyId) },
canManageRoomTypes = authz.canManageProperty(currentRoute.propertyId),
onEdit = {
selectedRoomType.value = it
route.value = AppRoute.EditRoomType(currentRoute.propertyId, it.id ?: "")
}
)
is AppRoute.AddRoomType -> AddRoomTypeScreen(
propertyId = currentRoute.propertyId,
onBack = { route.value = AppRoute.RoomTypes(currentRoute.propertyId) },
onSave = { route.value = AppRoute.RoomTypes(currentRoute.propertyId) }
)
is AppRoute.EditRoomType -> EditRoomTypeScreen(
propertyId = currentRoute.propertyId,
roomType = selectedRoomType.value
?: com.android.trisolarispms.data.api.model.RoomTypeDto(id = currentRoute.roomTypeId, code = "", name = ""),
onBack = { route.value = AppRoute.RoomTypes(currentRoute.propertyId) },
onSave = { route.value = AppRoute.RoomTypes(currentRoute.propertyId) },
onOpenRatePlanCalendar = { ratePlanId, ratePlanCode ->
route.value = AppRoute.RatePlanCalendar(
currentRoute.propertyId,
currentRoute.roomTypeId,
ratePlanId,
ratePlanCode
)
}
)
AppRoute.Amenities -> AmenitiesScreen(
onBack = { route.value = amenitiesReturnRoute.value },
onAdd = { route.value = AppRoute.AddAmenity },
canManageAmenities = state.isSuperAdmin,
onEdit = {
selectedAmenity.value = it
route.value = AppRoute.EditAmenity(it.id ?: "")
}
)
AppRoute.AddAmenity -> AddAmenityScreen(
onBack = { route.value = AppRoute.Amenities },
onSave = { route.value = AppRoute.Amenities }
)
is AppRoute.EditAmenity -> EditAmenityScreen(
amenity = selectedAmenity.value
?: com.android.trisolarispms.data.api.model.AmenityDto(id = currentRoute.amenityId, name = ""),
onBack = { route.value = AppRoute.Amenities },
onSave = { route.value = AppRoute.Amenities }
)
AppRoute.ImageTags -> ImageTagsScreen(
onBack = { route.value = AppRoute.Home },
onAdd = { route.value = AppRoute.AddImageTag },
onEdit = {
selectedImageTag.value = it
route.value = AppRoute.EditImageTag(it.id ?: "")
}
)
AppRoute.AddImageTag -> AddImageTagScreen(
onBack = { route.value = AppRoute.ImageTags },
onSave = { route.value = AppRoute.ImageTags }
)
is AppRoute.EditImageTag -> EditImageTagScreen(
tag = selectedImageTag.value
?: com.android.trisolarispms.data.api.model.RoomImageTagDto(id = currentRoute.tagId, name = ""),
onBack = { route.value = AppRoute.ImageTags },
onSave = { route.value = AppRoute.ImageTags }
)
is AppRoute.AddRoom -> RoomFormScreen(
title = "Add Room",
propertyId = currentRoute.propertyId,
roomId = null,
roomData = null,
formKey = roomFormKey.value,
onBack = { route.value = AppRoute.Rooms(currentRoute.propertyId) },
onSave = { route.value = AppRoute.Rooms(currentRoute.propertyId) },
onViewImages = { }
)
is AppRoute.EditRoom -> RoomFormScreen(
title = "Modify Room",
propertyId = currentRoute.propertyId,
roomId = currentRoute.roomId,
roomData = selectedRoom.value,
formKey = roomFormKey.value,
onBack = { route.value = AppRoute.Rooms(currentRoute.propertyId) },
onSave = { route.value = AppRoute.Rooms(currentRoute.propertyId) },
onViewImages = { roomId ->
route.value = AppRoute.RoomImages(currentRoute.propertyId, roomId)
}
)
is AppRoute.IssueTemporaryCard -> IssueTemporaryCardScreen(
propertyId = currentRoute.propertyId,
roomId = currentRoute.roomId,
roomNumber = selectedRoom.value?.roomNumber?.toString(),
onBack = { route.value = AppRoute.Rooms(currentRoute.propertyId) }
)
is AppRoute.CardInfo -> CardInfoScreen(
propertyId = currentRoute.propertyId,
onBack = { route.value = AppRoute.Rooms(currentRoute.propertyId) }
)
is AppRoute.RatePlanCalendar -> RatePlanCalendarScreen(
propertyId = currentRoute.propertyId,
ratePlanId = currentRoute.ratePlanId,
ratePlanCode = currentRoute.ratePlanCode,
onBack = { route.value = AppRoute.EditRoomType(currentRoute.propertyId, currentRoute.roomTypeId) }
)
is AppRoute.RoomImages -> RoomImagesScreen(
propertyId = currentRoute.propertyId,
roomId = currentRoute.roomId,
onBack = { route.value = AppRoute.EditRoom(currentRoute.propertyId, currentRoute.roomId) }
)
}
} else {
AuthScreen(viewModel = authViewModel)
state.apiVerified && state.needsName -> NameScreen(viewModel = authViewModel)
state.apiVerified -> MainRouteContent(
state = state,
authViewModel = authViewModel
)
else -> AuthScreen(viewModel = authViewModel)
}
}
}

View File

@@ -0,0 +1,82 @@
package com.android.trisolarispms
import com.android.trisolarispms.auth.AuthzPolicy
import com.android.trisolarispms.ui.AppRoute
internal fun handleBackNavigation(
refs: MainUiRefs,
authz: AuthzPolicy,
propertyCount: Int
) {
when (val currentRoute = refs.currentRoute) {
AppRoute.Home -> Unit
AppRoute.AddProperty -> refs.route.value = AppRoute.Home
AppRoute.SuperAdminUsers -> refs.route.value = AppRoute.Home
is AppRoute.ActiveRoomStays -> {
val blockBack = authz.shouldBlockBackToHome(
propertyId = currentRoute.propertyId,
propertyCount = propertyCount
)
if (!blockBack) {
refs.route.value = AppRoute.Home
}
}
is AppRoute.PropertyUsers -> refs.openActiveRoomStays(currentRoute.propertyId)
is AppRoute.PropertyAccessCode -> refs.route.value = AppRoute.PropertyUsers(currentRoute.propertyId)
is AppRoute.Rooms -> refs.openActiveRoomStays(currentRoute.propertyId)
is AppRoute.AddRoom -> refs.route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.EditRoom -> refs.route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.RoomTypes -> refs.route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.AddRoomType -> refs.route.value = AppRoute.RoomTypes(currentRoute.propertyId)
is AppRoute.EditRoomType -> refs.route.value = AppRoute.RoomTypes(currentRoute.propertyId)
AppRoute.Amenities -> refs.route.value = refs.amenitiesReturnRoute.value
AppRoute.AddAmenity -> refs.route.value = AppRoute.Amenities
is AppRoute.EditAmenity -> refs.route.value = AppRoute.Amenities
AppRoute.ImageTags -> refs.route.value = AppRoute.Home
AppRoute.AddImageTag -> refs.route.value = AppRoute.ImageTags
is AppRoute.EditImageTag -> refs.route.value = AppRoute.ImageTags
is AppRoute.RoomImages -> refs.route.value = AppRoute.EditRoom(currentRoute.propertyId, currentRoute.roomId)
is AppRoute.IssueTemporaryCard -> refs.route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.CardInfo -> refs.route.value = AppRoute.Rooms(currentRoute.propertyId)
is AppRoute.RatePlanCalendar -> refs.route.value = AppRoute.EditRoomType(
currentRoute.propertyId,
currentRoute.roomTypeId
)
is AppRoute.RazorpaySettings -> refs.openActiveRoomStays(currentRoute.propertyId)
is AppRoute.RazorpayQr -> refs.route.value = AppRoute.BookingDetailsTabs(
currentRoute.propertyId,
currentRoute.bookingId,
null
)
is AppRoute.CreateBooking -> refs.openActiveRoomStays(currentRoute.propertyId)
is AppRoute.GuestInfo -> refs.route.value = AppRoute.Home
is AppRoute.GuestSignature -> refs.route.value = AppRoute.GuestInfo(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId
)
is AppRoute.ManageRoomStaySelect -> refs.openActiveRoomStays(currentRoute.propertyId)
is AppRoute.ManageRoomStayRates -> refs.route.value = AppRoute.ManageRoomStaySelect(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.fromAt,
currentRoute.toAt
)
is AppRoute.ManageRoomStaySelectFromBooking -> refs.openActiveRoomStays(currentRoute.propertyId)
is AppRoute.ManageRoomStayRatesFromBooking -> refs.route.value = AppRoute.ManageRoomStaySelectFromBooking(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId,
currentRoute.fromAt,
currentRoute.toAt
)
is AppRoute.BookingRoomStays -> refs.openActiveRoomStays(currentRoute.propertyId)
is AppRoute.BookingExpectedDates -> refs.openActiveRoomStays(currentRoute.propertyId)
is AppRoute.BookingDetailsTabs -> refs.openActiveRoomStays(currentRoute.propertyId)
is AppRoute.BookingPayments -> refs.route.value = AppRoute.BookingDetailsTabs(
currentRoute.propertyId,
currentRoute.bookingId,
null
)
}
}

View File

@@ -0,0 +1,98 @@
package com.android.trisolarispms
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import com.android.trisolarispms.auth.AuthzPolicy
import com.android.trisolarispms.data.api.model.AmenityDto
import com.android.trisolarispms.data.api.model.GuestDto
import com.android.trisolarispms.data.api.model.RoomDto
import com.android.trisolarispms.data.api.model.RoomImageTagDto
import com.android.trisolarispms.data.api.model.RoomTypeDto
import com.android.trisolarispms.ui.AppRoute
import com.android.trisolarispms.ui.auth.AuthUiState
import com.android.trisolarispms.ui.auth.AuthViewModel
import com.android.trisolarispms.ui.roomstay.ManageRoomStaySelection
@Composable
internal fun MainRouteContent(
state: AuthUiState,
authViewModel: AuthViewModel
) {
val refs = remember {
MainUiRefs(
route = mutableStateOf<AppRoute>(AppRoute.Home),
refreshKey = mutableStateOf(0),
selectedPropertyId = mutableStateOf<String?>(null),
selectedPropertyName = mutableStateOf<String?>(null),
selectedRoom = mutableStateOf<RoomDto?>(null),
selectedRoomType = mutableStateOf<RoomTypeDto?>(null),
selectedAmenity = mutableStateOf<AmenityDto?>(null),
selectedGuest = mutableStateOf<GuestDto?>(null),
selectedGuestPhone = mutableStateOf<String?>(null),
selectedImageTag = mutableStateOf<RoomImageTagDto?>(null),
selectedManageRooms = mutableStateOf<List<ManageRoomStaySelection>>(emptyList()),
roomFormKey = mutableStateOf(0),
amenitiesReturnRoute = mutableStateOf<AppRoute>(AppRoute.Home)
)
}
val authz = remember(state.isSuperAdmin, state.propertyRoles) {
AuthzPolicy(
isSuperAdmin = state.isSuperAdmin,
propertyRoles = state.propertyRoles
)
}
val singlePropertyId = state.propertyRoles.keys.firstOrNull()
val singlePropertyIsAdmin = singlePropertyId?.let(authz::isPropertyAdmin) ?: false
BackHandler(enabled = refs.currentRoute != AppRoute.Home) {
handleBackNavigation(
refs = refs,
authz = authz,
propertyCount = state.propertyRoles.size
)
}
if (
refs.currentRoute == AppRoute.Home &&
!state.isSuperAdmin &&
!singlePropertyIsAdmin &&
state.propertyRoles.size == 1 &&
singlePropertyId != null
) {
LaunchedEffect(singlePropertyId) {
refs.selectedPropertyId.value = singlePropertyId
refs.openActiveRoomStays(singlePropertyId)
}
}
when {
renderHomeGuestRoutes(
refs = refs,
state = state,
authViewModel = authViewModel
) -> Unit
renderStayFlowRoutes(
refs = refs,
state = state,
authViewModel = authViewModel,
authz = authz
) -> Unit
renderBookingRoutes(
refs = refs,
authz = authz
) -> Unit
renderManagementRoutes(
refs = refs,
stateIsSuperAdmin = state.isSuperAdmin,
authz = authz
) -> Unit
}
}

View File

@@ -0,0 +1,89 @@
package com.android.trisolarispms
import androidx.compose.runtime.Composable
import com.android.trisolarispms.auth.AuthzPolicy
import com.android.trisolarispms.ui.AppRoute
import com.android.trisolarispms.ui.booking.BookingExpectedDatesScreen
import com.android.trisolarispms.ui.payment.BookingPaymentsScreen
import com.android.trisolarispms.ui.roomstay.BookingDetailsTabsScreen
import com.android.trisolarispms.ui.roomstay.BookingRoomStaysScreen
@Composable
internal fun renderBookingRoutes(
refs: MainUiRefs,
authz: AuthzPolicy
): Boolean {
when (val currentRoute = refs.currentRoute) {
is AppRoute.BookingRoomStays -> BookingRoomStaysScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
onBack = { refs.openActiveRoomStays(currentRoute.propertyId) }
)
is AppRoute.BookingExpectedDates -> BookingExpectedDatesScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
status = currentRoute.status,
expectedCheckInAt = currentRoute.expectedCheckInAt,
expectedCheckOutAt = currentRoute.expectedCheckOutAt,
onBack = { refs.openActiveRoomStays(currentRoute.propertyId) },
onDone = { refs.openActiveRoomStays(currentRoute.propertyId) }
)
is AppRoute.BookingDetailsTabs -> BookingDetailsTabsScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
guestId = currentRoute.guestId,
onBack = { refs.openActiveRoomStays(currentRoute.propertyId) },
onEditCheckout = { expectedCheckInAt, expectedCheckOutAt ->
refs.route.value = AppRoute.BookingExpectedDates(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
status = "CHECKED_IN",
expectedCheckInAt = expectedCheckInAt,
expectedCheckOutAt = expectedCheckOutAt
)
},
onEditSignature = { guestId ->
refs.route.value = AppRoute.GuestSignature(
currentRoute.propertyId,
currentRoute.bookingId,
guestId
)
},
onOpenRazorpayQr = { pendingAmount, guestPhone ->
refs.route.value = AppRoute.RazorpayQr(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
pendingAmount = pendingAmount,
guestPhone = guestPhone
)
},
onOpenPayments = {
refs.route.value = AppRoute.BookingPayments(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId
)
},
canManageDocuments = authz.canManageRazorpaySettings(currentRoute.propertyId)
)
is AppRoute.BookingPayments -> BookingPaymentsScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
canAddCash = authz.canAddBookingPayment(currentRoute.propertyId),
canDeleteCash = authz.canDeleteCashPayment(currentRoute.propertyId),
canRefund = authz.canRefundBookingPayment(currentRoute.propertyId),
onBack = {
refs.route.value = AppRoute.BookingDetailsTabs(
currentRoute.propertyId,
currentRoute.bookingId,
null
)
}
)
else -> return false
}
return true
}

View File

@@ -0,0 +1,117 @@
package com.android.trisolarispms
import androidx.compose.runtime.Composable
import com.android.trisolarispms.auth.Role
import com.android.trisolarispms.ui.AppRoute
import com.android.trisolarispms.ui.auth.AuthUiState
import com.android.trisolarispms.ui.auth.AuthViewModel
import com.android.trisolarispms.ui.booking.BookingCreateScreen
import com.android.trisolarispms.ui.guest.GuestInfoScreen
import com.android.trisolarispms.ui.guest.GuestSignatureScreen
import com.android.trisolarispms.ui.home.HomeScreen
import com.android.trisolarispms.ui.property.AddPropertyScreen
@Composable
internal fun renderHomeGuestRoutes(
refs: MainUiRefs,
state: AuthUiState,
authViewModel: AuthViewModel
): Boolean {
when (val currentRoute = refs.currentRoute) {
AppRoute.Home -> HomeScreen(
userId = state.userId,
userName = state.userName,
isSuperAdmin = state.isSuperAdmin,
onUserDirectory = { refs.route.value = AppRoute.SuperAdminUsers },
onLogout = authViewModel::signOut,
onAddProperty = { refs.route.value = AppRoute.AddProperty },
onAmenities = {
refs.amenitiesReturnRoute.value = AppRoute.Home
refs.route.value = AppRoute.Amenities
},
onImageTags = { refs.route.value = AppRoute.ImageTags },
refreshKey = refs.refreshKey.value,
selectedPropertyId = refs.selectedPropertyId.value,
onSelectProperty = { id, name ->
refs.selectedPropertyId.value = id
refs.selectedPropertyName.value = name
refs.route.value = AppRoute.ActiveRoomStays(id, name)
},
onRefreshProfile = authViewModel::refreshMe,
showJoinProperty = state.propertyRoles.isEmpty() && !state.isSuperAdmin,
onJoinPropertySuccess = { joinedPropertyId, joinedRoles ->
refs.refreshKey.value++
authViewModel.refreshMe()
val isAdmin = joinedRoles.contains(Role.ADMIN)
val shouldAutoOpen = !state.isSuperAdmin && !isAdmin && state.propertyRoles.size <= 1
if (shouldAutoOpen) {
refs.openActiveRoomStays(joinedPropertyId)
}
}
)
AppRoute.AddProperty -> AddPropertyScreen(
onBack = { refs.route.value = AppRoute.Home },
onCreated = {
refs.refreshKey.value++
refs.route.value = AppRoute.Home
}
)
is AppRoute.CreateBooking -> BookingCreateScreen(
propertyId = currentRoute.propertyId,
onBack = { refs.openActiveRoomStays(currentRoute.propertyId) },
onCreated = { response, guest, phone ->
val bookingId = response.id.orEmpty()
val guestId = (guest?.id ?: response.guestId).orEmpty()
refs.selectedGuest.value = guest
refs.selectedGuestPhone.value = phone
if (bookingId.isNotBlank() && guestId.isNotBlank()) {
val fromAt = response.checkInAt?.takeIf { it.isNotBlank() }
?: response.expectedCheckInAt.orEmpty()
val toAt = response.expectedCheckOutAt?.takeIf { it.isNotBlank() }
refs.route.value = AppRoute.ManageRoomStaySelectFromBooking(
propertyId = currentRoute.propertyId,
bookingId = bookingId,
guestId = guestId,
fromAt = fromAt,
toAt = toAt
)
} else {
refs.route.value = AppRoute.Home
}
}
)
is AppRoute.GuestInfo -> GuestInfoScreen(
propertyId = currentRoute.propertyId,
guestId = currentRoute.guestId,
initialGuest = refs.selectedGuest.value,
initialPhone = refs.selectedGuestPhone.value,
onBack = { refs.route.value = AppRoute.Home },
onSave = {
refs.route.value = AppRoute.GuestSignature(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId
)
}
)
is AppRoute.GuestSignature -> GuestSignatureScreen(
propertyId = currentRoute.propertyId,
guestId = currentRoute.guestId,
onBack = {
refs.route.value = AppRoute.GuestInfo(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId
)
},
onDone = { refs.openActiveRoomStays(currentRoute.propertyId) }
)
else -> return false
}
return true
}

View File

@@ -0,0 +1,210 @@
package com.android.trisolarispms
import androidx.compose.runtime.Composable
import com.android.trisolarispms.auth.AuthzPolicy
import com.android.trisolarispms.auth.toRoleNameList
import com.android.trisolarispms.data.api.model.AmenityDto
import com.android.trisolarispms.data.api.model.RoomImageTagDto
import com.android.trisolarispms.data.api.model.RoomTypeDto
import com.android.trisolarispms.ui.AppRoute
import com.android.trisolarispms.ui.card.CardInfoScreen
import com.android.trisolarispms.ui.card.IssueTemporaryCardScreen
import com.android.trisolarispms.ui.room.RoomFormScreen
import com.android.trisolarispms.ui.room.RoomsScreen
import com.android.trisolarispms.ui.roomimage.AddImageTagScreen
import com.android.trisolarispms.ui.roomimage.EditImageTagScreen
import com.android.trisolarispms.ui.roomimage.ImageTagsScreen
import com.android.trisolarispms.ui.roomimage.RoomImagesScreen
import com.android.trisolarispms.ui.roomtype.AddAmenityScreen
import com.android.trisolarispms.ui.roomtype.AddRoomTypeScreen
import com.android.trisolarispms.ui.roomtype.AmenitiesScreen
import com.android.trisolarispms.ui.roomtype.EditAmenityScreen
import com.android.trisolarispms.ui.roomtype.EditRoomTypeScreen
import com.android.trisolarispms.ui.roomtype.RatePlanCalendarScreen
import com.android.trisolarispms.ui.roomtype.RoomTypesScreen
import com.android.trisolarispms.ui.users.PropertyAccessCodeScreen
import com.android.trisolarispms.ui.users.PropertyUsersScreen
import com.android.trisolarispms.ui.users.SuperAdminUserDirectoryScreen
@Composable
internal fun renderManagementRoutes(
refs: MainUiRefs,
stateIsSuperAdmin: Boolean,
authz: AuthzPolicy
): Boolean {
when (val currentRoute = refs.currentRoute) {
AppRoute.SuperAdminUsers -> SuperAdminUserDirectoryScreen(
onBack = { refs.route.value = AppRoute.Home }
)
is AppRoute.PropertyUsers -> PropertyUsersScreen(
propertyId = currentRoute.propertyId,
allowedRoleAssignments = authz
.allowedRoleAssignments(currentRoute.propertyId)
.toRoleNameList(),
canDisableAdmin = authz.canDisableAdmin(currentRoute.propertyId),
canDisableManager = authz.canDisableManager(currentRoute.propertyId),
onBack = { refs.openActiveRoomStays(currentRoute.propertyId) },
onOpenAccessCode = {
refs.route.value = AppRoute.PropertyAccessCode(currentRoute.propertyId)
}
)
is AppRoute.PropertyAccessCode -> PropertyAccessCodeScreen(
propertyId = currentRoute.propertyId,
allowedRoles = authz.allowedAccessCodeRoles(currentRoute.propertyId).toRoleNameList(),
onBack = { refs.route.value = AppRoute.PropertyUsers(currentRoute.propertyId) }
)
is AppRoute.Rooms -> RoomsScreen(
propertyId = currentRoute.propertyId,
onBack = { refs.openActiveRoomStays(currentRoute.propertyId) },
onAddRoom = {
refs.roomFormKey.value++
refs.route.value = AppRoute.AddRoom(currentRoute.propertyId)
},
onViewRoomTypes = { refs.route.value = AppRoute.RoomTypes(currentRoute.propertyId) },
onViewCardInfo = { refs.route.value = AppRoute.CardInfo(currentRoute.propertyId) },
canManageRooms = authz.canManageProperty(currentRoute.propertyId),
canViewCardInfo = authz.canViewCardInfo(currentRoute.propertyId),
canIssueTemporaryCard = authz.canIssueTemporaryCard(currentRoute.propertyId),
onEditRoom = {
refs.selectedRoom.value = it
refs.roomFormKey.value++
refs.route.value = AppRoute.EditRoom(currentRoute.propertyId, it.id ?: "")
},
onIssueTemporaryCard = {
if (it.id != null && authz.canIssueTemporaryCard(currentRoute.propertyId)) {
refs.selectedRoom.value = it
refs.route.value = AppRoute.IssueTemporaryCard(currentRoute.propertyId, it.id)
}
}
)
is AppRoute.RoomTypes -> RoomTypesScreen(
propertyId = currentRoute.propertyId,
onBack = { refs.route.value = AppRoute.Rooms(currentRoute.propertyId) },
onAdd = { refs.route.value = AppRoute.AddRoomType(currentRoute.propertyId) },
canManageRoomTypes = authz.canManageProperty(currentRoute.propertyId),
onEdit = {
refs.selectedRoomType.value = it
refs.route.value = AppRoute.EditRoomType(currentRoute.propertyId, it.id ?: "")
}
)
is AppRoute.AddRoomType -> AddRoomTypeScreen(
propertyId = currentRoute.propertyId,
onBack = { refs.route.value = AppRoute.RoomTypes(currentRoute.propertyId) },
onSave = { refs.route.value = AppRoute.RoomTypes(currentRoute.propertyId) }
)
is AppRoute.EditRoomType -> EditRoomTypeScreen(
propertyId = currentRoute.propertyId,
roomType = refs.selectedRoomType.value
?: RoomTypeDto(id = currentRoute.roomTypeId, code = "", name = ""),
onBack = { refs.route.value = AppRoute.RoomTypes(currentRoute.propertyId) },
onSave = { refs.route.value = AppRoute.RoomTypes(currentRoute.propertyId) },
onOpenRatePlanCalendar = { ratePlanId, ratePlanCode ->
refs.route.value = AppRoute.RatePlanCalendar(
currentRoute.propertyId,
currentRoute.roomTypeId,
ratePlanId,
ratePlanCode
)
}
)
AppRoute.Amenities -> AmenitiesScreen(
onBack = { refs.route.value = refs.amenitiesReturnRoute.value },
onAdd = { refs.route.value = AppRoute.AddAmenity },
canManageAmenities = stateIsSuperAdmin,
onEdit = {
refs.selectedAmenity.value = it
refs.route.value = AppRoute.EditAmenity(it.id ?: "")
}
)
AppRoute.AddAmenity -> AddAmenityScreen(
onBack = { refs.route.value = AppRoute.Amenities },
onSave = { refs.route.value = AppRoute.Amenities }
)
is AppRoute.EditAmenity -> EditAmenityScreen(
amenity = refs.selectedAmenity.value ?: AmenityDto(id = currentRoute.amenityId, name = ""),
onBack = { refs.route.value = AppRoute.Amenities },
onSave = { refs.route.value = AppRoute.Amenities }
)
AppRoute.ImageTags -> ImageTagsScreen(
onBack = { refs.route.value = AppRoute.Home },
onAdd = { refs.route.value = AppRoute.AddImageTag },
onEdit = {
refs.selectedImageTag.value = it
refs.route.value = AppRoute.EditImageTag(it.id ?: "")
}
)
AppRoute.AddImageTag -> AddImageTagScreen(
onBack = { refs.route.value = AppRoute.ImageTags },
onSave = { refs.route.value = AppRoute.ImageTags }
)
is AppRoute.EditImageTag -> EditImageTagScreen(
tag = refs.selectedImageTag.value ?: RoomImageTagDto(id = currentRoute.tagId, name = ""),
onBack = { refs.route.value = AppRoute.ImageTags },
onSave = { refs.route.value = AppRoute.ImageTags }
)
is AppRoute.AddRoom -> RoomFormScreen(
title = "Add Room",
propertyId = currentRoute.propertyId,
roomId = null,
roomData = null,
formKey = refs.roomFormKey.value,
onBack = { refs.route.value = AppRoute.Rooms(currentRoute.propertyId) },
onSave = { refs.route.value = AppRoute.Rooms(currentRoute.propertyId) },
onViewImages = { }
)
is AppRoute.EditRoom -> RoomFormScreen(
title = "Modify Room",
propertyId = currentRoute.propertyId,
roomId = currentRoute.roomId,
roomData = refs.selectedRoom.value,
formKey = refs.roomFormKey.value,
onBack = { refs.route.value = AppRoute.Rooms(currentRoute.propertyId) },
onSave = { refs.route.value = AppRoute.Rooms(currentRoute.propertyId) },
onViewImages = { roomId ->
refs.route.value = AppRoute.RoomImages(currentRoute.propertyId, roomId)
}
)
is AppRoute.IssueTemporaryCard -> IssueTemporaryCardScreen(
propertyId = currentRoute.propertyId,
roomId = currentRoute.roomId,
roomNumber = refs.selectedRoom.value?.roomNumber?.toString(),
onBack = { refs.route.value = AppRoute.Rooms(currentRoute.propertyId) }
)
is AppRoute.CardInfo -> CardInfoScreen(
propertyId = currentRoute.propertyId,
onBack = { refs.route.value = AppRoute.Rooms(currentRoute.propertyId) }
)
is AppRoute.RatePlanCalendar -> RatePlanCalendarScreen(
propertyId = currentRoute.propertyId,
ratePlanId = currentRoute.ratePlanId,
ratePlanCode = currentRoute.ratePlanCode,
onBack = { refs.route.value = AppRoute.EditRoomType(currentRoute.propertyId, currentRoute.roomTypeId) }
)
is AppRoute.RoomImages -> RoomImagesScreen(
propertyId = currentRoute.propertyId,
roomId = currentRoute.roomId,
onBack = { refs.route.value = AppRoute.EditRoom(currentRoute.propertyId, currentRoute.roomId) }
)
else -> return false
}
return true
}

View File

@@ -0,0 +1,171 @@
package com.android.trisolarispms
import androidx.compose.runtime.Composable
import com.android.trisolarispms.auth.AuthzPolicy
import com.android.trisolarispms.ui.AppRoute
import com.android.trisolarispms.ui.auth.AuthUiState
import com.android.trisolarispms.ui.auth.AuthViewModel
import com.android.trisolarispms.ui.razorpay.RazorpayQrScreen
import com.android.trisolarispms.ui.razorpay.RazorpaySettingsScreen
import com.android.trisolarispms.ui.roomstay.ActiveRoomStaysScreen
import com.android.trisolarispms.ui.roomstay.ManageRoomStayRatesScreen
import com.android.trisolarispms.ui.roomstay.ManageRoomStaySelectScreen
@Composable
internal fun renderStayFlowRoutes(
refs: MainUiRefs,
state: AuthUiState,
authViewModel: AuthViewModel,
authz: AuthzPolicy
): Boolean {
when (val currentRoute = refs.currentRoute) {
is AppRoute.ActiveRoomStays -> ActiveRoomStaysScreen(
propertyId = currentRoute.propertyId,
propertyName = currentRoute.propertyName,
onBack = {
val blockBack = authz.shouldBlockBackToHome(
propertyId = currentRoute.propertyId,
propertyCount = state.propertyRoles.size
)
if (!blockBack) {
refs.route.value = AppRoute.Home
}
},
showBack = !authz.shouldBlockBackToHome(
propertyId = currentRoute.propertyId,
propertyCount = state.propertyRoles.size
),
onViewRooms = { refs.route.value = AppRoute.Rooms(currentRoute.propertyId) },
onCreateBooking = { refs.route.value = AppRoute.CreateBooking(currentRoute.propertyId) },
canCreateBooking = authz.canCreateBookingFor(currentRoute.propertyId),
showRazorpaySettings = authz.canManageRazorpaySettings(currentRoute.propertyId),
onRazorpaySettings = { refs.route.value = AppRoute.RazorpaySettings(currentRoute.propertyId) },
showUserAdmin = authz.canManagePropertyUsers(currentRoute.propertyId),
onUserAdmin = { refs.route.value = AppRoute.PropertyUsers(currentRoute.propertyId) },
onLogout = authViewModel::signOut,
onManageRoomStay = { booking ->
val fromAt = booking.checkInAt?.takeIf { it.isNotBlank() }
?: booking.expectedCheckInAt.orEmpty()
val toAt = booking.expectedCheckOutAt?.takeIf { it.isNotBlank() }
?: booking.checkOutAt?.takeIf { it.isNotBlank() }
if (fromAt.isNotBlank()) {
refs.route.value = AppRoute.ManageRoomStaySelect(
propertyId = currentRoute.propertyId,
bookingId = booking.id.orEmpty(),
fromAt = fromAt,
toAt = toAt
)
}
},
onViewBookingStays = { booking ->
refs.route.value = AppRoute.BookingRoomStays(
propertyId = currentRoute.propertyId,
bookingId = booking.id.orEmpty()
)
},
onOpenBookingDetails = { booking ->
refs.route.value = AppRoute.BookingDetailsTabs(
propertyId = currentRoute.propertyId,
bookingId = booking.id.orEmpty(),
guestId = booking.guestId
)
}
)
is AppRoute.RazorpaySettings -> RazorpaySettingsScreen(
propertyId = currentRoute.propertyId,
onBack = { refs.openActiveRoomStays(currentRoute.propertyId) }
)
is AppRoute.RazorpayQr -> RazorpayQrScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
pendingAmount = currentRoute.pendingAmount,
guestPhone = currentRoute.guestPhone,
onBack = {
refs.route.value = AppRoute.BookingDetailsTabs(
currentRoute.propertyId,
currentRoute.bookingId,
null
)
}
)
is AppRoute.ManageRoomStaySelect -> ManageRoomStaySelectScreen(
propertyId = currentRoute.propertyId,
bookingFromAt = currentRoute.fromAt,
bookingToAt = currentRoute.toAt,
onBack = { refs.openActiveRoomStays(currentRoute.propertyId) },
onNext = { rooms ->
refs.selectedManageRooms.value = rooms
refs.route.value = AppRoute.ManageRoomStayRates(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
fromAt = currentRoute.fromAt,
toAt = currentRoute.toAt
)
}
)
is AppRoute.ManageRoomStaySelectFromBooking -> ManageRoomStaySelectScreen(
propertyId = currentRoute.propertyId,
bookingFromAt = currentRoute.fromAt,
bookingToAt = currentRoute.toAt,
onBack = { refs.openActiveRoomStays(currentRoute.propertyId) },
onNext = { rooms ->
refs.selectedManageRooms.value = rooms
refs.route.value = AppRoute.ManageRoomStayRatesFromBooking(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
guestId = currentRoute.guestId,
fromAt = currentRoute.fromAt,
toAt = currentRoute.toAt
)
}
)
is AppRoute.ManageRoomStayRates -> ManageRoomStayRatesScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
checkInAt = currentRoute.fromAt,
checkOutAt = currentRoute.toAt,
selectedRooms = refs.selectedManageRooms.value,
onBack = {
refs.route.value = AppRoute.ManageRoomStaySelect(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.fromAt,
currentRoute.toAt
)
},
onDone = { refs.openActiveRoomStays(currentRoute.propertyId) }
)
is AppRoute.ManageRoomStayRatesFromBooking -> ManageRoomStayRatesScreen(
propertyId = currentRoute.propertyId,
bookingId = currentRoute.bookingId,
checkInAt = currentRoute.fromAt,
checkOutAt = currentRoute.toAt,
selectedRooms = refs.selectedManageRooms.value,
onBack = {
refs.route.value = AppRoute.ManageRoomStaySelectFromBooking(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId,
currentRoute.fromAt,
currentRoute.toAt
)
},
onDone = {
refs.route.value = AppRoute.GuestInfo(
currentRoute.propertyId,
currentRoute.bookingId,
currentRoute.guestId
)
}
)
else -> return false
}
return true
}

View File

@@ -0,0 +1,33 @@
package com.android.trisolarispms
import androidx.compose.runtime.MutableState
import com.android.trisolarispms.data.api.model.AmenityDto
import com.android.trisolarispms.data.api.model.GuestDto
import com.android.trisolarispms.data.api.model.RoomDto
import com.android.trisolarispms.data.api.model.RoomImageTagDto
import com.android.trisolarispms.data.api.model.RoomTypeDto
import com.android.trisolarispms.ui.AppRoute
import com.android.trisolarispms.ui.roomstay.ManageRoomStaySelection
internal data class MainUiRefs(
val route: MutableState<AppRoute>,
val refreshKey: MutableState<Int>,
val selectedPropertyId: MutableState<String?>,
val selectedPropertyName: MutableState<String?>,
val selectedRoom: MutableState<RoomDto?>,
val selectedRoomType: MutableState<RoomTypeDto?>,
val selectedAmenity: MutableState<AmenityDto?>,
val selectedGuest: MutableState<GuestDto?>,
val selectedGuestPhone: MutableState<String?>,
val selectedImageTag: MutableState<RoomImageTagDto?>,
val selectedManageRooms: MutableState<List<ManageRoomStaySelection>>,
val roomFormKey: MutableState<Int>,
val amenitiesReturnRoute: MutableState<AppRoute>
) {
val currentRoute: AppRoute
get() = route.value
fun openActiveRoomStays(propertyId: String) {
route.value = AppRoute.ActiveRoomStays(propertyId, selectedPropertyName.value ?: "Property")
}
}

View File

@@ -2,6 +2,8 @@ package com.android.trisolarispms.ui.home
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.android.trisolarispms.auth.Role
import com.android.trisolarispms.auth.toRoles
import com.android.trisolarispms.data.api.ApiClient
import com.android.trisolarispms.data.api.model.PropertyAccessCodeJoinRequest
import kotlinx.coroutines.flow.MutableStateFlow
@@ -14,7 +16,7 @@ data class HomeJoinPropertyState(
val error: String? = null,
val message: String? = null,
val joinedPropertyId: String? = null,
val joinedRoles: List<String> = emptyList()
val joinedRoles: List<Role> = emptyList()
)
class HomeJoinPropertyViewModel : ViewModel() {
@@ -49,7 +51,7 @@ class HomeJoinPropertyViewModel : ViewModel() {
message = "Joined property",
error = null,
joinedPropertyId = body.propertyId ?: trimmedPropertyId,
joinedRoles = body.roles
joinedRoles = body.roles.toRoles()
)
}
} else {

View File

@@ -33,6 +33,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.trisolarispms.auth.Role
import com.android.trisolarispms.ui.property.PropertyListViewModel
import androidx.compose.foundation.text.KeyboardOptions
@@ -52,7 +53,7 @@ fun HomeScreen(
onSelectProperty: (String, String) -> Unit,
onRefreshProfile: () -> Unit,
showJoinProperty: Boolean,
onJoinPropertySuccess: (String, List<String>) -> Unit,
onJoinPropertySuccess: (String, List<Role>) -> Unit,
viewModel: PropertyListViewModel = viewModel(),
joinViewModel: HomeJoinPropertyViewModel = viewModel()
) {

View File

@@ -32,18 +32,9 @@ class UserDirectoryViewModel : ViewModel() {
when (mode) {
UserDirectoryMode.SuperAdmin -> {
val response = api.listUsers(null)
val body = response.body()
if (response.isSuccessful && body != null) {
val mapped = body.map {
PropertyUserUi(
userId = it.id,
name = it.name,
phoneE164 = it.phoneE164,
disabled = it.disabled,
superAdmin = it.superAdmin
)
}
_state.update { it.copy(isLoading = false, users = mapped, error = null) }
val users = response.body()?.toSuperAdminUsers()
if (response.isSuccessful && users != null) {
_state.update { it.copy(isLoading = false, users = users, error = null) }
} else {
_state.update { it.copy(isLoading = false, error = "Load failed: ${response.code()}") }
}
@@ -53,19 +44,9 @@ class UserDirectoryViewModel : ViewModel() {
propertyId = mode.propertyId,
phone = null
)
val body = response.body()
if (response.isSuccessful && body != null) {
val mapped = body.map {
PropertyUserUi(
userId = it.userId,
roles = it.roles,
name = it.name,
phoneE164 = it.phoneE164,
disabled = it.disabled,
superAdmin = it.superAdmin
)
}
_state.update { it.copy(isLoading = false, users = mapped, error = null) }
val users = response.body()?.toPropertyUsers()
if (response.isSuccessful && users != null) {
_state.update { it.copy(isLoading = false, users = users, error = null) }
} else {
_state.update { it.copy(isLoading = false, error = "Load failed: ${response.code()}") }
}
@@ -90,18 +71,9 @@ class UserDirectoryViewModel : ViewModel() {
when (mode) {
UserDirectoryMode.SuperAdmin -> {
val response = api.listUsers(digits)
val body = response.body()
if (response.isSuccessful && body != null) {
val mapped = body.map {
PropertyUserUi(
userId = it.id,
name = it.name,
phoneE164 = it.phoneE164,
disabled = it.disabled,
superAdmin = it.superAdmin
)
}
_state.update { it.copy(isLoading = false, users = mapped, error = null) }
val users = response.body()?.toSuperAdminUsers()
if (response.isSuccessful && users != null) {
_state.update { it.copy(isLoading = false, users = users, error = null) }
} else {
_state.update { it.copy(isLoading = false, error = "Search failed: ${response.code()}") }
}
@@ -111,19 +83,9 @@ class UserDirectoryViewModel : ViewModel() {
propertyId = mode.propertyId,
phone = digits
)
val body = response.body()
if (response.isSuccessful && body != null) {
val mapped = body.map {
PropertyUserUi(
userId = it.userId,
roles = it.roles,
name = it.name,
phoneE164 = it.phoneE164,
disabled = it.disabled,
superAdmin = it.superAdmin
)
}
_state.update { it.copy(isLoading = false, users = mapped, error = null) }
val users = response.body()?.toPropertyUsers()
if (response.isSuccessful && users != null) {
_state.update { it.copy(isLoading = false, users = users, error = null) }
} else {
_state.update { it.copy(isLoading = false, error = "Search failed: ${response.code()}") }
}
@@ -134,4 +96,28 @@ class UserDirectoryViewModel : ViewModel() {
}
}
}
private fun List<com.android.trisolarispms.data.api.model.AppUserSummaryResponse>.toSuperAdminUsers():
List<PropertyUserUi> =
map {
PropertyUserUi(
userId = it.id,
name = it.name,
phoneE164 = it.phoneE164,
disabled = it.disabled,
superAdmin = it.superAdmin
)
}
private fun List<com.android.trisolarispms.data.api.model.PropertyUserDetailsResponse>.toPropertyUsers():
List<PropertyUserUi> = map {
PropertyUserUi(
userId = it.userId,
roles = it.roles,
name = it.name,
phoneE164 = it.phoneE164,
disabled = it.disabled,
superAdmin = it.superAdmin
)
}
}