diff --git a/.idea/other.xml b/.idea/other.xml new file mode 100644 index 0000000..22069ff --- /dev/null +++ b/.idea/other.xml @@ -0,0 +1,549 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2ae92ff..df69c67 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 { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4e96ec6..c4e9461 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,8 +1,9 @@ + xmlns:tools="http://schemas.android.com/tools"> + + tools:targetApi="31"> + @@ -41,14 +45,26 @@ android:name=".ui.profile.mystore.TokoSayaActivity" android:exported="false" /> + 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/model/Product.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/ProductsItem.kt similarity index 68% rename from app/src/main/java/com/alya/ecommerce_serang/data/model/Product.kt rename to app/src/main/java/com/alya/ecommerce_serang/data/api/dto/ProductsItem.kt index a5f79ea..37a5bf2 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/model/Product.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/ProductsItem.kt @@ -1,8 +1,9 @@ -package com.alya.ecommerce_serang.data.model +package com.alya.ecommerce_serang.data.api.dto + import com.google.gson.annotations.SerializedName -data class Product( +data class ProductsItem( @field:SerializedName("store_id") val storeId: Int, @@ -19,23 +20,20 @@ data class Product( @field:SerializedName("weight") val weight: Int, - @field:SerializedName("product_name") - val productName: String, - @field:SerializedName("is_pre_order") val isPreOrder: Boolean, - @field:SerializedName("duration") - val duration: Any, - @field:SerializedName("category_id") val categoryId: Int, @field:SerializedName("price") val price: String, - @field:SerializedName("product_id") - val productId: Int, + @field:SerializedName("name") + val name: String, + + @field:SerializedName("id") + val id: Int, @field:SerializedName("min_order") val minOrder: Int, @@ -46,6 +44,6 @@ data class Product( @field:SerializedName("stock") val stock: Int, - @field:SerializedName("product_category") - val productCategory: String + @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/dto/UserProfile.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/UserProfile.kt new file mode 100644 index 0000000..8a0a173 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/UserProfile.kt @@ -0,0 +1,30 @@ +package com.alya.ecommerce_serang.data.api.dto + +import com.google.gson.annotations.SerializedName + +data class UserProfile( + + @field:SerializedName("image") + val image: String? = null, + + @field:SerializedName("role") + val role: String, + + @field:SerializedName("user_id") + val userId: Int, + + @field:SerializedName("phone") + val phone: String, + + @field:SerializedName("birth_date") + val birthDate: String, + + @field:SerializedName("name") + val name: String, + + @field:SerializedName("email") + val email: String, + + @field:SerializedName("username") + val username: String +) \ 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/AllStoreResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/AllStoreResponse.kt new file mode 100644 index 0000000..4d2f860 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/AllStoreResponse.kt @@ -0,0 +1,33 @@ +package com.alya.ecommerce_serang.data.api.response + +import com.google.gson.annotations.SerializedName + +data class AllStoreResponse( + + @field:SerializedName("store") + val store: AllStore, + + @field:SerializedName("message") + val message: String +) + +data class AllStore( + + @field:SerializedName("store_name") + val storeName: String, + + @field:SerializedName("description") + val description: String, + + @field:SerializedName("store_type") + val storeType: String, + + @field:SerializedName("store_location") + val storeLocation: String, + + @field:SerializedName("store_image") + val storeImage: Any, + + @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/DetailStoreProductResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/DetailStoreProductResponse.kt new file mode 100644 index 0000000..4f83751 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/DetailStoreProductResponse.kt @@ -0,0 +1,33 @@ +package com.alya.ecommerce_serang.data.api.response + +import com.google.gson.annotations.SerializedName + +data class DetailStoreProductResponse( + + @field:SerializedName("store") + val store: StoreProduct, + + @field:SerializedName("message") + val message: String +) + +data class StoreProduct( + + @field:SerializedName("store_name") + val storeName: String, + + @field:SerializedName("description") + val description: String, + + @field:SerializedName("store_type") + val storeType: String, + + @field:SerializedName("store_location") + val storeLocation: String, + + @field:SerializedName("store_image") + val storeImage: Any, + + @field:SerializedName("status") + val status: 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/ProductResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ProductResponse.kt index 26b1130..448ad92 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ProductResponse.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ProductResponse.kt @@ -17,7 +17,7 @@ data class Product( val storeId: Int, @field:SerializedName("image") - val image: String, + val image: String? = null, @field:SerializedName("rating") val rating: String, @@ -35,7 +35,7 @@ data class Product( val isPreOrder: Boolean, @field:SerializedName("duration") - val duration: Any, + val duration: Any?, @field:SerializedName("category_id") val categoryId: Int, diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ProfileResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ProfileResponse.kt new file mode 100644 index 0000000..d9fe08d --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ProfileResponse.kt @@ -0,0 +1,15 @@ +package com.alya.ecommerce_serang.data.api.response + +import com.alya.ecommerce_serang.data.api.dto.UserProfile +import com.google.gson.annotations.SerializedName + +data class ProfileResponse( + + @field:SerializedName("message") + val message: String, + + @field:SerializedName("user") + val user: UserProfile +) + + 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/ReviewProductResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ReviewProductResponse.kt new file mode 100644 index 0000000..f9a927c --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ReviewProductResponse.kt @@ -0,0 +1,39 @@ +package com.alya.ecommerce_serang.data.api.response + +import com.google.gson.annotations.SerializedName + +data class ReviewProductResponse( + + @field:SerializedName("reviews") + val reviews: List, + + @field:SerializedName("message") + val message: String +) + +data class ReviewsItem( + + @field:SerializedName("order_item_id") + val orderItemId: Int, + + @field:SerializedName("review_date") + val reviewDate: String, + + @field:SerializedName("user_image") + val userImage: String? = null, + + @field:SerializedName("product_id") + val productId: Int, + + @field:SerializedName("rating") + val rating: Int, + + @field:SerializedName("review_text") + val reviewText: String, + + @field:SerializedName("product_name") + val productName: 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..5cf478a 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,67 @@ 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.DetailStoreProductResponse +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.ProfileResponse +import com.alya.ecommerce_serang.data.api.response.RegisterResponse +import com.alya.ecommerce_serang.data.api.response.ReviewProductResponse +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/review/{id}") + suspend fun getProductReview( + @Path("id") productId: Int + ): Response @GET("product/detail/{id}") - fun getDetailProduct ( - @Header("Authorization") token: String, + suspend fun getDetailProduct ( @Path("id") productId: Int - ): Call + ): Response + + @GET("profile") + suspend fun getUserProfile(): Response + + @GET("store/detail/{id}") + suspend fun getDetailStore ( + @Path("id") storeId: Int + ): Response + + + @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..519b5d4 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,10 @@ 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.response.ProductResponse +import com.alya.ecommerce_serang.data.api.response.ReviewsItem import com.alya.ecommerce_serang.data.api.retrofit.ApiService import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -11,25 +14,84 @@ 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 + Log.e("ProductRepository", "Error: ${response.errorBody()?.string()}") + 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 + + suspend fun fetchProductDetail(productId: Int): ProductResponse? { + return try { + val response = apiService.getDetailProduct(productId) + if (response.isSuccessful) { + response.body() + } else { + Log.e("ProductRepository", "Error: ${response.errorBody()?.string()}") + null + } + } catch (e: Exception) { + null + } + } + + 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) + } + } + + suspend fun fetchProductReview(productId: Int): List? { + return try { + val response = apiService.getProductReview(productId) + if (response.isSuccessful) { + response.body()?.reviews // Ambil daftar review dari response + } else { + Log.e("ProductRepository", "Error: ${response.errorBody()?.string()}") + null + } + } catch (e: Exception) { + null + } + } +} + +// suspend fun fetchStoreDetail(storeId: Int): Store? { +// return try { +// val response = apiService.getStore(storeId) +// if (response.isSucessful) { +// response.body()?.store +// } else { +// Log.e("ProductRepository", "Error: ${response.errorBody()?.string()}") // -// 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 +// null +// } +// } catch (e: Exception) { +// null +// } +// } \ 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..0977624 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt @@ -0,0 +1,69 @@ +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.dto.UserProfile +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) + } + } + + suspend fun fetchUserProfile(): Result { + return try { + val response = apiService.getUserProfile() + if (response.isSuccessful) { + response.body()?.user?.let { + Result.Success(it) // ✅ Returning only UserProfile + } ?: Result.Error(Exception("User data not found")) + } else { + Result.Error(Exception("Error fetching profile: ${response.code()}")) + } + } 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