Skip to content

Commit

Permalink
Merge pull request #23 from indigotech/feature/user-details
Browse files Browse the repository at this point in the history
user detail screen and integration
  • Loading branch information
VituHonda authored Sep 18, 2024
2 parents 0168e10 + e455681 commit 2582bae
Show file tree
Hide file tree
Showing 21 changed files with 440 additions and 311 deletions.
2 changes: 1 addition & 1 deletion .gradle/config.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Thu Sep 05 11:55:59 BRT 2024
#Fri Sep 13 14:46:51 BRT 2024
java.home=/Applications/Android Studio.app/Contents/jbr/Contents/Home
5 changes: 5 additions & 0 deletions app/src/main/java/com/example/greetingcard/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.navigation.compose.rememberNavController
import com.example.greetingcard.ui.theme.GreetingCardTheme
import com.example.greetingcard.view.LoginScreen
import com.example.greetingcard.view.NewUserScreen
import com.example.greetingcard.view.UserDetailScreen
import com.example.greetingcard.view.UserListScreen

class MainActivity : ComponentActivity() {
Expand All @@ -36,5 +37,9 @@ fun MyApp() {
composable(route = "Login") { LoginScreen(navController) }
composable(route = "UserListScreen") { UserListScreen(navController) }
composable(route = "NewUserScreen") { NewUserScreen(navController) }
composable("UserDetailScreen/{id}") { backStackEntry ->
val userId = backStackEntry.arguments?.getString("id")
UserDetailScreen(userId = userId ?: "", navController = navController)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ data class LoadListResponse(
)

data class LoadListDataResponse(
val nodes: List<User>
val nodes: List<ListUserItem>
)

data class LoadListUserItem(
data class ListUserItem(
val id: String,
val name: String,
val email: String
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/java/com/example/greetingcard/model/Roles.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ package com.example.greetingcard.model

enum class Roles {
ADMIN,
USER,
NOROLE
USER
}
7 changes: 0 additions & 7 deletions app/src/main/java/com/example/greetingcard/model/User.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.greetingcard.model
data class UserDetailState(
val name: String = "",
val email: String = "",
val phone: String = "",
val birthDate: String = "",
val role: String = ""
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import retrofit2.await

class UserPagingSource(
private val token: String
) : PagingSource<Int, User>() {
) : PagingSource<Int, ListUserItem>() {

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, User> {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, ListUserItem> {
return try {
val currentPage = params.key ?: 0

val response = UserRetrofitService.userRetrofitService.loadUsers(token, currentPage).await()
val response = UserRetrofitService.userRetrofitService.loadUsers(token, currentPage)
val users = response.data.nodes

LoadResult.Page(
Expand All @@ -26,10 +26,10 @@ class UserPagingSource(
}
}

override fun getRefreshKey(state: PagingState<Int, User>): Int? {
override fun getRefreshKey(state: PagingState<Int, ListUserItem>): Int? {
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.greetingcard.model.AuthenticationRequestBody
import com.example.greetingcard.model.ListUserItem
import com.example.greetingcard.model.LoadUserResponse
import com.example.greetingcard.model.NewUserRequest
import com.example.greetingcard.model.User
import com.example.greetingcard.model.UserPagingSource
import com.example.greetingcard.rest.UserRetrofitService
import kotlinx.coroutines.flow.Flow
import retrofit2.await
import retrofit2.HttpException
import java.io.IOException

class UserRepository private constructor() {

Expand All @@ -36,11 +38,11 @@ class UserRepository private constructor() {
token = authToken
Result.success(authToken)
} catch (e: Exception) {
Result.failure(e)
throw Exception("Erro desconhecido ao autenticar usuário: ${e.message}")
}
}

fun loadUsers(): Flow<PagingData<User>> {
fun loadUsers(): Flow<PagingData<ListUserItem>> {
return Pager(
config = PagingConfig(
pageSize = 20,
Expand All @@ -54,7 +56,20 @@ class UserRepository private constructor() {
try {
UserRetrofitService.userRetrofitService.newUser(token, newUserRequest)
} catch (e: Exception) {
throw Exception("Erro ao cadastrar usuário")
throw Exception("Erro desconhecido ao cadastrar usuário: ${e.message}")
}
}


suspend fun loadUserDetail(userId: String): LoadUserResponse {
try {
return UserRetrofitService.userRetrofitService.loadUserDetail(token, userId)
} catch (e: IOException) {
throw Exception("Erro de rede ao carregar usuário: ${e.message}")
} catch (e: HttpException) {
throw Exception("Erro ao carregar usuário: ${e.message()}")
} catch (e: Exception) {
throw Exception("Erro desconhecido ao carregar usuário: ${e.message}")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.example.greetingcard.rest
import com.example.greetingcard.model.AuthenticationRequestBody
import com.example.greetingcard.model.AuthenticationResponse
import com.example.greetingcard.model.LoadListResponse
import com.example.greetingcard.model.LoadUserResponse
import com.example.greetingcard.model.NewUserRequest
import retrofit2.Call
import retrofit2.Retrofit
Expand All @@ -11,6 +12,7 @@ import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST
import retrofit2.http.Path
import retrofit2.http.Query

interface UserRetrofitService {
Expand All @@ -20,9 +22,11 @@ interface UserRetrofitService {
@GET("users")
suspend fun loadUsers(@Header("Authorization") token: String, @Query("offset") offset: Int): LoadListResponse


@POST("users")
suspend fun newUser(@Header("Authorization") token: String, @Body newUserRequest: NewUserRequest)

@GET("users/{id}")
suspend fun loadUserDetail(@Header("Authorization") token: String, @Path("id") userId: String): LoadUserResponse
companion object RetrofitInstance {

private const val BASE_URL = "https://template-onboarding-node-sjz6wnaoia-uc.a.run.app/"
Expand Down
73 changes: 12 additions & 61 deletions app/src/main/java/com/example/greetingcard/view/LoginScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,26 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.greetingcard.view.component.InputFields
import com.example.greetingcard.view.component.ShowErrors
import com.example.greetingcard.viewModel.LoginViewModel

@Composable
fun LoginScreen(navController: NavHostController) {
val viewModel: LoginViewModel = viewModel()
val emailState by viewModel.emailState
val passwordState by viewModel.passwordState
val emailErrorMessages by viewModel.emailErrorMessages
val passwordErrorMessages by viewModel.passwordErrorMessages
val authenticationErrorMessages by viewModel.authenticationErrorMessages
val isLoading by viewModel.isLoading

Scaffold(modifier = Modifier.padding(32.dp)) { innerPadding ->
Column(
Expand All @@ -47,32 +36,32 @@ fun LoginScreen(navController: NavHostController) {
Title()
Spacer(modifier = Modifier.height(48.dp))
InputFields(
emailState,
viewModel.emailState,
"E-mail",
KeyboardType.Email,
onValueChange = { email -> viewModel.updateEmailInput(email) }
)
ShowErrors(emailErrorMessages)
ShowErrors(viewModel.emailErrorMessages)
Spacer(modifier = Modifier.height(36.dp))
InputFields(
passwordState,
viewModel.passwordState,
"Senha",
KeyboardType.Password,
onValueChange = { password -> viewModel.updatePasswordInput(password) },
true
)
ShowErrors(passwordErrorMessages)
ShowErrors(viewModel.passwordErrorMessages)
Spacer(modifier = Modifier.height(36.dp))
if (!isLoading) {
if (!viewModel.isLoading) {
LoginButton(onClick = {
viewModel.validateAndSetEmailErrors()
viewModel.validateAndSetPasswordErrors()
if (emailErrorMessages.isEmpty() && passwordErrorMessages.isEmpty()) {
if (viewModel.emailErrorMessages.isEmpty() && viewModel.passwordErrorMessages.isEmpty()) {
viewModel.authenticateUser(navController)
}
})
}
if (isLoading) {
if (viewModel.isLoading) {
Box(
modifier = Modifier
.fillMaxWidth(),
Expand All @@ -81,59 +70,21 @@ fun LoginScreen(navController: NavHostController) {
CircularProgressIndicator()
}
}
ShowErrors(authenticationErrorMessages)
ShowErrors(viewModel.authenticationErrorMessages)
}
}
}

@Composable
fun Title() {
private fun Title() {
Text(
fontWeight = FontWeight.Bold, fontSize = 24.sp, text = "Bem vindo(a) à Taqtile!"
)
}

@Composable
fun InputFields(
value: String,
title: String,
type: KeyboardType,
onValueChange: (String) -> Unit,
isPassword: Boolean = false
) {
Column() {
Text(text = title)
OutlinedTextField(
value = value,
onValueChange = onValueChange,
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp),
keyboardOptions = KeyboardOptions(
keyboardType = type
),
shape = RoundedCornerShape(16.dp),
visualTransformation = if (isPassword) PasswordVisualTransformation() else VisualTransformation.None
)
}
}

@Composable
fun LoginButton(onClick: () -> Unit) {
private fun LoginButton(onClick: () -> Unit) {
Button(onClick = onClick, modifier = Modifier.fillMaxWidth()) {
Text(fontSize = 20.sp, text = "Entrar")
}
}

@Composable
fun ShowErrors(errorMessages: List<String>) {
if (errorMessages.isNotEmpty()) {
for (error in errorMessages) {
Text(
text = error,
color = Color.Red,
modifier = Modifier.padding(bottom = 8.dp)
)
}
}
}
Loading

0 comments on commit 2582bae

Please sign in to comment.