Converted merged fragments to viewbinding

This commit is contained in:
Alex
2026-04-08 02:06:07 -06:00
parent 627ce7a987
commit a35b432b54
5 changed files with 217 additions and 311 deletions

View File

@@ -5,9 +5,11 @@ import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.*; import android.view.*;
import android.widget.*; import android.widget.*;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.RetrofitClient; import com.example.petstoremobile.api.RetrofitClient;
import com.example.petstoremobile.databinding.FragmentAnalyticsBinding;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.SaleDTO; import com.example.petstoremobile.dtos.SaleDTO;
import com.example.petstoremobile.fragments.ListFragment; import com.example.petstoremobile.fragments.ListFragment;
@@ -18,23 +20,25 @@ import retrofit2.*;
public class AnalyticsFragment extends Fragment { public class AnalyticsFragment extends Fragment {
private TextView tvTotalRevenue, tvTotalTransactions, tvAvgTransaction, tvTotalItems; private FragmentAnalyticsBinding binding;
private LinearLayout llTopRevenue, llTopQuantity, llPaymentMethods, llEmployeePerformance, llDailyRevenue;
private Button btnRefresh;
private ImageButton hamburger;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_analytics, container, false); binding = FragmentAnalyticsBinding.inflate(inflater, container, false);
initViews(view);
loadAnalytics(); loadAnalytics();
btnRefresh.setOnClickListener(v -> loadAnalytics()); binding.btnRefreshAnalytics.setOnClickListener(v -> loadAnalytics());
hamburger.setOnClickListener(v -> openDrawer()); binding.btnHamburgerAnalytics.setOnClickListener(v -> openDrawer());
return view; return binding.getRoot();
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
} }
private void openDrawer() { private void openDrawer() {
@@ -47,33 +51,19 @@ public class AnalyticsFragment extends Fragment {
} }
} }
private void initViews(View v) {
tvTotalRevenue = v.findViewById(R.id.tvTotalRevenue);
tvTotalTransactions = v.findViewById(R.id.tvTotalTransactions);
tvAvgTransaction = v.findViewById(R.id.tvAvgTransaction);
tvTotalItems = v.findViewById(R.id.tvTotalItems);
llTopRevenue = v.findViewById(R.id.llTopRevenue);
llTopQuantity = v.findViewById(R.id.llTopQuantity);
llPaymentMethods = v.findViewById(R.id.llPaymentMethods);
llEmployeePerformance = v.findViewById(R.id.llEmployeePerformance);
llDailyRevenue = v.findViewById(R.id.llDailyRevenue);
btnRefresh = v.findViewById(R.id.btnRefreshAnalytics);
hamburger = v.findViewById(R.id.btnHamburgerAnalytics);
}
private void loadAnalytics() { private void loadAnalytics() {
// Clear all sections // Clear all sections
llTopRevenue.removeAllViews(); binding.llTopRevenue.removeAllViews();
llTopQuantity.removeAllViews(); binding.llTopQuantity.removeAllViews();
llPaymentMethods.removeAllViews(); binding.llPaymentMethods.removeAllViews();
llEmployeePerformance.removeAllViews(); binding.llEmployeePerformance.removeAllViews();
llDailyRevenue.removeAllViews(); binding.llDailyRevenue.removeAllViews();
// Show loading // Show loading
tvTotalRevenue.setText("Loading..."); binding.tvTotalRevenue.setText("Loading...");
tvTotalTransactions.setText("..."); binding.tvTotalTransactions.setText("...");
tvAvgTransaction.setText("..."); binding.tvAvgTransaction.setText("...");
tvTotalItems.setText("..."); binding.tvTotalItems.setText("...");
RetrofitClient.getSaleApi(requireContext()).getAllSales(0, 1000, null, null, null, "saleDate,desc") RetrofitClient.getSaleApi(requireContext()).getAllSales(0, 1000, null, null, null, "saleDate,desc")
.enqueue(new Callback<PageResponse<SaleDTO>>() { .enqueue(new Callback<PageResponse<SaleDTO>>() {
@@ -121,10 +111,10 @@ public class AnalyticsFragment extends Fragment {
? totalRevenue.divide(BigDecimal.valueOf(totalTx), 2, RoundingMode.HALF_UP) ? totalRevenue.divide(BigDecimal.valueOf(totalTx), 2, RoundingMode.HALF_UP)
: BigDecimal.ZERO; : BigDecimal.ZERO;
tvTotalRevenue.setText("$" + totalRevenue.setScale(2, RoundingMode.HALF_UP)); binding.tvTotalRevenue.setText("$" + totalRevenue.setScale(2, RoundingMode.HALF_UP));
tvTotalTransactions.setText(String.valueOf(totalTx)); binding.tvTotalTransactions.setText(String.valueOf(totalTx));
tvAvgTransaction.setText("$" + avgTx); binding.tvAvgTransaction.setText("$" + avgTx);
tvTotalItems.setText(String.valueOf(totalItems)); binding.tvTotalItems.setText(String.valueOf(totalItems));
// ── Top Products by Revenue ─────────────────────────── // ── Top Products by Revenue ───────────────────────────
Map<String, BigDecimal> revenueByProduct = new LinkedHashMap<>(); Map<String, BigDecimal> revenueByProduct = new LinkedHashMap<>();
@@ -150,28 +140,28 @@ public class AnalyticsFragment extends Fragment {
topRevenue.sort((a, b) -> b.getValue().compareTo(a.getValue())); topRevenue.sort((a, b) -> b.getValue().compareTo(a.getValue()));
BigDecimal maxRevenue = topRevenue.isEmpty() ? BigDecimal.ONE : topRevenue.get(0).getValue(); BigDecimal maxRevenue = topRevenue.isEmpty() ? BigDecimal.ONE : topRevenue.get(0).getValue();
llTopRevenue.removeAllViews(); binding.llTopRevenue.removeAllViews();
for (int i = 0; i < Math.min(5, topRevenue.size()); i++) { for (int i = 0; i < Math.min(5, topRevenue.size()); i++) {
Map.Entry<String, BigDecimal> e = topRevenue.get(i); Map.Entry<String, BigDecimal> e = topRevenue.get(i);
addBarRow(llTopRevenue, e.getKey(), "$" + e.getValue().setScale(2, RoundingMode.HALF_UP), addBarRow(binding.llTopRevenue, e.getKey(), "$" + e.getValue().setScale(2, RoundingMode.HALF_UP),
e.getValue().floatValue() / maxRevenue.floatValue(), "#ff6b35"); e.getValue().floatValue() / maxRevenue.floatValue(), "#ff6b35");
} }
if (topRevenue.isEmpty()) if (topRevenue.isEmpty())
addEmptyRow(llTopRevenue, "No data"); addEmptyRow(binding.llTopRevenue, "No data");
// Sort by quantity desc, take top 5 // Sort by quantity desc, take top 5
List<Map.Entry<String, Integer>> topQuantity = new ArrayList<>(quantityByProduct.entrySet()); List<Map.Entry<String, Integer>> topQuantity = new ArrayList<>(quantityByProduct.entrySet());
topQuantity.sort((a, b) -> b.getValue() - a.getValue()); topQuantity.sort((a, b) -> b.getValue() - a.getValue());
int maxQty = topQuantity.isEmpty() ? 1 : topQuantity.get(0).getValue(); int maxQty = topQuantity.isEmpty() ? 1 : topQuantity.get(0).getValue();
llTopQuantity.removeAllViews(); binding.llTopQuantity.removeAllViews();
for (int i = 0; i < Math.min(5, topQuantity.size()); i++) { for (int i = 0; i < Math.min(5, topQuantity.size()); i++) {
Map.Entry<String, Integer> e = topQuantity.get(i); Map.Entry<String, Integer> e = topQuantity.get(i);
addBarRow(llTopQuantity, e.getKey(), e.getValue() + " units", addBarRow(binding.llTopQuantity, e.getKey(), e.getValue() + " units",
(float) e.getValue() / maxQty, "#4ecdc4"); (float) e.getValue() / maxQty, "#4ecdc4");
} }
if (topQuantity.isEmpty()) if (topQuantity.isEmpty())
addEmptyRow(llTopQuantity, "No data"); addEmptyRow(binding.llTopQuantity, "No data");
// ── Payment Methods ─────────────────────────────────── // ── Payment Methods ───────────────────────────────────
Map<String, Integer> paymentCount = new LinkedHashMap<>(); Map<String, Integer> paymentCount = new LinkedHashMap<>();
@@ -183,16 +173,16 @@ public class AnalyticsFragment extends Fragment {
int maxPayment = paymentCount.values().stream().max(Integer::compare).orElse(1); int maxPayment = paymentCount.values().stream().max(Integer::compare).orElse(1);
String[] paymentColors = { "#1a759f", "#ff9f1c", "#577590", "#90be6d" }; String[] paymentColors = { "#1a759f", "#ff9f1c", "#577590", "#90be6d" };
int ci = 0; int ci = 0;
llPaymentMethods.removeAllViews(); binding.llPaymentMethods.removeAllViews();
for (Map.Entry<String, Integer> e : paymentCount.entrySet()) { for (Map.Entry<String, Integer> e : paymentCount.entrySet()) {
addBarRow(llPaymentMethods, e.getKey(), addBarRow(binding.llPaymentMethods, e.getKey(),
e.getValue() + " transactions", e.getValue() + " transactions",
(float) e.getValue() / maxPayment, (float) e.getValue() / maxPayment,
paymentColors[ci % paymentColors.length]); paymentColors[ci % paymentColors.length]);
ci++; ci++;
} }
if (paymentCount.isEmpty()) if (paymentCount.isEmpty())
addEmptyRow(llPaymentMethods, "No data"); addEmptyRow(binding.llPaymentMethods, "No data");
// ── Employee Performance ────────────────────────────── // ── Employee Performance ──────────────────────────────
Map<String, BigDecimal> employeeRevenue = new LinkedHashMap<>(); Map<String, BigDecimal> employeeRevenue = new LinkedHashMap<>();
@@ -206,15 +196,15 @@ public class AnalyticsFragment extends Fragment {
empList.sort((a, b) -> b.getValue().compareTo(a.getValue())); empList.sort((a, b) -> b.getValue().compareTo(a.getValue()));
BigDecimal maxEmp = empList.isEmpty() ? BigDecimal.ONE : empList.get(0).getValue(); BigDecimal maxEmp = empList.isEmpty() ? BigDecimal.ONE : empList.get(0).getValue();
llEmployeePerformance.removeAllViews(); binding.llEmployeePerformance.removeAllViews();
for (Map.Entry<String, BigDecimal> e : empList) { for (Map.Entry<String, BigDecimal> e : empList) {
addBarRow(llEmployeePerformance, e.getKey(), addBarRow(binding.llEmployeePerformance, e.getKey(),
"$" + e.getValue().setScale(2, RoundingMode.HALF_UP), "$" + e.getValue().setScale(2, RoundingMode.HALF_UP),
e.getValue().floatValue() / maxEmp.floatValue(), e.getValue().floatValue() / maxEmp.floatValue(),
"#1a759f"); "#1a759f");
} }
if (empList.isEmpty()) if (empList.isEmpty())
addEmptyRow(llEmployeePerformance, "No data"); addEmptyRow(binding.llEmployeePerformance, "No data");
// ── Daily Revenue (last 7 days) ─────────────────────── // ── Daily Revenue (last 7 days) ───────────────────────
Map<String, BigDecimal> dailyRevenue = new TreeMap<>(); Map<String, BigDecimal> dailyRevenue = new TreeMap<>();
@@ -247,13 +237,13 @@ public class AnalyticsFragment extends Fragment {
if (maxDaily.compareTo(BigDecimal.ZERO) == 0) if (maxDaily.compareTo(BigDecimal.ZERO) == 0)
maxDaily = BigDecimal.ONE; maxDaily = BigDecimal.ONE;
llDailyRevenue.removeAllViews(); binding.llDailyRevenue.removeAllViews();
for (Map.Entry<String, BigDecimal> e : dailyRevenue.entrySet()) { for (Map.Entry<String, BigDecimal> e : dailyRevenue.entrySet()) {
// Show just MM-DD // Show just MM-DD
String label = e.getKey().length() >= 10 String label = e.getKey().length() >= 10
? e.getKey().substring(5) ? e.getKey().substring(5)
: e.getKey(); : e.getKey();
addBarRow(llDailyRevenue, label, addBarRow(binding.llDailyRevenue, label,
"$" + e.getValue().setScale(2, RoundingMode.HALF_UP), "$" + e.getValue().setScale(2, RoundingMode.HALF_UP),
e.getValue().floatValue() / maxDaily.floatValue(), e.getValue().floatValue() / maxDaily.floatValue(),
"#ff6b35"); "#ff6b35");
@@ -325,10 +315,10 @@ public class AnalyticsFragment extends Fragment {
private void showError(String msg) { private void showError(String msg) {
if (getContext() == null) if (getContext() == null)
return; return;
tvTotalRevenue.setText("Error"); binding.tvTotalRevenue.setText("Error");
tvTotalTransactions.setText(""); binding.tvTotalTransactions.setText("");
tvAvgTransaction.setText(""); binding.tvAvgTransaction.setText("");
tvTotalItems.setText(""); binding.tvTotalItems.setText("");
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
} }
} }

View File

@@ -9,66 +9,54 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.adapters.EmployeeAdapter; import com.example.petstoremobile.adapters.EmployeeAdapter;
import com.example.petstoremobile.api.RetrofitClient; import com.example.petstoremobile.api.RetrofitClient;
import com.example.petstoremobile.databinding.FragmentStaffBinding;
import com.example.petstoremobile.dtos.EmployeeDTO; import com.example.petstoremobile.dtos.EmployeeDTO;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.utils.UIUtils; import com.example.petstoremobile.utils.UIUtils;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.*; import java.util.*;
import retrofit2.*; import retrofit2.*;
public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmployeeClickListener { public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmployeeClickListener {
private FragmentStaffBinding binding;
private List<EmployeeDTO> employeeList = new ArrayList<>(); private List<EmployeeDTO> employeeList = new ArrayList<>();
private List<EmployeeDTO> filteredList = new ArrayList<>(); private List<EmployeeDTO> filteredList = new ArrayList<>();
private EmployeeAdapter adapter; private EmployeeAdapter adapter;
private SwipeRefreshLayout swipeRefresh;
private EditText etSearch;
private LinearLayout layoutFilter;
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_staff, container, false); binding = FragmentStaffBinding.inflate(inflater, container, false);
layoutFilter = view.findViewById(R.id.layoutFilterStaff);
setupRecyclerView(view); setupRecyclerView();
setupSearch(view); setupSearch();
setupSwipeRefresh(view); setupSwipeRefresh();
loadStaff(); loadStaff();
FloatingActionButton fab = view.findViewById(R.id.fabAddStaff); binding.fabAddStaff.setOnClickListener(v -> openDetail(-1));
fab.setOnClickListener(v -> openDetail(-1));
ImageButton hamburger = view.findViewById(R.id.btnHamburgerStaff); UIUtils.setupHamburgerMenu(binding.btnHamburgerStaff, this);
UIUtils.setupHamburgerMenu(hamburger, this);
ImageButton btnToggleFilter = view.findViewById(R.id.btnToggleFilterStaff); UIUtils.setupFilterToggle(binding.btnToggleFilterStaff, binding.layoutFilterStaff, binding.etSearchStaff);
UIUtils.setupFilterToggle(btnToggleFilter, layoutFilter, etSearch);
return view; return binding.getRoot();
} }
private void setupRecyclerView(View view) { private void setupRecyclerView() {
RecyclerView rv = view.findViewById(R.id.recyclerViewStaff);
adapter = new EmployeeAdapter(filteredList, this); adapter = new EmployeeAdapter(filteredList, this);
rv.setLayoutManager(new LinearLayoutManager(getContext())); binding.recyclerViewStaff.setLayoutManager(new LinearLayoutManager(getContext()));
rv.setAdapter(adapter); binding.recyclerViewStaff.setAdapter(adapter);
} }
private void setupSearch(View view) { private void setupSearch() {
etSearch = view.findViewById(R.id.etSearchStaff); UIUtils.attachSearch(binding.etSearchStaff, () -> filter(binding.etSearchStaff.getText().toString()));
UIUtils.attachSearch(etSearch, () -> filter(etSearch.getText().toString()));
} }
private void setupSwipeRefresh(View view) { private void setupSwipeRefresh() {
swipeRefresh = view.findViewById(R.id.swipeRefreshStaff); binding.swipeRefreshStaff.setOnRefreshListener(this::loadStaff);
swipeRefresh.setOnRefreshListener(this::loadStaff);
} }
private void filter(String query) { private void filter(String query) {
@@ -90,16 +78,16 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye
} }
private void loadStaff() { private void loadStaff() {
if (swipeRefresh != null) swipeRefresh.setRefreshing(true); binding.swipeRefreshStaff.setRefreshing(true);
RetrofitClient.getEmployeeApi(requireContext()).getAllEmployees(0, 100) RetrofitClient.getEmployeeApi(requireContext()).getAllEmployees(0, 100)
.enqueue(new Callback<PageResponse<EmployeeDTO>>() { .enqueue(new Callback<PageResponse<EmployeeDTO>>() {
public void onResponse(Call<PageResponse<EmployeeDTO>> c, public void onResponse(Call<PageResponse<EmployeeDTO>> c,
Response<PageResponse<EmployeeDTO>> r) { Response<PageResponse<EmployeeDTO>> r) {
if (swipeRefresh != null) swipeRefresh.setRefreshing(false); if (binding != null) binding.swipeRefreshStaff.setRefreshing(false);
if (r.isSuccessful() && r.body() != null) { if (r.isSuccessful() && r.body() != null) {
employeeList.clear(); employeeList.clear();
employeeList.addAll(r.body().getContent()); employeeList.addAll(r.body().getContent());
filter(etSearch != null ? etSearch.getText().toString() : ""); filter(binding != null ? binding.etSearchStaff.getText().toString() : "");
} else { } else {
if (getContext() != null) { if (getContext() != null) {
Toast.makeText(getContext(), "Failed to load staff", Toast.makeText(getContext(), "Failed to load staff",
@@ -108,7 +96,7 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye
} }
} }
public void onFailure(Call<PageResponse<EmployeeDTO>> c, Throwable t) { public void onFailure(Call<PageResponse<EmployeeDTO>> c, Throwable t) {
if (swipeRefresh != null) swipeRefresh.setRefreshing(false); if (binding != null) binding.swipeRefreshStaff.setRefreshing(false);
Log.e("StaffFragment", t.getMessage()); Log.e("StaffFragment", t.getMessage());
} }
}); });
@@ -135,4 +123,10 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye
public void onEmployeeClick(int position) { public void onEmployeeClick(int position) {
openDetail(position); openDetail(position);
} }
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
} }

View File

@@ -10,6 +10,7 @@ import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.RetrofitClient; import com.example.petstoremobile.api.RetrofitClient;
import com.example.petstoremobile.databinding.FragmentRefundBinding;
import com.example.petstoremobile.dtos.SaleDTO; import com.example.petstoremobile.dtos.SaleDTO;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -19,13 +20,7 @@ import retrofit2.*;
public class RefundFragment extends Fragment { public class RefundFragment extends Fragment {
private EditText etSaleId; private FragmentRefundBinding binding;
private Button btnLoadSale, btnProcessRefund, btnBack;
private TextView tvSaleInfo, tvRefundTotal;
private LinearLayout llOriginalItems, llRefundItems;
private LinearLayout cardOriginalItems, cardRefundItems, cardPayment;
private Spinner spinnerPayment;
private SaleDTO currentSale; private SaleDTO currentSale;
private List<SaleDTO> allSales = new ArrayList<>(); private List<SaleDTO> allSales = new ArrayList<>();
@@ -60,8 +55,8 @@ public class RefundFragment extends Fragment {
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_refund, container, false); binding = FragmentRefundBinding.inflate(inflater, container, false);
initViews(view);
setupSpinner(); setupSpinner();
loadAllSales(); loadAllSales();
@@ -69,34 +64,19 @@ public class RefundFragment extends Fragment {
Bundle args = getArguments(); Bundle args = getArguments();
if (args != null && args.containsKey("saleId")) { if (args != null && args.containsKey("saleId")) {
long saleId = args.getLong("saleId"); long saleId = args.getLong("saleId");
etSaleId.setText(String.valueOf(saleId)); binding.etRefundSaleId.setText(String.valueOf(saleId));
// Auto-load after sales are fetched // Auto-load after sales are fetched
} }
btnLoadSale.setOnClickListener(v -> loadSale()); binding.btnLoadSale.setOnClickListener(v -> loadSale());
btnProcessRefund.setOnClickListener(v -> processRefund()); binding.btnProcessRefund.setOnClickListener(v -> processRefund());
btnBack.setOnClickListener(v -> navigateBack()); binding.btnRefundBack.setOnClickListener(v -> navigateBack());
return view; return binding.getRoot();
}
private void initViews(View v) {
etSaleId = v.findViewById(R.id.etRefundSaleId);
btnLoadSale = v.findViewById(R.id.btnLoadSale);
btnProcessRefund= v.findViewById(R.id.btnProcessRefund);
btnBack = v.findViewById(R.id.btnRefundBack);
tvSaleInfo = v.findViewById(R.id.tvSaleInfo);
tvRefundTotal = v.findViewById(R.id.tvRefundTotal);
llOriginalItems = v.findViewById(R.id.llOriginalItems);
llRefundItems = v.findViewById(R.id.llRefundItems);
cardOriginalItems = v.findViewById(R.id.cardOriginalItems);
cardRefundItems = v.findViewById(R.id.cardRefundItems);
cardPayment = v.findViewById(R.id.cardPayment);
spinnerPayment = v.findViewById(R.id.spinnerRefundPayment);
} }
private void setupSpinner() { private void setupSpinner() {
spinnerPayment.setAdapter(new ArrayAdapter<>(requireContext(), binding.spinnerRefundPayment.setAdapter(new ArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, PAYMENT_METHODS)); android.R.layout.simple_spinner_item, PAYMENT_METHODS));
} }
@@ -121,7 +101,7 @@ public class RefundFragment extends Fragment {
} }
private void loadSale() { private void loadSale() {
String idStr = etSaleId.getText().toString().trim(); String idStr = binding.etRefundSaleId.getText().toString().trim();
if (idStr.isEmpty()) { if (idStr.isEmpty()) {
Toast.makeText(getContext(), "Enter a Sale ID", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Enter a Sale ID", Toast.LENGTH_SHORT).show();
return; return;
@@ -156,8 +136,8 @@ public class RefundFragment extends Fragment {
currentSale = found; currentSale = found;
// Show sale info // Show sale info
tvSaleInfo.setVisibility(View.VISIBLE); binding.tvSaleInfo.setVisibility(View.VISIBLE);
tvSaleInfo.setText("Sale #" + currentSale.getSaleId() binding.tvSaleInfo.setText("Sale #" + currentSale.getSaleId()
+ " | " + (currentSale.getSaleDate() != null + " | " + (currentSale.getSaleDate() != null
? currentSale.getSaleDate().substring(0, 10) : "") ? currentSale.getSaleDate().substring(0, 10) : "")
+ " | Employee: " + (currentSale.getEmployeeName() != null + " | Employee: " + (currentSale.getEmployeeName() != null
@@ -169,7 +149,7 @@ public class RefundFragment extends Fragment {
if (currentSale.getPaymentMethod() != null) { if (currentSale.getPaymentMethod() != null) {
for (int i = 0; i < PAYMENT_METHODS.length; i++) { for (int i = 0; i < PAYMENT_METHODS.length; i++) {
if (PAYMENT_METHODS[i].equalsIgnoreCase(currentSale.getPaymentMethod())) { if (PAYMENT_METHODS[i].equalsIgnoreCase(currentSale.getPaymentMethod())) {
spinnerPayment.setSelection(i); break; binding.spinnerRefundPayment.setSelection(i); break;
} }
} }
} }
@@ -187,10 +167,10 @@ public class RefundFragment extends Fragment {
refundCart.clear(); refundCart.clear();
// Show cards // Show cards
cardOriginalItems.setVisibility(View.VISIBLE); binding.cardOriginalItems.setVisibility(View.VISIBLE);
cardRefundItems.setVisibility(View.VISIBLE); binding.cardRefundItems.setVisibility(View.VISIBLE);
cardPayment.setVisibility(View.VISIBLE); binding.cardPayment.setVisibility(View.VISIBLE);
btnProcessRefund.setVisibility(View.VISIBLE); binding.btnProcessRefund.setVisibility(View.VISIBLE);
renderOriginalItems(); renderOriginalItems();
renderRefundCart(); renderRefundCart();
@@ -233,10 +213,10 @@ public class RefundFragment extends Fragment {
} }
private void renderOriginalItems() { private void renderOriginalItems() {
llOriginalItems.removeAllViews(); binding.llOriginalItems.removeAllViews();
// Header // Header
addTableHeader(llOriginalItems); addTableHeader(binding.llOriginalItems);
for (RefundItem item : availableItems) { for (RefundItem item : availableItems) {
// Calculate pending in cart // Calculate pending in cart
@@ -254,23 +234,23 @@ public class RefundFragment extends Fragment {
true, // show add button true, // show add button
() -> showQuantityDialog(item) () -> showQuantityDialog(item)
); );
llOriginalItems.addView(row); binding.llOriginalItems.addView(row);
} }
} }
private void renderRefundCart() { private void renderRefundCart() {
llRefundItems.removeAllViews(); binding.llRefundItems.removeAllViews();
if (refundCart.isEmpty()) { if (refundCart.isEmpty()) {
TextView empty = new TextView(getContext()); TextView empty = new TextView(getContext());
empty.setText("No items added to refund yet"); empty.setText("No items added to refund yet");
empty.setTextColor(0xFF888780); empty.setTextColor(0xFF888780);
empty.setTextSize(13f); empty.setTextSize(13f);
llRefundItems.addView(empty); binding.llRefundItems.addView(empty);
return; return;
} }
addTableHeader(llRefundItems); addTableHeader(binding.llRefundItems);
for (RefundItem item : refundCart) { for (RefundItem item : refundCart) {
LinearLayout row = buildItemRow( LinearLayout row = buildItemRow(
@@ -285,7 +265,7 @@ public class RefundFragment extends Fragment {
updateRefundTotal(); updateRefundTotal();
} }
); );
llRefundItems.addView(row); binding.llRefundItems.addView(row);
} }
} }
@@ -428,7 +408,7 @@ public class RefundFragment extends Fragment {
private void updateRefundTotal() { private void updateRefundTotal() {
BigDecimal total = BigDecimal.ZERO; BigDecimal total = BigDecimal.ZERO;
for (RefundItem item : refundCart) total = total.add(item.getTotal()); for (RefundItem item : refundCart) total = total.add(item.getTotal());
tvRefundTotal.setText("Refund Total: $" + total.setScale(2, RoundingMode.HALF_UP)); binding.tvRefundTotal.setText("Refund Total: $" + total.setScale(2, RoundingMode.HALF_UP));
} }
private void processRefund() { private void processRefund() {
@@ -442,7 +422,7 @@ public class RefundFragment extends Fragment {
return; return;
} }
String payment = PAYMENT_METHODS[spinnerPayment.getSelectedItemPosition()]; String payment = PAYMENT_METHODS[binding.spinnerRefundPayment.getSelectedItemPosition()];
// Confirm dialog // Confirm dialog
BigDecimal total = BigDecimal.ZERO; BigDecimal total = BigDecimal.ZERO;
@@ -507,4 +487,10 @@ public class RefundFragment extends Fragment {
private void navigateBack() { private void navigateBack() {
NavHostFragment.findNavController(this).popBackStack(); NavHostFragment.findNavController(this).popBackStack();
} }
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
} }

View File

@@ -5,11 +5,11 @@ import android.util.Log;
import android.view.*; import android.view.*;
import android.widget.*; import android.widget.*;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.*; import com.example.petstoremobile.api.*;
import com.example.petstoremobile.databinding.FragmentSaleDetailBinding;
import com.example.petstoremobile.dtos.*; import com.example.petstoremobile.dtos.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.*; import java.util.*;
@@ -17,11 +17,7 @@ import retrofit2.*;
public class SaleDetailFragment extends Fragment { public class SaleDetailFragment extends Fragment {
private TextView tvMode, tvSaleDetailId, tvTotal; private FragmentSaleDetailBinding binding;
private Spinner spinnerStore, spinnerCustomer, spinnerPayment, spinnerProduct;
private EditText etQuantity;
private Button btnAddItem, btnSave, btnBack, btnRefund;
private LinearLayout llItems;
private boolean viewOnly = false; private boolean viewOnly = false;
private long saleId = -1; private long saleId = -1;
@@ -36,8 +32,11 @@ public class SaleDetailFragment extends Fragment {
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_sale_detail, container, false); binding = FragmentSaleDetailBinding.inflate(inflater, container, false);
initViews(view);
binding.spinnerPaymentMethod.setAdapter(new ArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, PAYMENT_METHODS));
handleArguments(); handleArguments();
if (!viewOnly) { if (!viewOnly) {
@@ -45,30 +44,11 @@ public class SaleDetailFragment extends Fragment {
setupAddItem(); setupAddItem();
} }
btnBack.setOnClickListener(v -> navigateBack()); binding.btnSaleBack.setOnClickListener(v -> navigateBack());
btnSave.setOnClickListener(v -> saveSale()); binding.btnSaveSale.setOnClickListener(v -> saveSale());
btnRefund.setOnClickListener(v -> showRefundDialog()); binding.btnRefundSale.setOnClickListener(v -> showRefundDialog());
return view; return binding.getRoot();
}
private void initViews(View v) {
tvMode = v.findViewById(R.id.tvSaleMode);
tvSaleDetailId = v.findViewById(R.id.tvSaleDetailId);
tvTotal = v.findViewById(R.id.tvSaleDetailTotal);
spinnerStore = v.findViewById(R.id.spinnerSaleStore);
spinnerCustomer = v.findViewById(R.id.spinnerSaleCustomer);
spinnerPayment = v.findViewById(R.id.spinnerPaymentMethod);
spinnerProduct = v.findViewById(R.id.spinnerSaleProduct);
etQuantity = v.findViewById(R.id.etSaleQuantity);
btnAddItem = v.findViewById(R.id.btnAddItem);
btnSave = v.findViewById(R.id.btnSaveSale);
btnBack = v.findViewById(R.id.btnSaleBack);
btnRefund = v.findViewById(R.id.btnRefundSale);
llItems = v.findViewById(R.id.llSaleItems);
spinnerPayment.setAdapter(new ArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, PAYMENT_METHODS));
} }
private void handleArguments() { private void handleArguments() {
@@ -76,31 +56,31 @@ public class SaleDetailFragment extends Fragment {
if (a != null && a.containsKey("saleId")) { if (a != null && a.containsKey("saleId")) {
saleId = a.getLong("saleId"); saleId = a.getLong("saleId");
viewOnly = a.getBoolean("viewOnly", false); viewOnly = a.getBoolean("viewOnly", false);
tvMode.setText("Sale #" + saleId); binding.tvSaleMode.setText("Sale #" + saleId);
tvSaleDetailId.setText("ID: " + saleId); binding.tvSaleDetailId.setText("ID: " + saleId);
// Show refund button for existing non-refund sales // Show refund button for existing non-refund sales
if (!a.getBoolean("isRefund", false)) { if (!a.getBoolean("isRefund", false)) {
btnRefund.setVisibility(View.VISIBLE); binding.btnRefundSale.setVisibility(View.VISIBLE);
} }
// Hide save and input controls for view only // Hide save and input controls for view only
if (viewOnly) { if (viewOnly) {
btnSave.setVisibility(View.GONE); binding.btnSaveSale.setVisibility(View.GONE);
spinnerStore.setEnabled(false); binding.spinnerSaleStore.setEnabled(false);
spinnerCustomer.setEnabled(false); binding.spinnerSaleCustomer.setEnabled(false);
spinnerPayment.setEnabled(false); binding.spinnerPaymentMethod.setEnabled(false);
spinnerProduct.setEnabled(false); binding.spinnerSaleProduct.setEnabled(false);
etQuantity.setEnabled(false); binding.etSaleQuantity.setEnabled(false);
btnAddItem.setEnabled(false); binding.btnAddItem.setEnabled(false);
} }
// Load sale details // Load sale details
loadSaleDetails(); loadSaleDetails();
} else { } else {
tvMode.setText("New Sale"); binding.tvSaleMode.setText("New Sale");
tvSaleDetailId.setVisibility(View.GONE); binding.tvSaleDetailId.setVisibility(View.GONE);
btnRefund.setVisibility(View.GONE); binding.btnRefundSale.setVisibility(View.GONE);
} }
} }
@@ -117,7 +97,7 @@ public class SaleDetailFragment extends Fragment {
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
names.add("-- Select Store --"); names.add("-- Select Store --");
names.add("Downtown Branch"); names.add("Downtown Branch");
spinnerStore.setAdapter(new ArrayAdapter<>(requireContext(), binding.spinnerSaleStore.setAdapter(new ArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names)); android.R.layout.simple_spinner_item, names));
} }
@@ -132,8 +112,10 @@ public class SaleDetailFragment extends Fragment {
names.add("-- No Customer --"); names.add("-- No Customer --");
for (CustomerDTO cu : customerList) for (CustomerDTO cu : customerList)
names.add(cu.getFirstName() + " " + cu.getLastName()); names.add(cu.getFirstName() + " " + cu.getLastName());
spinnerCustomer.setAdapter(new ArrayAdapter<>(requireContext(), if (binding != null) {
android.R.layout.simple_spinner_item, names)); binding.spinnerSaleCustomer.setAdapter(new ArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
}
} }
} }
@@ -154,8 +136,10 @@ public class SaleDetailFragment extends Fragment {
names.add("-- Select Product --"); names.add("-- Select Product --");
for (ProductDTO p : productList) for (ProductDTO p : productList)
names.add(p.getProdName()); names.add(p.getProdName());
spinnerProduct.setAdapter(new ArrayAdapter<>(requireContext(), if (binding != null) {
android.R.layout.simple_spinner_item, names)); binding.spinnerSaleProduct.setAdapter(new ArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
}
} }
} }
@@ -171,14 +155,16 @@ public class SaleDetailFragment extends Fragment {
public void onResponse(Call<SaleDTO> c, Response<SaleDTO> r) { public void onResponse(Call<SaleDTO> c, Response<SaleDTO> r) {
if (r.isSuccessful() && r.body() != null) { if (r.isSuccessful() && r.body() != null) {
SaleDTO sale = r.body(); SaleDTO sale = r.body();
tvTotal.setText("Total: $" + sale.getTotalAmount()); if (binding != null) {
// Display items binding.tvSaleDetailTotal.setText("Total: $" + sale.getTotalAmount());
if (sale.getItems() != null) { // Display items
llItems.removeAllViews(); if (sale.getItems() != null) {
for (SaleDTO.SaleItemDTO item : sale.getItems()) { binding.llSaleItems.removeAllViews();
addItemRow(item.getProductName(), for (SaleDTO.SaleItemDTO item : sale.getItems()) {
Math.abs(item.getQuantity()), addItemRow(item.getProductName(),
item.getUnitPrice()); Math.abs(item.getQuantity()),
item.getUnitPrice());
}
} }
} }
} }
@@ -191,25 +177,25 @@ public class SaleDetailFragment extends Fragment {
} }
private void setupAddItem() { private void setupAddItem() {
btnAddItem.setOnClickListener(v -> { binding.btnAddItem.setOnClickListener(v -> {
if (spinnerProduct.getSelectedItemPosition() == 0) { if (binding.spinnerSaleProduct.getSelectedItemPosition() == 0) {
Toast.makeText(getContext(), "Select a product", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Select a product", Toast.LENGTH_SHORT).show();
return; return;
} }
String qtyStr = etQuantity.getText().toString().trim(); String qtyStr = binding.etSaleQuantity.getText().toString().trim();
if (qtyStr.isEmpty()) { if (qtyStr.isEmpty()) {
etQuantity.setError("Enter quantity"); binding.etSaleQuantity.setError("Enter quantity");
return; return;
} }
int qty; int qty;
try { try {
qty = Integer.parseInt(qtyStr); qty = Integer.parseInt(qtyStr);
} catch (Exception e) { } catch (Exception e) {
etQuantity.setError("Invalid quantity"); binding.etSaleQuantity.setError("Invalid quantity");
return; return;
} }
ProductDTO product = productList.get(spinnerProduct.getSelectedItemPosition() - 1); ProductDTO product = productList.get(binding.spinnerSaleProduct.getSelectedItemPosition() - 1);
// Check if product already in cart // Check if product already in cart
for (SaleDTO.SaleItemDTO existing : cartItems) { for (SaleDTO.SaleItemDTO existing : cartItems) {
@@ -223,7 +209,7 @@ public class SaleDetailFragment extends Fragment {
cartItems.add(item); cartItems.add(item);
addItemRow(product.getProdName(), qty, product.getProdPrice()); addItemRow(product.getProdName(), qty, product.getProdPrice());
updateTotal(); updateTotal();
etQuantity.setText(""); binding.etSaleQuantity.setText("");
}); });
} }
@@ -250,28 +236,25 @@ public class SaleDetailFragment extends Fragment {
row.addView(tvName); row.addView(tvName);
row.addView(tvQty); row.addView(tvQty);
row.addView(tvPrice); row.addView(tvPrice);
llItems.addView(row); binding.llSaleItems.addView(row);
} }
private void updateTotal() { private void updateTotal() {
BigDecimal total = BigDecimal.ZERO; BigDecimal total = BigDecimal.ZERO;
int productIdx = 0;
for (SaleDTO.SaleItemDTO item : cartItems) { for (SaleDTO.SaleItemDTO item : cartItems) {
if (productIdx < productList.size()) { for (ProductDTO p : productList) {
for (ProductDTO p : productList) { if (p.getProdId().equals(item.getProdId()) && p.getProdPrice() != null) {
if (p.getProdId().equals(item.getProdId()) && p.getProdPrice() != null) { total = total.add(p.getProdPrice()
total = total.add(p.getProdPrice() .multiply(BigDecimal.valueOf(item.getQuantity())));
.multiply(BigDecimal.valueOf(item.getQuantity()))); break;
break;
}
} }
} }
} }
tvTotal.setText("Total: $" + total); binding.tvSaleDetailTotal.setText("Total: $" + total);
} }
private void saveSale() { private void saveSale() {
if (spinnerStore.getSelectedItemPosition() == 0) { if (binding.spinnerSaleStore.getSelectedItemPosition() == 0) {
Toast.makeText(getContext(), "Select a store", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Select a store", Toast.LENGTH_SHORT).show();
return; return;
} }
@@ -281,12 +264,12 @@ public class SaleDetailFragment extends Fragment {
} }
StoreDTO store = storeList.get(0); // only one store StoreDTO store = storeList.get(0); // only one store
String payment = PAYMENT_METHODS[spinnerPayment.getSelectedItemPosition()]; String payment = PAYMENT_METHODS[binding.spinnerPaymentMethod.getSelectedItemPosition()];
// Optional customer // Optional customer
Long customerId = null; Long customerId = null;
if (spinnerCustomer.getSelectedItemPosition() > 0) { if (binding.spinnerSaleCustomer.getSelectedItemPosition() > 0) {
customerId = customerList.get(spinnerCustomer.getSelectedItemPosition() - 1) customerId = customerList.get(binding.spinnerSaleCustomer.getSelectedItemPosition() - 1)
.getCustomerId(); .getCustomerId();
} }
@@ -298,11 +281,6 @@ public class SaleDetailFragment extends Fragment {
null, null,
customerId); customerId);
Log.d("SALE_SAVE", "storeId=" + store.getStoreId()
+ " payment=" + payment
+ " items=" + cartItems.size()
+ " customerId=" + customerId);
RetrofitClient.getSaleApi(requireContext()).createSale(dto) RetrofitClient.getSaleApi(requireContext()).createSale(dto)
.enqueue(new Callback<SaleDTO>() { .enqueue(new Callback<SaleDTO>() {
public void onResponse(Call<SaleDTO> c, Response<SaleDTO> r) { public void onResponse(Call<SaleDTO> c, Response<SaleDTO> r) {
@@ -334,35 +312,13 @@ public class SaleDetailFragment extends Fragment {
NavHostFragment.findNavController(this).navigate(R.id.nav_refund, args); NavHostFragment.findNavController(this).navigate(R.id.nav_refund, args);
} }
private void submitRefund() {
RefundDTO refundDTO = new RefundDTO(saleId, "Refund requested from mobile app");
RetrofitClient.getRefundApi(requireContext()).createRefund(refundDTO)
.enqueue(new Callback<RefundDTO>() {
public void onResponse(Call<RefundDTO> c, Response<RefundDTO> r) {
if (r.isSuccessful()) {
Toast.makeText(getContext(), "Refund request submitted!",
Toast.LENGTH_SHORT).show();
btnRefund.setVisibility(View.GONE);
} else {
try {
String err = r.errorBody().string();
Log.e("REFUND", "Error: " + err);
Toast.makeText(getContext(), "Error: " + err,
Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.e("REFUND", "Failed to read error");
}
}
}
public void onFailure(Call<RefundDTO> c, Throwable t) {
Log.e("REFUND", "Failure: " + t.getMessage());
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
}
});
}
private void navigateBack() { private void navigateBack() {
NavHostFragment.findNavController(this).popBackStack(); NavHostFragment.findNavController(this).popBackStack();
} }
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
} }

View File

@@ -11,16 +11,13 @@ import androidx.navigation.fragment.NavHostFragment;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.EmployeeApi; import com.example.petstoremobile.api.EmployeeApi;
import com.example.petstoremobile.api.RetrofitClient; import com.example.petstoremobile.api.RetrofitClient;
import com.example.petstoremobile.databinding.FragmentStaffDetailBinding;
import com.example.petstoremobile.dtos.EmployeeDTO; import com.example.petstoremobile.dtos.EmployeeDTO;
import retrofit2.*; import retrofit2.*;
public class StaffDetailFragment extends Fragment { public class StaffDetailFragment extends Fragment {
private TextView tvMode, tvStaffId; private FragmentStaffDetailBinding binding;
private EditText etUsername, etPassword, etFirstName, etLastName, etEmail, etPhone;
private Spinner spinnerRole, spinnerStatus;
private Button btnSave, btnDelete, btnBack;
private long employeeId = -1; private long employeeId = -1;
private boolean isEditing = false; private boolean isEditing = false;
@@ -30,37 +27,21 @@ public class StaffDetailFragment extends Fragment {
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_staff_detail, container, false); binding = FragmentStaffDetailBinding.inflate(inflater, container, false);
initViews(view);
setupSpinners(); setupSpinners();
handleArguments(); handleArguments();
btnBack.setOnClickListener(v -> navigateBack()); binding.btnStaffBack.setOnClickListener(v -> navigateBack());
btnSave.setOnClickListener(v -> save()); binding.btnSaveStaff.setOnClickListener(v -> save());
btnDelete.setOnClickListener(v -> confirmDelete()); binding.btnDeleteStaff.setOnClickListener(v -> confirmDelete());
return view; return binding.getRoot();
}
private void initViews(View v) {
tvMode = v.findViewById(R.id.tvStaffMode);
tvStaffId = v.findViewById(R.id.tvStaffId);
etUsername = v.findViewById(R.id.etStaffUsername);
etPassword = v.findViewById(R.id.etStaffPassword);
etFirstName = v.findViewById(R.id.etStaffFirstName);
etLastName = v.findViewById(R.id.etStaffLastName);
etEmail = v.findViewById(R.id.etStaffEmail);
etPhone = v.findViewById(R.id.etStaffPhone);
spinnerRole = v.findViewById(R.id.spinnerStaffRole);
spinnerStatus = v.findViewById(R.id.spinnerStaffStatus);
btnSave = v.findViewById(R.id.btnSaveStaff);
btnDelete = v.findViewById(R.id.btnDeleteStaff);
btnBack = v.findViewById(R.id.btnStaffBack);
} }
private void setupSpinners() { private void setupSpinners() {
spinnerRole.setAdapter(new ArrayAdapter<>(requireContext(), binding.spinnerStaffRole.setAdapter(new ArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, ROLES)); android.R.layout.simple_spinner_item, ROLES));
spinnerStatus.setAdapter(new ArrayAdapter<>(requireContext(), binding.spinnerStaffStatus.setAdapter(new ArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, STATUSES)); android.R.layout.simple_spinner_item, STATUSES));
} }
@@ -70,61 +51,61 @@ public class StaffDetailFragment extends Fragment {
isEditing = true; isEditing = true;
employeeId = a.getLong("employeeId", -1); employeeId = a.getLong("employeeId", -1);
tvMode.setText("Edit Staff Account"); binding.tvStaffMode.setText("Edit Staff Account");
tvStaffId.setText("ID: " + employeeId); binding.tvStaffId.setText("ID: " + employeeId);
tvStaffId.setVisibility(View.VISIBLE); binding.tvStaffId.setVisibility(View.VISIBLE);
etUsername.setText(a.getString("username", "")); binding.etStaffUsername.setText(a.getString("username", ""));
etFirstName.setText(a.getString("firstName", "")); binding.etStaffFirstName.setText(a.getString("firstName", ""));
etLastName.setText(a.getString("lastName", "")); binding.etStaffLastName.setText(a.getString("lastName", ""));
etEmail.setText(a.getString("email", "")); // ← was showing fullName binding.etStaffEmail.setText(a.getString("email", ""));
etPhone.setText(a.getString("phone", "")); binding.etStaffPhone.setText(a.getString("phone", ""));
btnDelete.setVisibility(View.VISIBLE); binding.btnDeleteStaff.setVisibility(View.VISIBLE);
// Pre-fill role // Pre-fill role
String role = a.getString("role", "STAFF"); String role = a.getString("role", "STAFF");
for (int i = 0; i < ROLES.length; i++) { for (int i = 0; i < ROLES.length; i++) {
if (ROLES[i].equals(role)) { if (ROLES[i].equals(role)) {
spinnerRole.setSelection(i); binding.spinnerStaffRole.setSelection(i);
break; break;
} }
} }
// Pre-fill status // Pre-fill status
boolean active = a.getBoolean("active", true); boolean active = a.getBoolean("active", true);
spinnerStatus.setSelection(active ? 0 : 1); binding.spinnerStaffStatus.setSelection(active ? 0 : 1);
} else { } else {
isEditing = false; isEditing = false;
employeeId = -1; employeeId = -1;
tvMode.setText("Add Staff Account"); binding.tvStaffMode.setText("Add Staff Account");
btnDelete.setVisibility(View.GONE); binding.btnDeleteStaff.setVisibility(View.GONE);
tvStaffId.setVisibility(View.GONE); binding.tvStaffId.setVisibility(View.GONE);
} }
} }
private void save() { private void save() {
String username = etUsername.getText() != null ? etUsername.getText().toString().trim() : ""; String username = binding.etStaffUsername.getText() != null ? binding.etStaffUsername.getText().toString().trim() : "";
String password = etPassword.getText() != null ? etPassword.getText().toString().trim() : ""; String password = binding.etStaffPassword.getText() != null ? binding.etStaffPassword.getText().toString().trim() : "";
String firstName = etFirstName.getText() != null ? etFirstName.getText().toString().trim() : ""; String firstName = binding.etStaffFirstName.getText() != null ? binding.etStaffFirstName.getText().toString().trim() : "";
String lastName = etLastName.getText() != null ? etLastName.getText().toString().trim() : ""; String lastName = binding.etStaffLastName.getText() != null ? binding.etStaffLastName.getText().toString().trim() : "";
String email = etEmail.getText() != null ? etEmail.getText().toString().trim() : ""; String email = binding.etStaffEmail.getText() != null ? binding.etStaffEmail.getText().toString().trim() : "";
String phone = etPhone.getText() != null ? etPhone.getText().toString().trim() : ""; String phone = binding.etStaffPhone.getText() != null ? binding.etStaffPhone.getText().toString().trim() : "";
String role = ROLES[spinnerRole.getSelectedItemPosition()]; String role = ROLES[binding.spinnerStaffRole.getSelectedItemPosition()];
boolean active = spinnerStatus.getSelectedItemPosition() == 0; boolean active = binding.spinnerStaffStatus.getSelectedItemPosition() == 0;
// Validation // Validation
if (username.isEmpty()) { etUsername.setError("Required"); return; } if (username.isEmpty()) { binding.etStaffUsername.setError("Required"); return; }
if (!isEditing && password.isEmpty()) { if (!isEditing && password.isEmpty()) {
etPassword.setError("Required for new account"); return; binding.etStaffPassword.setError("Required for new account"); return;
} }
if (!isEditing && password.length() < 6) { if (!isEditing && password.length() < 6) {
etPassword.setError("At least 6 characters"); return; binding.etStaffPassword.setError("At least 6 characters"); return;
} }
if (firstName.isEmpty()) { etFirstName.setError("Required"); return; } if (firstName.isEmpty()) { binding.etStaffFirstName.setError("Required"); return; }
if (lastName.isEmpty()) { etLastName.setError("Required"); return; } if (lastName.isEmpty()) { binding.etStaffLastName.setError("Required"); return; }
if (email.isEmpty()) { etEmail.setError("Required"); return; } if (email.isEmpty()) { binding.etStaffEmail.setError("Required"); return; }
if (phone.isEmpty()) { etPhone.setError("Required"); return; } if (phone.isEmpty()) { binding.etStaffPhone.setError("Required"); return; }
EmployeeDTO dto = new EmployeeDTO( EmployeeDTO dto = new EmployeeDTO(
username, username,
@@ -137,10 +118,6 @@ public class StaffDetailFragment extends Fragment {
active active
); );
Log.d("STAFF_SAVE", "isEditing=" + isEditing
+ " employeeId=" + employeeId
+ " username=" + username);
EmployeeApi api = RetrofitClient.getEmployeeApi(requireContext()); EmployeeApi api = RetrofitClient.getEmployeeApi(requireContext());
if (isEditing && employeeId > 0) { if (isEditing && employeeId > 0) {
api.updateEmployee(employeeId, dto).enqueue(simpleCallback("Updated successfully")); api.updateEmployee(employeeId, dto).enqueue(simpleCallback("Updated successfully"));
@@ -152,14 +129,12 @@ public class StaffDetailFragment extends Fragment {
private Callback<EmployeeDTO> simpleCallback(String msg) { private Callback<EmployeeDTO> simpleCallback(String msg) {
return new Callback<>() { return new Callback<>() {
public void onResponse(Call<EmployeeDTO> c, Response<EmployeeDTO> r) { public void onResponse(Call<EmployeeDTO> c, Response<EmployeeDTO> r) {
Log.d("STAFF_SAVE", "Response: " + r.code());
if (r.isSuccessful()) { if (r.isSuccessful()) {
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
navigateBack(); navigateBack();
} else { } else {
try { try {
String err = r.errorBody().string(); String err = r.errorBody().string();
Log.e("STAFF_SAVE", "Error: " + err);
Toast.makeText(getContext(), "Error " + r.code() + ": " + err, Toast.makeText(getContext(), "Error " + r.code() + ": " + err,
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
} catch (Exception e) { } catch (Exception e) {
@@ -168,7 +143,6 @@ public class StaffDetailFragment extends Fragment {
} }
} }
public void onFailure(Call<EmployeeDTO> c, Throwable t) { public void onFailure(Call<EmployeeDTO> c, Throwable t) {
Log.e("STAFF_SAVE", "Failure: " + t.getMessage());
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
} }
}; };
@@ -196,4 +170,10 @@ public class StaffDetailFragment extends Fragment {
private void navigateBack() { private void navigateBack() {
NavHostFragment.findNavController(this).popBackStack(); NavHostFragment.findNavController(this).popBackStack();
} }
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
} }