Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package com.niyaj.common.tags

object CategoryTestTags {

const val CATEGORY_SCREEN_TITLE = "Categories"
const val CATEGORY_NOT_AVAILABLE = "Category Not Available"
const val CATEGORY_SCREEN_TITLE = "Dish Categories"
const val CATEGORY_NOT_AVAILABLE = "Dish Category Not Available"
const val CATEGORY_SEARCH_PLACEHOLDER = "Search for Categories..."

const val ADD_EDIT_CATEGORY_BTN = "AddEdit Category Button"
Expand All @@ -12,8 +12,8 @@ object CategoryTestTags {
const val UPDATE_CATEGORY = "Update Category"
const val ADD_EDIT_CATEGORY_SCREEN = "AddUpdate Category Screen"

const val CATEGORY_NAME_FIELD = "Category Name"
const val CATEGORY_NAME_ERROR = "Category Name Error"
const val CATEGORY_NAME_FIELD = "Dish Category Name"
const val CATEGORY_NAME_ERROR = "Dish Category Name Error"

const val CATEGORY_AVAILABLE_SWITCH = "Category Available Switch"

Expand Down
50 changes: 25 additions & 25 deletions core/common/src/main/java/com/niyaj/common/tags/ProductTestTags.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,48 @@ package com.niyaj.common.tags

object ProductTestTags {

const val PRODUCT_SCREEN_TITLE = "Products"
const val PRODUCT_NOT_AVAILABLE = "Product Not Available"
const val NO_ITEMS_IN_PRODUCT = "Products Not Found"
const val PRODUCT_SEARCH_PLACEHOLDER = "Search for Product..."
const val PRODUCT_SCREEN_TITLE = "Dishes"
const val PRODUCT_NOT_AVAILABLE = "Dish Not Available"
const val NO_ITEMS_IN_PRODUCT = "Dishes Not Found"
const val PRODUCT_SEARCH_PLACEHOLDER = "Search for Dish..."

const val CREATE_NEW_PRODUCT = "Create New Product"
const val EDIT_PRODUCT = "Update Product"
const val CREATE_NEW_PRODUCT = "Create New Dish"
const val EDIT_PRODUCT = "Update Dish"

const val PRODUCT_NAME_FIELD = "Product Name"
const val PRODUCT_NAME_ERROR = "Product NameError"
const val PRODUCT_NAME_FIELD = "Dish Name"
const val PRODUCT_NAME_ERROR = "Dish NameError"

const val PRODUCT_CATEGORY_FIELD = "Category Name"
const val PRODUCT_CATEGORY_FIELD = "Dish Category"
const val PRODUCT_CATEGORY_ERROR = "CategoryError"

const val PRODUCT_PRICE_FIELD = "Product Price"
const val PRODUCT_PRICE_ERROR = "Product PriceError"
const val PRODUCT_PRICE_FIELD = "Dish Price"
const val PRODUCT_PRICE_ERROR = "Dish PriceError"

const val PRODUCT_AVAILABILITY_FIELD = "Product Availability"
const val PRODUCT_AVAILABILITY_FIELD = "Dish Availability"

const val ADD_EDIT_PRODUCT_BUTTON = "AddEdit ProductButton"
const val ADD_EDIT_PRODUCT_BUTTON = "AddEdit DishButton"

const val PRODUCT_NAME_EMPTY_ERROR = "Product name must not be empty"
const val PRODUCT_NAME_LENGTH_ERROR = "Product name must be more than 4 characters"
const val PRODUCT_NAME_ALREADY_EXIST_ERROR = "Product name already exists."
const val PRODUCT_NAME_EMPTY_ERROR = "Dish name must not be empty"
const val PRODUCT_NAME_LENGTH_ERROR = "Dish name must be more than 4 characters"
const val PRODUCT_NAME_ALREADY_EXIST_ERROR = "Dish name already exists."

const val PRODUCT_PRICE_EMPTY_ERROR = "Product price must not be empty."
const val PRODUCT_PRICE_LENGTH_ERROR = "Product price must be at least 10 rupees."
const val PRODUCT_PRICE_EMPTY_ERROR = "Dish price must not be empty."
const val PRODUCT_PRICE_LENGTH_ERROR = "Dish price must be at least 10 rupees."

const val PRODUCT_CATEGORY_EMPTY_ERROR = "Product category must not be empty."
const val PRODUCT_CATEGORY_EMPTY_ERROR = "Dish category must not be empty."

const val DELETE_PRODUCT_TITLE = "Delete Product?"
const val DELETE_PRODUCT_MESSAGE = "Are you sure to delete these products?"
const val DELETE_PRODUCT_TITLE = "Delete Dish?"
const val DELETE_PRODUCT_MESSAGE = "Are you sure to delete these dishes?"

const val PRODUCT_TAG = "Product-"
const val PRODUCT_TAG = "Dish-"

const val EXPORT_PRODUCTS_TITLE = "Export Products"
const val EXPORT_PRODUCTS_TITLE = "Export Dishes"

const val IMPORT_PRODUCTS_TITLE = "Import Products"
const val IMPORT_PRODUCTS_TITLE = "Import Dishes"
const val IMPORT_PRODUCTS_NOTE_TEXT = "Make sure to open products.json file."

const val INCREASE_PRODUCTS_TITLE = "Increase Price"
const val INCREASE_PRODUCTS_TEXT_FIELD = "Product Price"
const val INCREASE_PRODUCTS_TEXT_FIELD = "Dish Price"

const val DECREASE_PRODUCTS_TITLE = "Decrease Price"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.niyaj.common.tags.CategoryTestTags.CATEGORY_NAME_EMPTY_ERROR
import com.niyaj.common.tags.CategoryTestTags.CATEGORY_NAME_LENGTH_ERROR
import com.niyaj.common.utils.Resource
import com.niyaj.common.utils.ValidationResult
import com.niyaj.data.mapper.toEntity
import com.niyaj.data.repository.CategoryRepository
import com.niyaj.data.repository.validation.CategoryValidationRepository
import com.niyaj.data.utils.collectWithSearch
Expand All @@ -20,9 +21,8 @@ import io.realm.kotlin.ext.query
import io.realm.kotlin.query.Sort
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.withContext
import org.mongodb.kbson.BsonObjectId
import timber.log.Timber

class CategoryRepositoryImpl(
Expand All @@ -37,24 +37,17 @@ class CategoryRepositoryImpl(
}

override suspend fun getAllCategories(searchText: String): Flow<List<Category>> {
return channelFlow {
withContext(ioDispatcher) {
try {
val items = realm.query<CategoryEntity>()
.sort("categoryId", Sort.ASCENDING)
.find()
.asFlow()

return withContext(ioDispatcher) {
realm.query<CategoryEntity>()
.sort("categoryId", Sort.ASCENDING)
.find()
.asFlow()
.mapLatest { items ->
items.collectWithSearch(
transform = { it.toExternalModel() },
searchFilter = { it.filterCategory(searchText) },
send = { send(it) }
)

} catch (e: Exception) {
send(emptyList())
}
}
}
}

Expand All @@ -69,60 +62,33 @@ class CategoryRepositoryImpl(
}
}

override fun findCategoryByName(name: String, categoryId: String?): Boolean {
val category = if (categoryId.isNullOrEmpty()) {
realm.query<CategoryEntity>("categoryName == $0", name).first().find()
} else {
realm.query<CategoryEntity>("categoryId != $0 && categoryName == $1", categoryId, name)
.first()
.find()
}

return category != null
}

override suspend fun createNewCategory(newCategory: Category): Resource<Boolean> {
return try {
withContext(ioDispatcher) {
val validateCategoryName = validateCategoryName(newCategory.categoryName)

if (validateCategoryName.successful) {
val category = CategoryEntity()
category.categoryId =
newCategory.categoryId.ifEmpty { BsonObjectId().toHexString() }
category.categoryName = newCategory.categoryName
category.categoryAvailability = newCategory.categoryAvailability
category.createdAt =
newCategory.createdAt.ifEmpty { System.currentTimeMillis().toString() }

realm.write {
this.copyToRealm(category)
}

Resource.Success(true)
} else {
Resource.Error(
validateCategoryName.errorMessage ?: "Unable to create category"
)
}
}
} catch (e: Exception) {
Resource.Error(e.message ?: "Unable to create new category")
override suspend fun findCategoryByName(name: String, categoryId: String?): Boolean {
return withContext(ioDispatcher) {
if (categoryId.isNullOrEmpty()) {
realm.query<CategoryEntity>("categoryName == $0", name).first().find()
} else {
realm.query<CategoryEntity>(
"categoryId != $0 && categoryName == $1",
categoryId,
name
)
.first()
.find()
} != null
}
}

override suspend fun updateCategory(
override suspend fun createOrUpdateCategory(
updatedCategory: Category,
categoryId: String
): Resource<Boolean> {
return try {
withContext(ioDispatcher) {
val validateCategoryName =
validateCategoryName(updatedCategory.categoryName, categoryId)
val validateName = validateCategoryName(updatedCategory.categoryName, categoryId)

if (validateCategoryName.successful) {
val category =
realm.query<CategoryEntity>("categoryId == $0", categoryId).first().find()
if (validateName.successful) {
val category = realm.query<CategoryEntity>("categoryId == $0", categoryId)
.first().find()

if (category != null) {
realm.write {
Expand All @@ -135,55 +101,21 @@ class CategoryRepositoryImpl(

Resource.Success(true)
} else {
Resource.Error(
validateCategoryName.errorMessage ?: "Unable to update category"
)
realm.write {
this.copyToRealm(updatedCategory.toEntity())
}

Resource.Success(true)
}
} else {
Resource.Error(
validateCategoryName.errorMessage ?: "Unable to update category"
)
Resource.Error(validateName.errorMessage ?: "Unable")
}
}
} catch (e: Exception) {
Resource.Error(e.message ?: "Unable to update category")
}
}

override suspend fun deleteCategory(categoryId: String): Resource<Boolean> {
return try {
val category =
realm.query<CategoryEntity>("categoryId == $0", categoryId).first().find()

if (category != null) {
withContext(ioDispatcher) {
realm.write {
val products =
this.query<ProductEntity>("category.categoryId == $0", categoryId)
.find()
val cartOrders =
this.query<CartEntity>("product.category.categoryId == $0", categoryId)
.find()

delete(cartOrders)

delete(products)

findLatest(category)?.let {
delete(it)
}
}
}

Resource.Success(true)
} else {
Resource.Error("Unable to find category")
}
} catch (e: Exception) {
Resource.Error(e.message ?: "Unable to delete category")
}
}

override suspend fun deleteCategories(categoryIds: List<String>): Resource<Boolean> {
return try {
withContext(ioDispatcher) {
Expand Down Expand Up @@ -227,7 +159,10 @@ class CategoryRepositoryImpl(
}
}

override fun validateCategoryName(categoryName: String, categoryId: String?): ValidationResult {
override suspend fun validateCategoryName(
categoryName: String,
categoryId: String?
): ValidationResult {
if (categoryName.isEmpty()) {
return ValidationResult(
successful = false,
Expand All @@ -242,7 +177,11 @@ class CategoryRepositoryImpl(
)
}

if (this.findCategoryByName(categoryName, categoryId)) {
val result = withContext(ioDispatcher) {
findCategoryByName(categoryName, categoryId)
}

if (result) {
return ValidationResult(
successful = false,
errorMessage = CATEGORY_NAME_ALREADY_EXIST_ERROR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package com.niyaj.data.mapper

import com.niyaj.database.model.CategoryEntity
import com.niyaj.model.Category
import org.mongodb.kbson.BsonObjectId

fun Category.toEntity(): CategoryEntity {
return CategoryEntity(
categoryId = categoryId,
categoryId = categoryId.ifEmpty { BsonObjectId().toHexString() },
categoryName = categoryName,
categoryAvailability = categoryAvailability,
createdAt = createdAt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ interface CategoryRepository {

suspend fun getCategoryById(categoryId: String): Resource<Category?>

fun findCategoryByName(name: String, categoryId: String?): Boolean
suspend fun findCategoryByName(name: String, categoryId: String?): Boolean

suspend fun createNewCategory(newCategory: Category): Resource<Boolean>

suspend fun updateCategory(updatedCategory: Category, categoryId: String): Resource<Boolean>

suspend fun deleteCategory(categoryId: String): Resource<Boolean>
suspend fun createOrUpdateCategory(
updatedCategory: Category,
categoryId: String
): Resource<Boolean>

suspend fun deleteCategories(categoryIds: List<String>): Resource<Boolean>
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ import com.niyaj.common.utils.ValidationResult

interface CategoryValidationRepository {

fun validateCategoryName(categoryName: String, categoryId: String? = null): ValidationResult
suspend fun validateCategoryName(
categoryName: String,
categoryId: String? = null
): ValidationResult
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.niyaj.feature.category

import androidx.activity.compose.BackHandler
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
Expand All @@ -11,6 +13,7 @@ import androidx.compose.material.ScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
Expand All @@ -21,6 +24,7 @@ import com.niyaj.common.tags.CategoryTestTags.CREATE_NEW_CATEGORY
import com.niyaj.common.tags.CategoryTestTags.DELETE_CATEGORY_ITEM_MESSAGE
import com.niyaj.common.tags.CategoryTestTags.DELETE_CATEGORY_ITEM_TITLE
import com.niyaj.common.utils.Constants.SEARCH_ITEM_NOT_FOUND
import com.niyaj.designsystem.theme.SpaceSmall
import com.niyaj.feature.category.components.CategoryData
import com.niyaj.feature.category.destinations.AddEditCategoryScreenDestination
import com.niyaj.ui.components.ItemNotAvailable
Expand Down Expand Up @@ -50,7 +54,7 @@ import kotlinx.coroutines.launch
* @param navController
* @param scaffoldState
* @param viewModel
// * @param resultRecipient
* @param resultRecipient
* @see CategoryViewModel
*/
@RootNavGraph(start = true)
Expand Down Expand Up @@ -193,6 +197,9 @@ fun CategoryScreen(

is UiState.Success -> {
LazyVerticalGrid(
modifier = Modifier
.fillMaxSize()
.padding(SpaceSmall),
columns = GridCells.Fixed(2),
state = lazyGridState,
) {
Expand Down
Loading