From d15940a5f20844136e2682c5fc7fea754588ae18 Mon Sep 17 00:00:00 2001 From: Alex <78383757+Lextical@users.noreply.github.com> Date: Sat, 11 Apr 2026 23:02:52 -0600 Subject: [PATCH] Made it so staffs can only manage their own store and they cannot see other branches data --- .../activities/MainActivity.java | 1 + .../petstoremobile/api/auth/TokenManager.java | 14 ++++++++ .../listfragments/AdoptionFragment.java | 34 ++++++++++++++---- .../listfragments/AppointmentFragment.java | 35 ++++++++++++++----- .../listfragments/InventoryFragment.java | 31 ++++++++++++---- .../fragments/listfragments/PetFragment.java | 31 +++++++++++----- .../listfragments/PurchaseOrderFragment.java | 31 ++++++++++++---- .../fragments/listfragments/SaleFragment.java | 34 ++++++++++++++---- .../AdoptionDetailFragment.java | 13 ++++++- .../AppointmentDetailFragment.java | 13 ++++++- .../detailfragments/PetDetailFragment.java | 27 +++++++++++++- .../detailfragments/SaleDetailFragment.java | 16 ++++++++- .../viewmodels/PetDetailViewModel.java | 27 ++++++++++++++ .../main/res/layout/fragment_pet_detail.xml | 9 ++--- 14 files changed, 264 insertions(+), 52 deletions(-) diff --git a/android/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java b/android/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java index f8c89342..022192f1 100644 --- a/android/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java +++ b/android/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java @@ -133,6 +133,7 @@ public class MainActivity extends AppCompatActivity { if (resource != null && resource.status != Resource.Status.LOADING) { if (resource.status == Resource.Status.SUCCESS && resource.data != null) { tokenManager.saveUserId(resource.data.getId()); + tokenManager.savePrimaryStoreId(resource.data.getStoreId()); } Toast.makeText(this, "Login successful", Toast.LENGTH_SHORT).show(); startActivity(new Intent(this, HomeActivity.class)); diff --git a/android/app/src/main/java/com/example/petstoremobile/api/auth/TokenManager.java b/android/app/src/main/java/com/example/petstoremobile/api/auth/TokenManager.java index aa9ab363..dc6096de 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/auth/TokenManager.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/auth/TokenManager.java @@ -15,6 +15,7 @@ public class TokenManager { private static final String ROLE_KEY = "role"; private static final String PREFS_NAME = "auth_prefs"; private static final String USER_ID_KEY = "user_id"; + private static final String PRIMARY_STORE_ID_KEY = "primary_store_id"; private SharedPreferences prefs; @@ -54,6 +55,19 @@ public class TokenManager { prefs.edit().putLong(USER_ID_KEY, userId).apply(); } + public void savePrimaryStoreId(Long storeId) { + if (storeId != null) { + prefs.edit().putLong(PRIMARY_STORE_ID_KEY, storeId).apply(); + } else { + prefs.edit().remove(PRIMARY_STORE_ID_KEY).apply(); + } + } + + public Long getPrimaryStoreId() { + long id = prefs.getLong(PRIMARY_STORE_ID_KEY, -1L); + return id == -1L ? null : id; + } + //Check if logged in public boolean isLoggedIn() { return getToken() != null; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java index 2d687c6e..cfc05233 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java @@ -17,6 +17,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.AdoptionAdapter; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.databinding.FragmentAdoptionBinding; import com.example.petstoremobile.dtos.AdoptionDTO; import com.example.petstoremobile.dtos.StoreDTO; @@ -38,6 +39,8 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; +import javax.inject.Inject; + import dagger.hilt.android.AndroidEntryPoint; @AndroidEntryPoint @@ -52,6 +55,8 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop private boolean isMonthMode = false; private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + @Inject TokenManager tokenManager; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -117,7 +122,7 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop public void onResume() { super.onResume(); loadAdoptions(); - viewModel.loadStores(); + if (!isStaff()) viewModel.loadStores(); } private void toggleCalendarMode() { @@ -128,8 +133,18 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop } private void setupFilterToggle() { - UIUtils.setupFilterToggle(binding.btnToggleFilterAdoption, binding.layoutFilterAdoption, - binding.etSearchAdoption, binding.spinnerStatusAdoption, binding.spinnerStoreAdoption); + if (isStaff()) { + UIUtils.setupFilterToggle(binding.btnToggleFilterAdoption, binding.layoutFilterAdoption, + binding.etSearchAdoption, binding.spinnerStatusAdoption); + binding.spinnerStoreAdoption.setVisibility(View.GONE); + } else { + UIUtils.setupFilterToggle(binding.btnToggleFilterAdoption, binding.layoutFilterAdoption, + binding.etSearchAdoption, binding.spinnerStatusAdoption, binding.spinnerStoreAdoption); + } + } + + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } private void setupCalendar() { @@ -195,10 +210,15 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop String query = binding.etSearchAdoption.getText().toString().trim(); String status = binding.spinnerStatusAdoption.getSelectedItem() != null ? binding.spinnerStatusAdoption.getSelectedItem().toString() : "All Statuses"; - Long storeId = null; - List stores = viewModel.getStores().getValue(); - if (binding.spinnerStoreAdoption.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { - storeId = stores.get(binding.spinnerStoreAdoption.getSelectedItemPosition() - 1).getStoreId(); + Long storeId; + if (isStaff()) { + storeId = tokenManager.getPrimaryStoreId(); + } else { + storeId = null; + List stores = viewModel.getStores().getValue(); + if (binding.spinnerStoreAdoption.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { + storeId = stores.get(binding.spinnerStoreAdoption.getSelectedItemPosition() - 1).getStoreId(); + } } String selectedDateString = null; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AppointmentFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AppointmentFragment.java index 8610790e..037c7ce9 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AppointmentFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AppointmentFragment.java @@ -17,6 +17,7 @@ import android.view.ViewGroup; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.AppointmentAdapter; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.databinding.FragmentAppointmentBinding; import com.example.petstoremobile.dtos.AppointmentDTO; import com.example.petstoremobile.dtos.StoreDTO; @@ -39,6 +40,8 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; +import javax.inject.Inject; + import dagger.hilt.android.AndroidEntryPoint; @AndroidEntryPoint @@ -52,6 +55,8 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. private AuthViewModel authViewModel; private BulkDeleteHandler bulkDeleteHandler; + @Inject TokenManager tokenManager; + private CalendarDay selectedCalendarDay; private boolean isMonthMode = false; private Long currentUserId = null; @@ -126,7 +131,7 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. public void onResume() { super.onResume(); loadAppointmentData(); - viewModel.loadStores(); + if (!isStaff()) viewModel.loadStores(); } private void toggleCalendarMode() { @@ -151,8 +156,13 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. } private void setupFilterToggle() { - UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchAppointment, - binding.spinnerStatus, binding.spinnerStore); + if (isStaff()) { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchAppointment, binding.spinnerStatus); + binding.spinnerStore.setVisibility(View.GONE); + } else { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchAppointment, + binding.spinnerStatus, binding.spinnerStore); + } } private void setupCalendar() { @@ -227,14 +237,23 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. } } + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); + } + private void loadAppointmentData() { String query = binding.etSearchAppointment.getText().toString().trim(); String status = binding.spinnerStatus.getSelectedItem() != null ? binding.spinnerStatus.getSelectedItem().toString() : "All Statuses"; - - Long storeId = null; - List stores = viewModel.getStores().getValue(); - if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { - storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + + Long storeId; + if (isStaff()) { + storeId = tokenManager.getPrimaryStoreId(); + } else { + storeId = null; + List stores = viewModel.getStores().getValue(); + if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { + storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + } } String selectedDateString = null; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/InventoryFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/InventoryFragment.java index 6cefedb8..4e2c2337 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/InventoryFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/InventoryFragment.java @@ -16,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.InventoryAdapter; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.databinding.FragmentInventoryBinding; import com.example.petstoremobile.dtos.InventoryDTO; import com.example.petstoremobile.dtos.StoreDTO; @@ -27,6 +28,8 @@ import com.example.petstoremobile.utils.SpinnerUtils; import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; + import dagger.hilt.android.AndroidEntryPoint; @AndroidEntryPoint @@ -38,6 +41,8 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn private InventoryListViewModel viewModel; private BulkDeleteHandler bulkDeleteHandler; + @Inject TokenManager tokenManager; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -99,7 +104,7 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn @Override public void onResume() { super.onResume(); - viewModel.loadStores(); + if (!isStaff()) viewModel.loadStores(); } @Override @@ -109,7 +114,16 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn } private void setupFilterToggle() { - UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchInventory, binding.spinnerStore); + if (isStaff()) { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchInventory); + binding.spinnerStore.setVisibility(View.GONE); + } else { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchInventory, binding.spinnerStore); + } + } + + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } private void setupSearch() { @@ -150,10 +164,15 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn String query = binding.etSearchInventory != null ? binding.etSearchInventory.getText().toString().trim() : ""; if (query.isEmpty()) query = null; - Long storeId = null; - List stores = viewModel.getStores().getValue(); - if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { - storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + Long storeId; + if (isStaff()) { + storeId = tokenManager.getPrimaryStoreId(); + } else { + storeId = null; + List stores = viewModel.getStores().getValue(); + if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { + storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + } } viewModel.loadInventory(reset, query, storeId); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java index bc1b9a6f..5c94113b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java @@ -107,12 +107,22 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen public void onResume() { super.onResume(); loadPetData(); - viewModel.loadStores(); + if (!isStaff()) viewModel.loadStores(); } private void setupFilterToggle() { - UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchPet, - binding.spinnerStatus, binding.spinnerSpecies, binding.spinnerStore); + if (isStaff()) { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchPet, + binding.spinnerStatus, binding.spinnerSpecies); + binding.spinnerStore.setVisibility(View.GONE); + } else { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchPet, + binding.spinnerStatus, binding.spinnerSpecies, binding.spinnerStore); + } + } + + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } private void setupSearch() { @@ -141,11 +151,16 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen String query = binding.etSearchPet.getText().toString().trim(); String status = binding.spinnerStatus.getSelectedItem() != null ? binding.spinnerStatus.getSelectedItem().toString() : "All Statuses"; String species = binding.spinnerSpecies.getSelectedItem() != null ? binding.spinnerSpecies.getSelectedItem().toString() : "All Species"; - - Long storeId = null; - List stores = viewModel.getStores().getValue(); - if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { - storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + + Long storeId; + if (isStaff()) { + storeId = tokenManager.getPrimaryStoreId(); + } else { + storeId = null; + List stores = viewModel.getStores().getValue(); + if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { + storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + } } viewModel.loadPets(query, status, species, storeId); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PurchaseOrderFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PurchaseOrderFragment.java index 64dc0ea5..10b9ee3c 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PurchaseOrderFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PurchaseOrderFragment.java @@ -14,6 +14,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.PurchaseOrderAdapter; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.databinding.FragmentPurchaseOrderBinding; import com.example.petstoremobile.dtos.PurchaseOrderDTO; import com.example.petstoremobile.dtos.StoreDTO; @@ -24,6 +25,8 @@ import com.example.petstoremobile.viewmodels.PurchaseOrderListViewModel; import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; + import dagger.hilt.android.AndroidEntryPoint; @AndroidEntryPoint @@ -35,6 +38,8 @@ public class PurchaseOrderFragment extends Fragment private PurchaseOrderAdapter adapter; private PurchaseOrderListViewModel viewModel; + @Inject TokenManager tokenManager; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -79,11 +84,20 @@ public class PurchaseOrderFragment extends Fragment public void onResume() { super.onResume(); loadData(); - viewModel.loadStores(); + if (!isStaff()) viewModel.loadStores(); } private void setupFilterToggle() { - UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchPO, binding.spinnerStore); + if (isStaff()) { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchPO); + binding.spinnerStore.setVisibility(View.GONE); + } else { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchPO, binding.spinnerStore); + } + } + + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } private void setupSearch() { @@ -108,10 +122,15 @@ public class PurchaseOrderFragment extends Fragment String query = binding.etSearchPO != null ? binding.etSearchPO.getText().toString().trim() : ""; if (query.isEmpty()) query = null; - Long storeId = null; - List stores = viewModel.getStores().getValue(); - if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { - storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + Long storeId; + if (isStaff()) { + storeId = tokenManager.getPrimaryStoreId(); + } else { + storeId = null; + List stores = viewModel.getStores().getValue(); + if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { + storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + } } viewModel.loadPurchaseOrders(query, storeId); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SaleFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SaleFragment.java index b3fd9546..787e99a7 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SaleFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SaleFragment.java @@ -15,6 +15,7 @@ import android.widget.Toast; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.SaleAdapter; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.databinding.FragmentSaleBinding; import com.example.petstoremobile.dtos.SaleDTO; import com.example.petstoremobile.dtos.StoreDTO; @@ -25,6 +26,8 @@ import com.example.petstoremobile.viewmodels.SaleListViewModel; import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; + import dagger.hilt.android.AndroidEntryPoint; @AndroidEntryPoint @@ -35,6 +38,8 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis private SaleAdapter adapter; private SaleListViewModel viewModel; + @Inject TokenManager tokenManager; + @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -87,12 +92,22 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis @Override public void onResume() { super.onResume(); - viewModel.loadStores(); + if (!isStaff()) viewModel.loadStores(); } private void setupFilterToggle() { - UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchSale, - binding.spinnerPaymentMethod, binding.spinnerStore, binding.spinnerRefundStatus); + if (isStaff()) { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchSale, + binding.spinnerPaymentMethod, binding.spinnerRefundStatus); + binding.spinnerStore.setVisibility(View.GONE); + } else { + UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchSale, + binding.spinnerPaymentMethod, binding.spinnerStore, binding.spinnerRefundStatus); + } + } + + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } private void setupStoreFilter() { @@ -149,10 +164,15 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis paymentMethod = (String) binding.spinnerPaymentMethod.getSelectedItem(); } - Long storeId = null; - List stores = viewModel.getStores().getValue(); - if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { - storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + Long storeId; + if (isStaff()) { + storeId = tokenManager.getPrimaryStoreId(); + } else { + storeId = null; + List stores = viewModel.getStores().getValue(); + if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) { + storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); + } } Boolean isRefund = null; 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 0455f457..e3467215 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 @@ -17,11 +17,14 @@ import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.SpinnerUtils; import com.example.petstoremobile.utils.UIUtils; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.viewmodels.AdoptionDetailViewModel; import java.math.BigDecimal; import java.util.*; +import javax.inject.Inject; + import dagger.hilt.android.AndroidEntryPoint; /** @@ -34,6 +37,8 @@ public class AdoptionDetailFragment extends Fragment { private AdoptionDetailViewModel viewModel; private boolean isUpdatingUI = false; + @Inject TokenManager tokenManager; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -82,7 +87,7 @@ public class AdoptionDetailFragment extends Fragment { viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> { AdoptionDetailViewModel.ViewState state = viewModel.getViewState().getValue(); - Long storeId = state != null ? state.selectedStoreId : null; + Long storeId = isStaff() ? tokenManager.getPrimaryStoreId() : (state != null ? state.selectedStoreId : null); SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionStore, list, DropdownDTO::getLabel, "-- Select Store --", storeId, DropdownDTO::getId); }); @@ -212,9 +217,15 @@ public class AdoptionDetailFragment extends Fragment { if (employees != null) SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionEmployee, employees, DropdownDTO::getLabel, "-- Select Staff --", state.selectedEmployeeId, DropdownDTO::getId); + if (isStaff()) binding.spinnerAdoptionStore.setEnabled(false); + isUpdatingUI = false; } + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); + } + private void saveAdoption() { if (!InputValidator.isSpinnerSelected(binding.spinnerAdoptionCustomer, "Customer")) return; if (!InputValidator.isSpinnerSelected(binding.spinnerAdoptionPet, "Pet")) return; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java index 3e0e20af..05b83622 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java @@ -23,10 +23,13 @@ import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.SpinnerUtils; import com.example.petstoremobile.utils.UIUtils; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.viewmodels.AppointmentDetailViewModel; import java.util.List; +import javax.inject.Inject; + import dagger.hilt.android.AndroidEntryPoint; /** @@ -43,6 +46,8 @@ public class AppointmentDetailFragment extends Fragment { private AppointmentDetailViewModel viewModel; private boolean isUpdatingUI = false; + @Inject TokenManager tokenManager; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -131,7 +136,7 @@ public class AppointmentDetailFragment extends Fragment { viewModel.getStores().observe(getViewLifecycleOwner(), list -> { AppointmentDetailViewModel.ViewState state = viewModel.getViewState().getValue(); - Long id = state != null ? state.selectedStoreId : null; + Long id = isStaff() ? tokenManager.getPrimaryStoreId() : (state != null ? state.selectedStoreId : null); SpinnerUtils.populateSpinner(requireContext(), binding.spinnerStore, list, DropdownDTO::getLabel, "-- Select Store --", id, DropdownDTO::getId); }); @@ -203,9 +208,15 @@ public class AppointmentDetailFragment extends Fragment { if (staff != null) SpinnerUtils.populateSpinner(requireContext(), binding.spinnerStaff, staff, DropdownDTO::getLabel, "-- Select Staff --", state.selectedStaffId, DropdownDTO::getId); + if (isStaff()) binding.spinnerStore.setEnabled(false); + isUpdatingUI = false; } + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); + } + private void notifyDateTimeStatusChange() { if (isUpdatingUI) return; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java index d56ba6a6..a41554ee 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java @@ -17,6 +17,7 @@ import android.widget.TextView; import android.widget.Toast; import com.example.petstoremobile.R; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.databinding.FragmentPetDetailBinding; import com.example.petstoremobile.dtos.DropdownDTO; import com.example.petstoremobile.dtos.PetDTO; @@ -31,6 +32,8 @@ import com.example.petstoremobile.viewmodels.PetDetailViewModel; import java.util.Locale; +import javax.inject.Inject; + import dagger.hilt.android.AndroidEntryPoint; /** @@ -43,6 +46,8 @@ public class PetDetailFragment extends Fragment { private PetDetailViewModel viewModel; private boolean isUpdatingUI = false; + @Inject TokenManager tokenManager; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -81,8 +86,19 @@ public class PetDetailFragment extends Fragment { viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> { PetDetailViewModel.ViewState state = viewModel.getViewState().getValue(); - Long selectedStoreId = state != null ? state.selectedStoreId : null; + boolean staffCreating = isStaff() && (state == null || !state.isEditing); + boolean storeEnabled = state == null || state.isStoreEnabled; + Long selectedStoreId = (staffCreating && storeEnabled) ? tokenManager.getPrimaryStoreId() : (state != null ? state.selectedStoreId : null); updateStoreSpinnerSelection(selectedStoreId); + if (staffCreating && storeEnabled) binding.spinnerStore.setEnabled(false); + }); + + viewModel.getSpeciesList().observe(getViewLifecycleOwner(), list -> { + PetDetailViewModel.ViewState state = viewModel.getViewState().getValue(); + String selectedSpecies = state != null ? state.selectedSpecies : null; + SpinnerUtils.populateSpinner(requireContext(), binding.spinnerPetSpecies, list, + DropdownDTO::getLabel, "-- Select Species --", null, DropdownDTO::getId); + SpinnerUtils.setSelectionByValue(binding.spinnerPetSpecies, selectedSpecies); }); } @@ -308,9 +324,18 @@ public class PetDetailFragment extends Fragment { binding.spinnerStore.setSelection(0); } + if (isStaff() && !state.isEditing && state.isStoreEnabled) { + updateStoreSpinnerSelection(tokenManager.getPrimaryStoreId()); + binding.spinnerStore.setEnabled(false); + } + isUpdatingUI = false; } + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); + } + private void clearSpinnerError(Spinner spinner) { View selectedView = spinner.getSelectedView(); if (selectedView instanceof TextView) { 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 1c216ba3..11e8b9f3 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 @@ -17,6 +17,10 @@ import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.UIUtils; +import com.example.petstoremobile.api.auth.TokenManager; + +import javax.inject.Inject; + import dagger.hilt.android.AndroidEntryPoint; import java.math.BigDecimal; import java.util.*; @@ -27,6 +31,8 @@ public class SaleDetailFragment extends Fragment { private FragmentSaleDetailBinding binding; private SaleDetailViewModel viewModel; + @Inject TokenManager tokenManager; + private final String[] PAYMENT_METHODS = { "Cash", "Card"}; @Override @@ -56,10 +62,18 @@ public class SaleDetailFragment extends Fragment { return binding.getRoot(); } + private boolean isStaff() { + return "STAFF".equalsIgnoreCase(tokenManager.getRole()); + } + private void observeViewModel() { viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> { + Long selectedStoreId = isStaff() ? tokenManager.getPrimaryStoreId() : -1L; SpinnerUtils.populateSpinner(requireContext(), binding.spinnerSaleStore, list, - DropdownDTO::getLabel, "-- Select Store --", -1L, DropdownDTO::getId); + DropdownDTO::getLabel, "-- Select Store --", selectedStoreId, DropdownDTO::getId); + if (isStaff()) { + binding.spinnerSaleStore.setEnabled(false); + } }); viewModel.getCustomerList().observe(getViewLifecycleOwner(), list -> { diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetDetailViewModel.java index 3a0f4482..dd0d302a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetDetailViewModel.java @@ -32,12 +32,14 @@ public class PetDetailViewModel extends ViewModel { private final MutableLiveData> customerList = new MutableLiveData<>(new ArrayList<>()); private final MutableLiveData> storeList = new MutableLiveData<>(new ArrayList<>()); + private final MutableLiveData> speciesList = new MutableLiveData<>(new ArrayList<>()); private final MutableLiveData isLoading = new MutableLiveData<>(false); private final MutableLiveData viewState = new MutableLiveData<>(new ViewState()); private long petId = -1; private Long selectedCustomerId = null; private Long selectedStoreId = null; + private String selectedSpecies = null; @Inject public PetDetailViewModel(PetRepository petRepository, CustomerRepository customerRepository, StoreRepository storeRepository) { @@ -58,6 +60,12 @@ public class PetDetailViewModel extends ViewModel { storeList.setValue(resource.data); } }); + + observeOnce(petRepository.getPetDropdowns(), resource -> { + if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { + speciesList.setValue(resource.data); + } + }); } public void setPetId(long id) { @@ -89,6 +97,16 @@ public class PetDetailViewModel extends ViewModel { updateViewState(state -> state.selectedCustomerId = selectedCustomerId); } + public void onSpeciesSelected(int position) { + List list = speciesList.getValue(); + if (position > 0 && list != null && position <= list.size()) { + selectedSpecies = list.get(position - 1).getLabel(); + } else { + selectedSpecies = null; + } + updateViewState(state -> state.selectedSpecies = selectedSpecies); + } + public void onStoreSelected(int position) { List list = storeList.getValue(); if (position > 0 && list != null && position <= list.size()) { @@ -125,8 +143,10 @@ public class PetDetailViewModel extends ViewModel { if (!isEditing) { selectedCustomerId = null; selectedStoreId = null; + selectedSpecies = null; state.selectedCustomerId = null; state.selectedStoreId = null; + state.selectedSpecies = null; state.selectedStatus = STATUS_AVAILABLE; state.isCustomerEnabled = false; state.isStoreEnabled = true; @@ -141,10 +161,12 @@ public class PetDetailViewModel extends ViewModel { PetDTO pet = resource.data; selectedCustomerId = pet.getCustomerId(); selectedStoreId = pet.getStoreId(); + selectedSpecies = pet.getPetSpecies(); updateViewState(state -> { state.selectedCustomerId = selectedCustomerId; state.selectedStoreId = selectedStoreId; + state.selectedSpecies = selectedSpecies; state.selectedStatus = normalizeStatus(pet.getPetStatus()); applyStatusRules(state, false); }); @@ -176,6 +198,10 @@ public class PetDetailViewModel extends ViewModel { return storeList; } + public LiveData> getSpeciesList() { + return speciesList; + } + public LiveData getIsLoading() { return isLoading; } @@ -253,6 +279,7 @@ public class PetDetailViewModel extends ViewModel { public String saveButtonText = "Add"; public String[] availableStatuses = new String[]{STATUS_AVAILABLE, STATUS_ADOPTED, STATUS_OWNED}; public String selectedStatus = STATUS_AVAILABLE; + public String selectedSpecies = null; public Long selectedCustomerId = null; public Long selectedStoreId = null; } diff --git a/android/app/src/main/res/layout/fragment_pet_detail.xml b/android/app/src/main/res/layout/fragment_pet_detail.xml index 4e7ac201..e9018362 100644 --- a/android/app/src/main/res/layout/fragment_pet_detail.xml +++ b/android/app/src/main/res/layout/fragment_pet_detail.xml @@ -95,14 +95,11 @@ android:textSize="12sp" android:layout_marginBottom="4dp"/> - + android:layout_marginBottom="16dp"/>