diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5be48a8..2e2e461 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -23,7 +23,7 @@ android { buildTypes { release { - buildConfigField("String", "BASE_URL", "\"http://192.168.1.13:3000/\"") + buildConfigField("String", "BASE_URL", "\"http://192.168.1.4:3000/\"") isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), @@ -31,7 +31,7 @@ android { ) } debug { - buildConfigField("String", "BASE_URL", "\"http://192.168.1.13:3000/\"") + buildConfigField("String", "BASE_URL", "\"http://192.168.1.4:3000/\"") } } compileOptions { @@ -72,6 +72,8 @@ dependencies { implementation("com.github.bumptech.glide:glide:4.16.0") implementation("androidx.paging:paging-runtime:3.2.1") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") + implementation("de.hdodenhof:circleimageview:3.1.0") + // implementation(libs.hilt.android) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5477aa0..dd10380 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,8 +1,9 @@ + xmlns:tools="http://schemas.android.com/tools"> + + android:name=".ui.product.DetailProductActivity" + android:exported="false" /> + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Category.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Category.kt deleted file mode 100644 index 95fe0bc..0000000 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Category.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.alya.ecommerce_serang.data.api.dto - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class Category( - val id: String, - val image: String, - val title: String -): Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/CategoryItem.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/CategoryItem.kt new file mode 100644 index 0000000..ca0963d --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/CategoryItem.kt @@ -0,0 +1,22 @@ +package com.alya.ecommerce_serang.data.api.dto + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import kotlinx.parcelize.Parcelize + +@Parcelize + +data class CategoryItem( + + @field:SerializedName("image") + val image: String, + + @field:SerializedName("name") + val name: String, + + @field:SerializedName("id") + val id: Int, + + @field:SerializedName("store_type_id") + val storeTypeId: Int +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/DetailProduct.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/DetailProduct.kt index fe2355f..0680a18 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/DetailProduct.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/DetailProduct.kt @@ -14,7 +14,7 @@ data class DetailProduct( val inStock: Int, val price: Double, val rating: Double, - val related: List, + val related: List, val reviews: Int, val title: String, @SerializedName("free_delivery") diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/LoginRequest.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/LoginRequest.kt new file mode 100644 index 0000000..3f98cc8 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/LoginRequest.kt @@ -0,0 +1,8 @@ +package com.alya.ecommerce_serang.data.api.dto + +import com.google.gson.annotations.SerializedName + +data class LoginRequest ( + @SerializedName("emailOrPhone") val email: String, + @SerializedName("password") val password: String, +) \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/OtpRequest.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/OtpRequest.kt new file mode 100644 index 0000000..00f383b --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/OtpRequest.kt @@ -0,0 +1,7 @@ +package com.alya.ecommerce_serang.data.api.dto + +import com.google.gson.annotations.SerializedName + +data class OtpRequest( + @SerializedName("email") val email: String +) \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Product.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Product.kt deleted file mode 100644 index 4af2851..0000000 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Product.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.alya.ecommerce_serang.data.api.dto - - -import com.google.gson.annotations.SerializedName - -data class Product ( - val id: String, - val discount: Double?, - @SerializedName("favorite") - var wishlist: Boolean, - val image: String, - val price: Double, - val rating: Double, - @SerializedName("rating_count") - val ratingCount: Int, - val title: String, -) \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/ProductsItem.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/ProductsItem.kt new file mode 100644 index 0000000..37a5bf2 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/ProductsItem.kt @@ -0,0 +1,49 @@ +package com.alya.ecommerce_serang.data.api.dto + + +import com.google.gson.annotations.SerializedName + +data class ProductsItem( + + @field:SerializedName("store_id") + val storeId: Int, + + @field:SerializedName("image") + val image: String, + + @field:SerializedName("rating") + val rating: String, + + @field:SerializedName("description") + val description: String, + + @field:SerializedName("weight") + val weight: Int, + + @field:SerializedName("is_pre_order") + val isPreOrder: Boolean, + + @field:SerializedName("category_id") + val categoryId: Int, + + @field:SerializedName("price") + val price: String, + + @field:SerializedName("name") + val name: String, + + @field:SerializedName("id") + val id: Int, + + @field:SerializedName("min_order") + val minOrder: Int, + + @field:SerializedName("total_sold") + val totalSold: Int, + + @field:SerializedName("stock") + val stock: Int, + + @field:SerializedName("status") + val status: String +) \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/RegisterRequest.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/RegisterRequest.kt new file mode 100644 index 0000000..650eab3 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/RegisterRequest.kt @@ -0,0 +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?, + @SerializedName("birth_date") val birthDate: String?, + @SerializedName("userimg") val image: String?, + val otp: String? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/AllProductResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/AllProductResponse.kt index f4fd1a5..e45093f 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/AllProductResponse.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/AllProductResponse.kt @@ -1,5 +1,6 @@ package com.alya.ecommerce_serang.data.api.response +import com.alya.ecommerce_serang.data.api.dto.ProductsItem import com.google.gson.annotations.SerializedName data class AllProductResponse( @@ -11,47 +12,4 @@ data class AllProductResponse( val products: List ) -data class ProductsItem( - @field:SerializedName("store_id") - val storeId: Int, - - @field:SerializedName("image") - val image: String, - - @field:SerializedName("rating") - val rating: String, - - @field:SerializedName("description") - val description: String, - - @field:SerializedName("weight") - val weight: Int, - - @field:SerializedName("is_pre_order") - val isPreOrder: Boolean, - - @field:SerializedName("category_id") - val categoryId: Int, - - @field:SerializedName("price") - val price: String, - - @field:SerializedName("name") - val name: String, - - @field:SerializedName("id") - val id: Int, - - @field:SerializedName("min_order") - val minOrder: Int, - - @field:SerializedName("total_sold") - val totalSold: Int, - - @field:SerializedName("stock") - val stock: Int, - - @field:SerializedName("status") - val status: String -) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/CategoryResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/CategoryResponse.kt new file mode 100644 index 0000000..26867ca --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/CategoryResponse.kt @@ -0,0 +1,15 @@ +package com.alya.ecommerce_serang.data.api.response + +import com.alya.ecommerce_serang.data.api.dto.CategoryItem +import com.google.gson.annotations.SerializedName + +data class CategoryResponse( + + @field:SerializedName("Category") + val category: List, + + @field:SerializedName("message") + val message: String +) + + diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/LoginResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/LoginResponse.kt new file mode 100644 index 0000000..58c9206 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/LoginResponse.kt @@ -0,0 +1,15 @@ +package com.alya.ecommerce_serang.data.api.response + +import com.google.gson.annotations.SerializedName + +data class LoginResponse( + + @field:SerializedName("role") + val role: String, + + @field:SerializedName("message") + val message: String, + + @field:SerializedName("accessToken") + val accessToken: String +) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/OtpResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/OtpResponse.kt new file mode 100644 index 0000000..60a87f5 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/OtpResponse.kt @@ -0,0 +1,9 @@ +package com.alya.ecommerce_serang.data.api.response + +import com.google.gson.annotations.SerializedName + +data class OtpResponse( + + @field:SerializedName("message") + val message: String +) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/RegisterResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/RegisterResponse.kt new file mode 100644 index 0000000..1136015 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/RegisterResponse.kt @@ -0,0 +1,42 @@ +package com.alya.ecommerce_serang.data.api.response + +import com.google.gson.annotations.SerializedName + +data class RegisterResponse( + + @field:SerializedName("message") + val message: String, + + @field:SerializedName("user") + val user: User +) + +data class User( + + @field:SerializedName("image") + val image: String, + + @field:SerializedName("password") + val password: String, + + @field:SerializedName("role") + val role: String, + + @field:SerializedName("phone") + val phone: String, + + @field:SerializedName("birth_date") + val birthDate: String, + + @field:SerializedName("name") + val name: String, + + @field:SerializedName("id") + val id: Int, + + @field:SerializedName("email") + val email: String, + + @field:SerializedName("username") + val username: String +) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/StoreResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/StoreResponse.kt new file mode 100644 index 0000000..386de42 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/StoreResponse.kt @@ -0,0 +1,138 @@ +package com.alya.ecommerce_serang.data.api.response + +import com.google.gson.annotations.SerializedName + +data class StoreResponse( + + @field:SerializedName("shipping") + val shipping: List, + + @field:SerializedName("payment") + val payment: List, + + @field:SerializedName("store") + val store: Store, + + @field:SerializedName("message") + val message: String +) + +data class Store( + + @field:SerializedName("approval_reason") + val approvalReason: String, + + @field:SerializedName("store_status") + val storeStatus: String, + + @field:SerializedName("sppirt") + val sppirt: String, + + @field:SerializedName("user_name") + val userName: String, + + @field:SerializedName("nib") + val nib: String, + + @field:SerializedName("latitude") + val latitude: String, + + @field:SerializedName("store_type_id") + val storeTypeId: Int, + + @field:SerializedName("balance") + val balance: String, + + @field:SerializedName("street") + val street: String, + + @field:SerializedName("store_name") + val storeName: String, + + @field:SerializedName("user_phone") + val userPhone: String, + + @field:SerializedName("halal") + val halal: String, + + @field:SerializedName("id") + val id: Int, + + @field:SerializedName("email") + val email: String, + + @field:SerializedName("store_image") + val storeImage: Any, + + @field:SerializedName("longitude") + val longitude: String, + + @field:SerializedName("store_id") + val storeId: Int, + + @field:SerializedName("is_store_location") + val isStoreLocation: Boolean, + + @field:SerializedName("ktp") + val ktp: String, + + @field:SerializedName("approval_status") + val approvalStatus: String, + + @field:SerializedName("npwp") + val npwp: String, + + @field:SerializedName("store_type") + val storeType: String, + + @field:SerializedName("is_on_leave") + val isOnLeave: Boolean, + + @field:SerializedName("user_id") + val userId: Int, + + @field:SerializedName("province_id") + val provinceId: Int, + + @field:SerializedName("phone") + val phone: String, + + @field:SerializedName("subdistrict") + val subdistrict: String, + + @field:SerializedName("recipient") + val recipient: String, + + @field:SerializedName("detail") + val detail: String, + + @field:SerializedName("postal_code") + val postalCode: String, + + @field:SerializedName("store_description") + val storeDescription: String, + + @field:SerializedName("city_id") + val cityId: Int +) + +data class ShippingItem( + + @field:SerializedName("courier") + val courier: String +) + +data class PaymentItem( + + @field:SerializedName("qris_image") + val qrisImage: String, + + @field:SerializedName("bank_num") + val bankNum: String, + + @field:SerializedName("bank_name") + val bankName: String, + + @field:SerializedName("id") + val id: Int +) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiConfig.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiConfig.kt index 3a2e8f4..e8ddcb0 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiConfig.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiConfig.kt @@ -1,24 +1,52 @@ package com.alya.ecommerce_serang.data.api.retrofit import com.alya.ecommerce_serang.BuildConfig +import com.alya.ecommerce_serang.utils.AuthInterceptor +import com.alya.ecommerce_serang.utils.SessionManager import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory class ApiConfig { - companion object{ - fun getApiService(): ApiService { - val loggingInterceptor = - HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY) + companion object { + fun getApiService(tokenManager: SessionManager): ApiService { + + val loggingInterceptor = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + + val authInterceptor = AuthInterceptor(tokenManager) + val client = OkHttpClient.Builder() .addInterceptor(loggingInterceptor) + .addInterceptor(authInterceptor) .build() + val retrofit = Retrofit.Builder() .baseUrl(BuildConfig.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build() + + return retrofit.create(ApiService::class.java) + } + + fun getUnauthenticatedApiService(): ApiService { + val loggingInterceptor = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + + val client = OkHttpClient.Builder() + .addInterceptor(loggingInterceptor) + .build() + + val retrofit = Retrofit.Builder() + .baseUrl(BuildConfig.BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .client(client) + .build() + return retrofit.create(ApiService::class.java) } } diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt index 711291d..0d4a120 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt @@ -1,22 +1,50 @@ package com.alya.ecommerce_serang.data.api.retrofit +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.AllProductResponse +import com.alya.ecommerce_serang.data.api.response.CategoryResponse +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.response.ProductResponse +import com.alya.ecommerce_serang.data.api.response.RegisterResponse +import com.alya.ecommerce_serang.data.api.response.StoreResponse import retrofit2.Call +import retrofit2.Response +import retrofit2.http.Body import retrofit2.http.GET -import retrofit2.http.Header +import retrofit2.http.POST import retrofit2.http.Path interface ApiService { - @GET("product") - fun getAllProduct( - @Header("Authorization") token: String = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzEsIm5hbWUiOiJhbHlhIiwiZW1haWwiOiJha3VuYmVsYWphci5hbHlhQGdtYWlsLmNvbSIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzM4NDg0OTc0LCJleHAiOjE3NDEwNzY5NzR9.0JyXJQ_6CKiZEi0gvk1gcn-0ILu3a9lOr3HqjhJXbBE" - ): Call + @POST("registeruser") + suspend fun register ( + @Body registerRequest: RegisterRequest + ): Response + @POST("otp") + suspend fun getOTP( + @Body otpRequest: OtpRequest + ):OtpResponse + + @POST("login") + suspend fun login( + @Body loginRequest: LoginRequest + ): Response + + @GET("category") + suspend fun allCategory( + ): Response + + @GET("product") + suspend fun getAllProduct(): Response @GET("product/detail/{id}") fun getDetailProduct ( - @Header("Authorization") token: String, @Path("id") productId: Int ): Call + + @GET("mystore") + fun getStore (): Call } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt index 1f73cbd..cfe5e8a 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt @@ -1,7 +1,8 @@ package com.alya.ecommerce_serang.data.repository import android.util.Log -import com.alya.ecommerce_serang.data.api.response.ProductsItem +import com.alya.ecommerce_serang.data.api.dto.CategoryItem +import com.alya.ecommerce_serang.data.api.dto.ProductsItem import com.alya.ecommerce_serang.data.api.retrofit.ApiService import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -11,25 +12,41 @@ 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) { - Result.success(response.body()?.products ?: emptyList()) + // Return a Result.Success with the list of products + + Result.Success(response.body()?.products ?: emptyList()) + } else { - Result.failure(Exception("Failed to fetch products")) + // Return a Result.Error with a custom Exception + Result.Error(Exception("Failed to fetch products. Code: ${response.code()}")) } } catch (e: Exception) { - Result.failure(e) + // Return a Result.Error with the exception caught + Result.Error(e) } } -// suspend fun getCategories():List -// -// fun getProducts(query: ProductQuery) : Flow> -// fun getRecentSearchs(): Flow> -// suspend fun clearRecents() -// suspend fun addRecents(search:String) -// suspend fun getProduct(id:String):DetailProduct + + suspend fun getAllCategories(): Result> = + withContext(Dispatchers.IO) { + try { + Log.d("Categories", "Attempting to fetch categories") + val response = apiService.allCategory() + + if (response.isSuccessful) { + val categories = response.body()?.category ?: emptyList() + Log.d("Categories", "Fetched categories: $categories") + categories.forEach { Log.d("Category Image", "Category: ${it.name}, Image: ${it.image}") } + Result.Success(categories) + } else { + Result.Error(Exception("Failed to fetch categories. Code: ${response.code()}")) + } + } catch (e: Exception) { + Log.e("Categories", "Error fetching categories", e) + Result.Error(e) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt new file mode 100644 index 0000000..335cea9 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt @@ -0,0 +1,51 @@ +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 + +class UserRepository(private val apiService: ApiService) { + + suspend fun requestOtpRep(email: String): OtpResponse { + +// fun requestOtpRep(email: String): Result { + + return apiService.getOTP(OtpRequest(email)) + + } + + suspend fun registerUser(request: RegisterRequest): String { + val response = apiService.register(request) // API call + + if (response.isSuccessful) { + val responseBody = response.body() ?: throw Exception("Empty response body") + return responseBody.message // Get the message from RegisterResponse + } else { + throw Exception("Registration failed: ${response.errorBody()?.string()}") + } + } + + suspend fun login(email: String, password: String): Result { + 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 { + data class Success(val data: T) : Result() + data class Error(val exception: Throwable) : Result() + object Loading : Result() +} \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/MainActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/MainActivity.kt index 9450c13..3877327 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/MainActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/MainActivity.kt @@ -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() diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginActivity.kt new file mode 100644 index 0000000..9ae19c4 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginActivity.kt @@ -0,0 +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 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() + + 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 + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginViewModel.kt new file mode 100644 index 0000000..8b4c27d --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginViewModel.kt @@ -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>() + val loginState: LiveData> 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 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/OtpBottomsheetDialog.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/OtpBottomsheetDialog.kt new file mode 100644 index 0000000..c20b7f9 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/OtpBottomsheetDialog.kt @@ -0,0 +1,41 @@ +package com.alya.ecommerce_serang.ui.auth + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import android.widget.Toast +import com.alya.ecommerce_serang.R +import com.alya.ecommerce_serang.data.api.dto.RegisterRequest +import com.google.android.material.bottomsheet.BottomSheetDialogFragment + +class OtpBottomSheetDialog( + private val userData: RegisterRequest, // Store user data + private val onRegister: (RegisterRequest) -> Unit) + : BottomSheetDialogFragment() { + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.dialog_otp, container, false) + + val etOtp = view.findViewById(R.id.etOtp) + val btnSubmit = view.findViewById