diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ActivityLogFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ActivityLogFragment.java index 85d77668..d54d8f6b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ActivityLogFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ActivityLogFragment.java @@ -11,7 +11,12 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; +import android.widget.Toast; + +import androidx.navigation.fragment.NavHostFragment; + import com.example.petstoremobile.adapters.ActivityLogAdapter; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.databinding.FragmentActivityLogBinding; import com.example.petstoremobile.dtos.ActivityLogDTO; import com.example.petstoremobile.dtos.DropdownDTO; @@ -19,6 +24,8 @@ import com.example.petstoremobile.utils.SpinnerUtils; import com.example.petstoremobile.utils.UIUtils; import com.example.petstoremobile.viewmodels.ActivityLogListViewModel; +import javax.inject.Inject; + import java.util.ArrayList; import java.util.List; @@ -32,10 +39,19 @@ public class ActivityLogFragment extends Fragment { private final List logList = new ArrayList<>(); private List storeList = new ArrayList<>(); + @Inject TokenManager tokenManager; + @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentActivityLogBinding.inflate(inflater, container, false); + + if (!"ADMIN".equalsIgnoreCase(tokenManager.getRole())) { + Toast.makeText(requireContext(), "Access denied", Toast.LENGTH_SHORT).show(); + NavHostFragment.findNavController(this).popBackStack(); + return binding.getRoot(); + } + viewModel = new ViewModelProvider(this).get(ActivityLogListViewModel.class); setupRecyclerView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java index a5a4bd3b..1cd47561 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java @@ -74,29 +74,42 @@ public class AdoptionDetailFragment extends Fragment { viewModel.getPetList().observe(getViewLifecycleOwner(), list -> { AdoptionDetailViewModel.ViewState state = viewModel.getViewState().getValue(); Long petId = state != null ? state.selectedPetId : null; + isUpdatingUI = true; SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionPet, list, DropdownDTO::getLabel, "-- Select Pet --", petId, DropdownDTO::getId); + isUpdatingUI = false; }); viewModel.getCustomerList().observe(getViewLifecycleOwner(), list -> { AdoptionDetailViewModel.ViewState state = viewModel.getViewState().getValue(); Long customerId = state != null ? state.selectedCustomerId : null; + isUpdatingUI = true; SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionCustomer, list, DropdownDTO::getLabel, "-- Select Customer --", customerId, DropdownDTO::getId); + isUpdatingUI = false; }); viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> { AdoptionDetailViewModel.ViewState state = viewModel.getViewState().getValue(); Long storeId = isStaff() ? tokenManager.getPrimaryStoreId() : (state != null ? state.selectedStoreId : null); + isUpdatingUI = true; SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionStore, list, DropdownDTO::getLabel, "-- Select Store --", storeId, DropdownDTO::getId); + isUpdatingUI = false; + + if (isStaff() && storeId != null) { + int position = binding.spinnerAdoptionStore.getSelectedItemPosition(); + if (position > 0) viewModel.onStoreSelected(position); + } }); viewModel.getEmployeeList().observe(getViewLifecycleOwner(), list -> { AdoptionDetailViewModel.ViewState state = viewModel.getViewState().getValue(); Long employeeId = state != null ? state.selectedEmployeeId : null; + isUpdatingUI = true; SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionEmployee, list, DropdownDTO::getLabel, "-- Select Staff --", employeeId, DropdownDTO::getId); + isUpdatingUI = false; }); } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SaleDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SaleDetailFragment.java index f8752a16..ec111675 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SaleDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SaleDetailFragment.java @@ -70,11 +70,15 @@ public class SaleDetailFragment extends Fragment { private void observeViewModel() { viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> { - Long selectedStoreId = isStaff() ? tokenManager.getPrimaryStoreId() : -1L; + Long primaryStoreId = tokenManager.getPrimaryStoreId(); + Long selectedStoreId = isStaff() ? primaryStoreId : -1L; SpinnerUtils.populateSpinner(requireContext(), binding.spinnerSaleStore, list, DropdownDTO::getLabel, "-- Select Store --", selectedStoreId, DropdownDTO::getId); if (isStaff()) { - binding.spinnerSaleStore.setEnabled(false); + UIUtils.setViewsEnabled(false, binding.spinnerSaleStore); + if (primaryStoreId == null) { + Toast.makeText(requireContext(), "No store assigned to your account. Contact an admin.", Toast.LENGTH_LONG).show(); + } } }); @@ -275,7 +279,7 @@ public class SaleDetailFragment extends Fragment { private void setupAddItem() { binding.btnAddItem.setOnClickListener(v -> { if (!InputValidator.isSpinnerSelected(binding.spinnerSaleProduct, "Product")) return; - if (!InputValidator.isPositiveInteger(binding.etSaleQuantity, "Quantity")) return; + if (!InputValidator.isAtLeastOne(binding.etSaleQuantity, "Quantity")) return; int qty = Integer.parseInt(binding.etSaleQuantity.getText().toString().trim()); ProductDTO product = viewModel.getProductList().getValue().get(binding.spinnerSaleProduct.getSelectedItemPosition() - 1); diff --git a/android/app/src/main/java/com/example/petstoremobile/utils/InputValidator.java b/android/app/src/main/java/com/example/petstoremobile/utils/InputValidator.java index 03802f65..ee79ec9f 100644 --- a/android/app/src/main/java/com/example/petstoremobile/utils/InputValidator.java +++ b/android/app/src/main/java/com/example/petstoremobile/utils/InputValidator.java @@ -17,7 +17,7 @@ public class InputValidator { return true; } - // Checks if the value is a positive integer + // Checks if the value is a positive integer (>= 0) public static boolean isPositiveInteger(EditText field, String fieldName) { String value = field.getText().toString().trim(); try { @@ -35,6 +35,24 @@ public class InputValidator { } } + // Checks if the value is a whole number of at least 1 + public static boolean isAtLeastOne(EditText field, String fieldName) { + String value = field.getText().toString().trim(); + try { + int num = Integer.parseInt(value); + if (num < 1) { + field.setError(fieldName + " must be at least 1"); + field.requestFocus(); + return false; + } + return true; + } catch (NumberFormatException e) { + field.setError(fieldName + " must be a whole number"); + field.requestFocus(); + return false; + } + } + // Checks if the value is a positive decimal number greater than 0 public static boolean isGreaterThanZero(EditText field, String fieldName) { String value = field.getText().toString().trim();