Skip to content

Commit

Permalink
feat: implement proposal details screen
Browse files Browse the repository at this point in the history
This commit implements the proposal details screen for businesses:

- Adds a new screen to display details of a specific proposal.

- Fetches proposal details from the API based on the proposal ID.
- Displays proposal information such as title, description, and budget.
- Includes buttons for accepting or rejecting the proposal (functionality not yet implemented).
- Adds a badge to the "Proposals" navigation item to indicate the number of pending proposals
.
  • Loading branch information
OkelloSam21 committed Aug 16, 2024
1 parent 94b134e commit 5ab45d6
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ class ProposalRepositoryImpl @Inject constructor(private val api: KaziHubApi): P
api.getProposals()
}
}

override suspend fun getProposalById(id: Int): Resource<ProposalResponse> {
return safeApiCall {
api.getProposalById(id)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ interface ProposalRepository {
suspend fun createProposal(id: Int, request: ProposalRequest): Resource<CreateProposalResponse>

suspend fun getProposals(): Resource<ProposalResponse>

suspend fun getProposalById(id: Int): Resource<ProposalResponse>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.samuelokello.kazihub.presentation.business

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.samuelokello.kazihub.domain.model.proposal.proposalResponse.ProposalResponseItem
import com.samuelokello.kazihub.domain.repositpry.ProposalRepository
import com.samuelokello.kazihub.utils.Resource
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class ProposalViewmodel @Inject constructor(private val proposalRepository: ProposalRepository): ViewModel() {
val _uiState = MutableStateFlow(ProposalUiState())
val uiState = _uiState.asStateFlow()

private fun fetchProposalsBYId(id: Int) {
viewModelScope.launch {
when (val result = proposalRepository.getProposalById(id)) {
is Resource.Error -> {
_uiState.update {
it.copy(
isLoading = false,
error = result.message
)
}
}
is Resource.Loading -> {
_uiState.update {
it.copy(
isLoading = true,
error = null
)
}
}
is Resource.Success -> {
_uiState.update {
it.copy(
isLoading = false,
error = null,
proposals = result.data ?: emptyList()
)
}
}
}
}
}
}

data class ProposalUiState (
val isLoading: Boolean = false,
val error: String? = null,
val proposals: List<ProposalResponseItem> = emptyList()
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.samuelokello.kazihub.presentation.business

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Surface
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.samuelokello.kazihub.domain.model.proposal.proposalResponse.ProposalResponseItem
import com.samuelokello.kazihub.ui.theme.KaziHubTheme

@OptIn(ExperimentalMaterial3Api::class)
@Destination
@Composable
fun ProposalUi(
proposalId: Int,
viewmodel: ProposalViewmodel = hiltViewModel(),
navigator: DestinationsNavigator
) {
val state = viewmodel.uiState.collectAsState()

KaziHubTheme {
Surface {
if (state.value.isLoading) {
Box(modifier = Modifier.fillMaxSize()) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
} else {
Column (Modifier.fillMaxSize()){
CenterAlignedTopAppBar(
title = { Text(text = "Proposals") },
navigationIcon = {
IconButton(onClick = { navigator.navigateUp() }) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null)
}
}
)
state.value.proposals.forEach { proposal ->
ProposalItem(
proposal = proposal,
onAccept = { },
onReject = { }
)
}
}
}
}
}


}

@Composable
fun ProposalItem(
proposal: ProposalResponseItem,
onAccept: () -> Unit,
onReject: () -> Unit,
modifier: Modifier = Modifier
) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Column {
Text(text = "Title: ${proposal.job.title}", style = MaterialTheme.typography.bodyLarge)
Text(text = "Description: ${proposal.job.description}", style = MaterialTheme.typography.bodyMedium)
Text(text = "Budget: ${proposal.job.budget}", style = MaterialTheme.typography.bodyMedium)
}
Row {
Button(onClick = onAccept, modifier = Modifier.padding(end = 8.dp)) {
Text(text = "Accept")
}
Button(onClick = onReject) {
Text(text = "Reject")
}
}
}
}

@Preview
@Composable
private fun ProposalUiPreview() {
KaziHubTheme {

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.List
import androidx.compose.material3.Badge
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
Expand All @@ -26,6 +27,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.samuelokello.kazihub.R
import com.samuelokello.kazihub.presentation.destinations.ProposalUiDestination

@Composable
fun NavigationDrawer(
Expand All @@ -49,14 +51,25 @@ fun NavigationDrawer(
label = "Home",
onClick = { onItemClick("Home") }
)
NavigationItem(
icon = Icons.Default.List,
label = "Proposals",
onClick = {
// navigator.navigate(ProposalsScreenDestination)
onItemClick("Proposals")

Row {
NavigationItem(
icon = Icons.Default.List,
label = "Proposals",
onClick = {
navigator.navigate(ProposalUiDestination(1))
onItemClick("Proposals")
}
)
Badge(
modifier = Modifier.padding(start = 8.dp),
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary
){
Text(text = "2")
}
)
}

// Add more navigation items as needed
}
}
Expand Down

0 comments on commit 5ab45d6

Please sign in to comment.