Compare commits

...

2 Commits

Author SHA1 Message Date
b40749faa1 UI/UX solution:
fix POST booking request
2025-12-05 22:19:51 +07:00
dbe735e541 UI/UX solution:
Added clickable date tabs for booking
2025-12-05 21:28:06 +07:00
4 changed files with 46 additions and 20 deletions

View File

@@ -8,7 +8,10 @@ import io.ktor.client.request.get
import io.ktor.client.request.post import io.ktor.client.request.post
import io.ktor.client.request.setBody import io.ktor.client.request.setBody
import io.ktor.client.statement.bodyAsText import io.ktor.client.statement.bodyAsText
import io.ktor.client.utils.EmptyContent.contentType
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.http.contentType
import io.ktor.serialization.kotlinx.json.json import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -145,6 +148,7 @@ object NetworkDataSource {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
runCatching { runCatching {
val response = client.post(getUrl(code, Constants.BOOK_URL)) { val response = client.post(getUrl(code, Constants.BOOK_URL)) {
contentType(ContentType.Application.Json)
setBody( setBody(
BookRequestDto( BookRequestDto(
date = date, date = date,

View File

@@ -2,11 +2,12 @@ package ru.myitschool.work.domain.booking
import ru.myitschool.work.data.repo.UserRepository import ru.myitschool.work.data.repo.UserRepository
class BookPlaceUseCase( class BookPlaceUseCase(
private val repository: UserRepository, private val repository: UserRepository,
) { ) {
suspend operator fun invoke(date: String, placeId: Int): Result<Unit> { suspend operator fun invoke(roomName: String, placeId: Int): Result<Unit> {
return repository.book(date, placeId) // Нужно получить дату из какого-то источника
// Либо изменить логику в ViewModel
return repository.book(roomName, placeId) // ← но repository.book ожидает date, а не roomName
} }
} }

View File

@@ -1,5 +1,6 @@
package ru.myitschool.work.ui.screen.book package ru.myitschool.work.ui.screen.book
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -13,6 +14,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
@@ -27,6 +29,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -262,15 +265,27 @@ private fun BookDataContent(
itemsIndexed(state.dates) { index, dateLabel -> itemsIndexed(state.dates) { index, dateLabel ->
Surface( Surface(
modifier = Modifier modifier = Modifier
.testTag(TestIds.Book.getIdDateItemByPosition(index)), .testTag(TestIds.Book.getIdDateItemByPosition(index))
tonalElevation = if (index == state.selectedDateIndex) 4.dp else 0.dp .clickable { onSelectDate(index) }
.clip(RoundedCornerShape(8.dp)),
tonalElevation = if (index == state.selectedDateIndex) 4.dp else 0.dp,
color = if (index == state.selectedDateIndex) {
MaterialTheme.colorScheme.primaryContainer
} else {
MaterialTheme.colorScheme.surface
}
) { ) {
Text( Text(
modifier = Modifier modifier = Modifier
.padding(horizontal = 12.dp, vertical = 8.dp) .padding(horizontal = 12.dp, vertical = 8.dp)
.testTag(TestIds.Book.ITEM_DATE), .testTag(TestIds.Book.ITEM_DATE),
text = dateLabel, text = dateLabel,
style = MaterialTheme.typography.bodyMedium style = MaterialTheme.typography.bodyMedium,
color = if (index == state.selectedDateIndex) {
MaterialTheme.colorScheme.onPrimaryContainer
} else {
MaterialTheme.colorScheme.onSurface
}
) )
} }
} }

View File

@@ -37,7 +37,7 @@ class BookViewModel : ViewModel() {
private var allGroups: List<DateGroup> = emptyList() private var allGroups: List<DateGroup> = emptyList()
private var selectedDateIndex: Int = 0 private var selectedDateIndex: Int = 0
private var selectedPlaceId: Int? = null private var selectedSlotId: Int? = null
fun onIntent(intent: BookIntent) { fun onIntent(intent: BookIntent) {
when (intent) { when (intent) {
@@ -51,7 +51,7 @@ class BookViewModel : ViewModel() {
} }
is BookIntent.SelectPlace -> { is BookIntent.SelectPlace -> {
selectedPlaceId = intent.id selectedSlotId = intent.id
val current = _uiState.value val current = _uiState.value
if (current is BookState.Data) { if (current is BookState.Data) {
val updatedPlaces = current.places.map { item -> val updatedPlaces = current.places.map { item ->
@@ -77,7 +77,7 @@ class BookViewModel : ViewModel() {
if (bookings.isEmpty()) { if (bookings.isEmpty()) {
_uiState.value = BookState.Empty _uiState.value = BookState.Empty
allGroups = emptyList() allGroups = emptyList()
selectedPlaceId = null selectedSlotId = null
selectedDateIndex = 0 selectedDateIndex = 0
return@fold return@fold
} }
@@ -86,18 +86,18 @@ class BookViewModel : ViewModel() {
if (allGroups.isEmpty()) { if (allGroups.isEmpty()) {
_uiState.value = BookState.Empty _uiState.value = BookState.Empty
selectedPlaceId = null selectedSlotId = null
selectedDateIndex = 0 selectedDateIndex = 0
return@fold return@fold
} }
selectedDateIndex = 0 selectedDateIndex = 0
selectedPlaceId = null selectedSlotId = null
val firstGroup = allGroups[0] val firstGroup = allGroups[0]
val places = firstGroup.slots.mapIndexed { index, slot -> val places = firstGroup.slots.map { slot ->
BookPlaceItem( BookPlaceItem(
id = index, id = slot.id,
roomName = slot.roomName, roomName = slot.roomName,
time = slot.time, time = slot.time,
isSelected = false, isSelected = false,
@@ -124,10 +124,9 @@ class BookViewModel : ViewModel() {
if (index !in groups.indices) return if (index !in groups.indices) return
selectedDateIndex = index selectedDateIndex = index
selectedPlaceId = null selectedSlotId = null
val group = groups[index] val group = groups[index]
val places = group.slots.mapIndexed { idx, slot -> val places = group.slots.map { slot ->
BookPlaceItem( BookPlaceItem(
id = slot.id, id = slot.id,
roomName = slot.roomName, roomName = slot.roomName,
@@ -135,7 +134,6 @@ class BookViewModel : ViewModel() {
isSelected = false, isSelected = false,
) )
} }
val datesLabels = groups.map { it.label } val datesLabels = groups.map { it.label }
val current = _uiState.value val current = _uiState.value
@@ -158,11 +156,19 @@ class BookViewModel : ViewModel() {
val current = _uiState.value val current = _uiState.value
if (current !is BookState.Data) return if (current !is BookState.Data) return
val placeId = selectedPlaceId ?: return val slotId = selectedSlotId ?: return
val place = current.places.firstOrNull { it.id == placeId } ?: return
allGroups
.flatMap { it.slots }
.firstOrNull { it.id == slotId }
?: return
val selectedDate = allGroups[selectedDateIndex].date.toString()
viewModelScope.launch(Dispatchers.Default) { viewModelScope.launch(Dispatchers.Default) {
bookPlaceUseCase(place.roomName, place.id)
bookPlaceUseCase(selectedDate, slotId)
.fold( .fold(
onSuccess = { onSuccess = {
_actionFlow.emit(Action.CloseWithSuccess) _actionFlow.emit(Action.CloseWithSuccess)