diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5be48a8..724cb49 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.6: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.6: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 e00fc08..8986548 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ - + + tools:targetApi="31"> - @@ -28,6 +25,20 @@ + + + + + + \ No newline at end of file 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..bcf9afb --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/LoginRequest.kt @@ -0,0 +1,6 @@ +package com.alya.ecommerce_serang.data.api.dto + +data class LoginRequest ( + val email: String, + 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/RegisterRequest.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/RegisterRequest.kt new file mode 100644 index 0000000..0e38c12 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/RegisterRequest.kt @@ -0,0 +1,12 @@ +package com.alya.ecommerce_serang.data.api.dto + +data class RegisterRequest ( + val name: String?, + val email: String?, + val password: String?, + val username: String?, + val phone: String?, + val birthDate: String?, + 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/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..43720e3 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,51 @@ 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 02e6bd2..ca78eab 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,28 +1,45 @@ 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.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") + fun login( + @Body loginRequest: LoginRequest + ): Call + + @GET("product") + fun getAllProduct(): Call @GET("product/detail/{id}") fun getDetailProduct ( - @Header("Authorization") token: String, @Path("id") productId: Int ): Call @GET("mystore") - fun getStore ( - @Header("Authorization") token: String = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzEsIm5hbWUiOiJhbHlhIiwiZW1haWwiOiJha3VuYmVsYWphci5hbHlhQGdtYWlsLmNvbSIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzM4NDg0OTc0LCJleHAiOjE3NDEwNzY5NzR9.0JyXJQ_6CKiZEi0gvk1gcn-0ILu3a9lOr3HqjhJXbBE" - ): Call + 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..47f561c 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 @@ -17,19 +17,15 @@ class ProductRepository(private val apiService: ApiService) { Log.d("ProductRepository", "Response message: ${response.message()}") 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 } \ 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..e7e57ac --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt @@ -0,0 +1,34 @@ +package com.alya.ecommerce_serang.data.repository + +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.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()}") + } + } +} + +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/auth/LoginActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginActivity.kt new file mode 100644 index 0000000..673762e --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginActivity.kt @@ -0,0 +1,21 @@ +package com.alya.ecommerce_serang.ui.auth + +import android.os.Bundle +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import com.alya.ecommerce_serang.R + +class LoginActivity : AppCompatActivity() { + 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 + } + } +} \ 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