mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-10 17:32:22 +00:00
login success
This commit is contained in:
@ -23,7 +23,7 @@ android {
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
buildConfigField("String", "BASE_URL", "\"http://192.168.1.6:3000/\"")
|
||||
buildConfigField("String", "BASE_URL", "\"http://192.168.1.3:3000/\"")
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
@ -31,7 +31,7 @@ android {
|
||||
)
|
||||
}
|
||||
debug {
|
||||
buildConfigField("String", "BASE_URL", "\"http://192.168.1.6:3000/\"")
|
||||
buildConfigField("String", "BASE_URL", "\"http://192.168.1.3:3000/\"")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.alya.ecommerce_serang.data.api.dto
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class LoginRequest (
|
||||
val email: String,
|
||||
val password: String,
|
||||
@SerializedName("emailOrPhone") val email: String,
|
||||
@SerializedName("password") val password: String,
|
||||
)
|
@ -1,12 +1,14 @@
|
||||
package com.alya.ecommerce_serang.data.api.dto
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class RegisterRequest (
|
||||
val name: String?,
|
||||
val email: String?,
|
||||
val password: String?,
|
||||
val username: String?,
|
||||
val phone: String?,
|
||||
val birthDate: String?,
|
||||
val image: String?,
|
||||
@SerializedName("birth_date") val birthDate: String?,
|
||||
@SerializedName("userimg") val image: String?,
|
||||
val otp: String? = null
|
||||
)
|
@ -11,6 +11,7 @@ import retrofit2.converter.gson.GsonConverterFactory
|
||||
class ApiConfig {
|
||||
companion object {
|
||||
fun getApiService(tokenManager: SessionManager): ApiService {
|
||||
|
||||
val loggingInterceptor = HttpLoggingInterceptor().apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
}
|
||||
|
@ -28,12 +28,12 @@ interface ApiService {
|
||||
):OtpResponse
|
||||
|
||||
@POST("login")
|
||||
fun login(
|
||||
suspend fun login(
|
||||
@Body loginRequest: LoginRequest
|
||||
): Call<LoginResponse>
|
||||
): Response<LoginResponse>
|
||||
|
||||
@GET("product")
|
||||
fun getAllProduct(): Call<AllProductResponse>
|
||||
suspend fun getAllProduct(): Response<AllProductResponse>
|
||||
|
||||
@GET("product/detail/{id}")
|
||||
fun getDetailProduct (
|
||||
|
@ -11,10 +11,7 @@ class ProductRepository(private val apiService: ApiService) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
Log.d("ProductRepository", "Attempting to fetch products")
|
||||
val response = apiService.getAllProduct().execute()
|
||||
Log.d("ProductRepository", "Response received. Success: ${response.isSuccessful}")
|
||||
Log.d("ProductRepository", "Response code: ${response.code()}")
|
||||
Log.d("ProductRepository", "Response message: ${response.message()}")
|
||||
val response = apiService.getAllProduct()
|
||||
|
||||
if (response.isSuccessful) {
|
||||
// Return a Result.Success with the list of products
|
||||
@ -28,4 +25,8 @@ class ProductRepository(private val apiService: ApiService) {
|
||||
Result.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
// suspend fun getUserData(): Response<UserResponse> {
|
||||
// return apiService.getProtectedData()
|
||||
// }
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
package com.alya.ecommerce_serang.data.repository
|
||||
|
||||
import com.alya.ecommerce_serang.data.api.dto.LoginRequest
|
||||
import com.alya.ecommerce_serang.data.api.dto.OtpRequest
|
||||
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
|
||||
import com.alya.ecommerce_serang.data.api.response.LoginResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.OtpResponse
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
||||
|
||||
@ -25,6 +27,21 @@ class UserRepository(private val apiService: ApiService) {
|
||||
throw Exception("Registration failed: ${response.errorBody()?.string()}")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun login(email: String, password: String): Result<LoginResponse> {
|
||||
return try {
|
||||
val response = apiService.login(LoginRequest(email, password))
|
||||
if (response.isSuccessful) {
|
||||
response.body()?.let {
|
||||
Result.Success(it)
|
||||
} ?: Result.Error(Exception("Login response is empty"))
|
||||
} else {
|
||||
Result.Error(Exception(response.errorBody()?.string() ?: "Unknown error"))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Result.Error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Result<out T> {
|
||||
|
@ -6,11 +6,16 @@ import androidx.core.view.isVisible
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
||||
import com.alya.ecommerce_serang.databinding.ActivityMainBinding
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
|
||||
//@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private lateinit var apiService: ApiService
|
||||
private lateinit var sessionManager: SessionManager
|
||||
private val navController by lazy {
|
||||
(supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController
|
||||
}
|
||||
@ -19,6 +24,9 @@ class MainActivity : AppCompatActivity() {
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
sessionManager = SessionManager(this)
|
||||
apiService = ApiConfig.getApiService(sessionManager) // Inject SessionManager
|
||||
|
||||
setupBottomNavigation()
|
||||
observeDestinationChanges()
|
||||
|
||||
|
@ -1,21 +1,75 @@
|
||||
package com.alya.ecommerce_serang.ui.auth
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||
import com.alya.ecommerce_serang.databinding.ActivityLoginBinding
|
||||
import com.alya.ecommerce_serang.ui.MainActivity
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
|
||||
class LoginActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityLoginBinding
|
||||
private val loginViewModel: LoginViewModel by viewModels{
|
||||
BaseViewModelFactory {
|
||||
val apiService = ApiConfig.getUnauthenticatedApiService()
|
||||
val userRepository = UserRepository(apiService)
|
||||
LoginViewModel(userRepository)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContentView(R.layout.activity_login)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
|
||||
binding = ActivityLoginBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
setupListeners()
|
||||
observeLoginState()
|
||||
}
|
||||
|
||||
private fun setupListeners() {
|
||||
binding.btnLogin.setOnClickListener {
|
||||
val email = binding.etLoginEmail.text.toString()
|
||||
val password = binding.etLoginPassword.text.toString()
|
||||
|
||||
if (email.isEmpty() || password.isEmpty()) {
|
||||
Toast.makeText(this, "Please fill in all fields", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
loginViewModel.login(email, password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeLoginState() {
|
||||
loginViewModel.loginState.observe(this) { result ->
|
||||
when (result) {
|
||||
is com.alya.ecommerce_serang.data.repository.Result.Success -> {
|
||||
val accessToken = result.data.accessToken
|
||||
|
||||
val sessionManager = SessionManager(this)
|
||||
sessionManager.saveToken(accessToken)
|
||||
|
||||
Toast.makeText(this, "Login Successful", Toast.LENGTH_SHORT).show()
|
||||
|
||||
startActivity(Intent(this, MainActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
|
||||
Toast.makeText(this, "Login Failed: ${result.exception.message}", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
is Result.Loading -> {
|
||||
// Show loading state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.alya.ecommerce_serang.ui.auth
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.alya.ecommerce_serang.data.api.response.LoginResponse
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LoginViewModel(private val repository: UserRepository) : ViewModel() {
|
||||
private val _loginState = MutableLiveData<com.alya.ecommerce_serang.data.repository.Result<LoginResponse>>()
|
||||
val loginState: LiveData<Result<LoginResponse>> get() = _loginState
|
||||
|
||||
fun login(email: String, password: String) {
|
||||
viewModelScope.launch {
|
||||
_loginState.value = com.alya.ecommerce_serang.data.repository.Result.Loading
|
||||
val result = repository.login(email, password)
|
||||
_loginState.value = result
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.alya.ecommerce_serang.ui.auth
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
@ -32,9 +33,6 @@ class RegisterActivity : AppCompatActivity() {
|
||||
// Observe OTP state
|
||||
observeOtpState()
|
||||
|
||||
// Observe Register state
|
||||
observeRegisterState()
|
||||
|
||||
binding.btnSignup.setOnClickListener {
|
||||
// Retrieve values inside the click listener (so we get latest input)
|
||||
val birthDate = binding.etBirthDate.text.toString()
|
||||
@ -74,6 +72,14 @@ class RegisterActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Observe Register state
|
||||
observeRegisterState()
|
||||
}
|
||||
|
||||
binding.tvLoginAlt.setOnClickListener{
|
||||
val intent = Intent(this, LoginActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
}
|
||||
@ -110,6 +116,8 @@ class RegisterActivity : AppCompatActivity() {
|
||||
// Hide loading indicator and show success message
|
||||
binding.progressBarRegister.visibility = android.view.View.GONE
|
||||
Toast.makeText(this, result.data, Toast.LENGTH_SHORT).show()
|
||||
val intent = Intent(this, LoginActivity::class.java)
|
||||
startActivity(intent)
|
||||
// Navigate to another screen if needed
|
||||
}
|
||||
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
|
||||
|
@ -25,6 +25,8 @@ class HomeFragment : Fragment() {
|
||||
|
||||
private var _binding: FragmentHomeBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private var productAdapter: HorizontalProductAdapter? = null
|
||||
private lateinit var sessionManager: SessionManager
|
||||
private val viewModel: HomeViewModel by viewModels {
|
||||
BaseViewModelFactory {
|
||||
val apiService = ApiConfig.getApiService(sessionManager)
|
||||
@ -32,18 +34,18 @@ class HomeFragment : Fragment() {
|
||||
HomeViewModel(productRepository)
|
||||
}
|
||||
}
|
||||
private var productAdapter: HorizontalProductAdapter? = null
|
||||
private lateinit var sessionManager: SessionManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
sessionManager = SessionManager(requireContext())
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||
sessionManager = SessionManager(requireContext()) // Initialize SessionManager
|
||||
|
||||
return binding.root
|
||||
return _binding!!.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
@ -17,7 +17,6 @@ class HomeViewModel (
|
||||
private val _uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
|
||||
val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
|
||||
|
||||
|
||||
init {
|
||||
loadProducts()
|
||||
}
|
||||
@ -26,20 +25,16 @@ class HomeViewModel (
|
||||
viewModelScope.launch {
|
||||
_uiState.value = HomeUiState.Loading
|
||||
|
||||
productRepository.getAllProducts().let { result ->
|
||||
when (result) {
|
||||
is Result.Success -> {
|
||||
// Handle the success case
|
||||
_uiState.value = HomeUiState.Success(result.data) // result.data contains the list of products
|
||||
}
|
||||
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
|
||||
// Handle the error case
|
||||
_uiState.value = HomeUiState.Error(result.exception.message ?: "Unknown error")
|
||||
Log.e("HomeViewModel", "Failed to fetch products", result.exception)
|
||||
}
|
||||
com.alya.ecommerce_serang.data.repository.Result.Loading -> {
|
||||
// Optionally handle the loading state if needed
|
||||
}
|
||||
when (val result = productRepository.getAllProducts()) {
|
||||
is Result.Success -> {
|
||||
_uiState.value = HomeUiState.Success(result.data)
|
||||
}
|
||||
is Result.Error -> {
|
||||
_uiState.value = HomeUiState.Error(result.exception.message ?: "Unknown error")
|
||||
Log.e("HomeViewModel", "Failed to fetch products", result.exception)
|
||||
}
|
||||
is Result.Loading-> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,6 +44,23 @@ class HomeViewModel (
|
||||
fun retry() {
|
||||
loadProducts()
|
||||
}
|
||||
|
||||
// private fun fetchUserData() {
|
||||
// viewModelScope.launch {
|
||||
// try {
|
||||
// val response = apiService.getProtectedData() // Example API request
|
||||
// if (response.isSuccessful) {
|
||||
// val data = response.body()
|
||||
// Log.d("HomeFragment", "User Data: $data")
|
||||
// // Update UI with data
|
||||
// } else {
|
||||
// Log.e("HomeFragment", "Error: ${response.message()}")
|
||||
// }
|
||||
// } catch (e: Exception) {
|
||||
// Log.e("HomeFragment", "Exception: ${e.message}")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
sealed class HomeUiState {
|
||||
|
@ -12,7 +12,7 @@ class SessionManager(context: Context) {
|
||||
private const val USER_TOKEN = "user_token"
|
||||
}
|
||||
|
||||
fun saveAuthToken(token: String) {
|
||||
fun saveToken(token: String) {
|
||||
val editor = sharedPreferences.edit()
|
||||
editor.putString(USER_TOKEN, token)
|
||||
editor.apply()
|
||||
|
@ -75,6 +75,7 @@
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/login"
|
||||
|
Reference in New Issue
Block a user