made admin analyics able to select store
This commit is contained in:
@@ -57,11 +57,13 @@ public class AnalyticsFragment extends Fragment {
|
|||||||
binding.btnMyAnalytics.setOnClickListener(v -> {
|
binding.btnMyAnalytics.setOnClickListener(v -> {
|
||||||
viewModel.setViewMode("mine");
|
viewModel.setViewMode("mine");
|
||||||
updateViewModeButtonStyles("mine");
|
updateViewModeButtonStyles("mine");
|
||||||
|
updateStoreFilterVisibility("mine");
|
||||||
});
|
});
|
||||||
|
|
||||||
binding.btnStoreAnalytics.setOnClickListener(v -> {
|
binding.btnStoreAnalytics.setOnClickListener(v -> {
|
||||||
viewModel.setViewMode("store");
|
viewModel.setViewMode("store");
|
||||||
updateViewModeButtonStyles("store");
|
updateViewModeButtonStyles("store");
|
||||||
|
updateStoreFilterVisibility("store");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +74,13 @@ public class AnalyticsFragment extends Fragment {
|
|||||||
android.content.res.ColorStateList.valueOf(mode.equals("store") ? COLOR_SELECTED : COLOR_UNSELECTED));
|
android.content.res.ColorStateList.valueOf(mode.equals("store") ? COLOR_SELECTED : COLOR_UNSELECTED));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateStoreFilterVisibility(String mode) {
|
||||||
|
boolean isAdmin = "ADMIN".equalsIgnoreCase(tokenManager.getRole());
|
||||||
|
int vis = (isAdmin && mode.equals("store")) ? View.VISIBLE : View.GONE;
|
||||||
|
binding.tvStoreFilterLabel.setVisibility(vis);
|
||||||
|
binding.spinnerFilterStore.setVisibility(vis);
|
||||||
|
}
|
||||||
|
|
||||||
// Filter Panel
|
// Filter Panel
|
||||||
|
|
||||||
private void setupFilterPanel() {
|
private void setupFilterPanel() {
|
||||||
@@ -126,6 +135,9 @@ public class AnalyticsFragment extends Fragment {
|
|||||||
int topNPos = binding.spinnerTopN.getSelectedItemPosition();
|
int topNPos = binding.spinnerTopN.getSelectedItemPosition();
|
||||||
filter.topN = (topNPos >= 0 && topNPos < TOP_N_VALUES.length) ? TOP_N_VALUES[topNPos] : 5;
|
filter.topN = (topNPos >= 0 && topNPos < TOP_N_VALUES.length) ? TOP_N_VALUES[topNPos] : 5;
|
||||||
|
|
||||||
|
Object store = binding.spinnerFilterStore.getSelectedItem();
|
||||||
|
viewModel.setStoreFilter(store != null ? store.toString() : "All Stores");
|
||||||
|
|
||||||
updateFilterSummary();
|
updateFilterSummary();
|
||||||
viewModel.applyFilter(filter);
|
viewModel.applyFilter(filter);
|
||||||
}
|
}
|
||||||
@@ -134,8 +146,8 @@ public class AnalyticsFragment extends Fragment {
|
|||||||
binding.etFilterStartDate.setText("");
|
binding.etFilterStartDate.setText("");
|
||||||
binding.etFilterEndDate.setText("");
|
binding.etFilterEndDate.setText("");
|
||||||
binding.spinnerTopN.setSelection(0);
|
binding.spinnerTopN.setSelection(0);
|
||||||
// Reset payment method to "All"
|
|
||||||
SpinnerUtils.setSelectionByValue(binding.spinnerFilterPayment, "All");
|
SpinnerUtils.setSelectionByValue(binding.spinnerFilterPayment, "All");
|
||||||
|
SpinnerUtils.setSelectionByValue(binding.spinnerFilterStore, "All Stores");
|
||||||
updateFilterSummary();
|
updateFilterSummary();
|
||||||
viewModel.resetFilter();
|
viewModel.resetFilter();
|
||||||
}
|
}
|
||||||
@@ -192,6 +204,16 @@ public class AnalyticsFragment extends Fragment {
|
|||||||
methods.toArray(new String[0]));
|
methods.toArray(new String[0]));
|
||||||
SpinnerUtils.setSelectionByValue(binding.spinnerFilterPayment, currentSelection);
|
SpinnerUtils.setSelectionByValue(binding.spinnerFilterPayment, currentSelection);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
viewModel.getAvailableStores().observe(getViewLifecycleOwner(), stores -> {
|
||||||
|
if (stores == null || stores.isEmpty()) return;
|
||||||
|
String currentSelection = binding.spinnerFilterStore.getSelectedItem() != null
|
||||||
|
? binding.spinnerFilterStore.getSelectedItem().toString() : "All Stores";
|
||||||
|
SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerFilterStore,
|
||||||
|
stores.toArray(new String[0]));
|
||||||
|
SpinnerUtils.setSelectionByValue(binding.spinnerFilterStore, currentSelection);
|
||||||
|
updateStoreFilterVisibility(viewModel.getViewMode());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -37,10 +37,12 @@ public class AnalyticsViewModel extends ViewModel {
|
|||||||
private final MutableLiveData<Boolean> isLoading = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> isLoading = new MutableLiveData<>(false);
|
||||||
private final MutableLiveData<String> errorMessage = new MutableLiveData<>();
|
private final MutableLiveData<String> errorMessage = new MutableLiveData<>();
|
||||||
private final MutableLiveData<List<String>> availablePaymentMethods = new MutableLiveData<>(new ArrayList<>());
|
private final MutableLiveData<List<String>> availablePaymentMethods = new MutableLiveData<>(new ArrayList<>());
|
||||||
|
private final MutableLiveData<List<String>> availableStores = new MutableLiveData<>(new ArrayList<>());
|
||||||
|
|
||||||
private List<SaleDTO> cachedSales = new ArrayList<>();
|
private List<SaleDTO> cachedSales = new ArrayList<>();
|
||||||
private FilterState currentFilter = new FilterState();
|
private FilterState currentFilter = new FilterState();
|
||||||
private String viewMode = "store";
|
private String viewMode = "store";
|
||||||
|
private String storeFilter = "All Stores";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public AnalyticsViewModel(SaleRepository saleRepository, TokenManager tokenManager) {
|
public AnalyticsViewModel(SaleRepository saleRepository, TokenManager tokenManager) {
|
||||||
@@ -52,6 +54,7 @@ public class AnalyticsViewModel extends ViewModel {
|
|||||||
public LiveData<Boolean> getIsLoading() { return isLoading; }
|
public LiveData<Boolean> getIsLoading() { return isLoading; }
|
||||||
public LiveData<String> getErrorMessage() { return errorMessage; }
|
public LiveData<String> getErrorMessage() { return errorMessage; }
|
||||||
public LiveData<List<String>> getAvailablePaymentMethods() { return availablePaymentMethods; }
|
public LiveData<List<String>> getAvailablePaymentMethods() { return availablePaymentMethods; }
|
||||||
|
public LiveData<List<String>> getAvailableStores() { return availableStores; }
|
||||||
|
|
||||||
public void loadAnalytics() {
|
public void loadAnalytics() {
|
||||||
isLoading.setValue(true);
|
isLoading.setValue(true);
|
||||||
@@ -61,6 +64,7 @@ public class AnalyticsViewModel extends ViewModel {
|
|||||||
if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
|
if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
|
||||||
cachedSales = resource.data.getContent();
|
cachedSales = resource.data.getContent();
|
||||||
derivePaymentMethods();
|
derivePaymentMethods();
|
||||||
|
deriveStores();
|
||||||
applyCurrentFilter();
|
applyCurrentFilter();
|
||||||
isLoading.setValue(false);
|
isLoading.setValue(false);
|
||||||
} else if (resource.status == Resource.Status.ERROR) {
|
} else if (resource.status == Resource.Status.ERROR) {
|
||||||
@@ -78,6 +82,7 @@ public class AnalyticsViewModel extends ViewModel {
|
|||||||
|
|
||||||
public void resetFilter() {
|
public void resetFilter() {
|
||||||
currentFilter = new FilterState();
|
currentFilter = new FilterState();
|
||||||
|
storeFilter = "All Stores";
|
||||||
applyCurrentFilter();
|
applyCurrentFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +95,15 @@ public class AnalyticsViewModel extends ViewModel {
|
|||||||
return viewMode;
|
return viewMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setStoreFilter(String store) {
|
||||||
|
storeFilter = (store != null && !store.isEmpty()) ? store : "All Stores";
|
||||||
|
applyCurrentFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStoreFilter() {
|
||||||
|
return storeFilter;
|
||||||
|
}
|
||||||
|
|
||||||
private void applyCurrentFilter() {
|
private void applyCurrentFilter() {
|
||||||
List<SaleDTO> salesForMode;
|
List<SaleDTO> salesForMode;
|
||||||
if (viewMode.equals("mine")) {
|
if (viewMode.equals("mine")) {
|
||||||
@@ -100,10 +114,29 @@ public class AnalyticsViewModel extends ViewModel {
|
|||||||
} else {
|
} else {
|
||||||
salesForMode = cachedSales;
|
salesForMode = cachedSales;
|
||||||
}
|
}
|
||||||
|
if (!storeFilter.equals("All Stores") && !storeFilter.isEmpty()) {
|
||||||
|
final String sf = storeFilter;
|
||||||
|
salesForMode = salesForMode.stream()
|
||||||
|
.filter(s -> sf.equalsIgnoreCase(s.getStoreName() != null ? s.getStoreName() : ""))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
List<SaleDTO> filtered = filterSales(salesForMode, currentFilter);
|
List<SaleDTO> filtered = filterSales(salesForMode, currentFilter);
|
||||||
computeAnalytics(filtered, currentFilter);
|
computeAnalytics(filtered, currentFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deriveStores() {
|
||||||
|
java.util.Set<String> stores = new java.util.TreeSet<>();
|
||||||
|
for (SaleDTO s : cachedSales) {
|
||||||
|
if (s.getStoreName() != null && !s.getStoreName().isEmpty()) {
|
||||||
|
stores.add(s.getStoreName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
result.add("All Stores");
|
||||||
|
result.addAll(stores);
|
||||||
|
availableStores.setValue(result);
|
||||||
|
}
|
||||||
|
|
||||||
private void derivePaymentMethods() {
|
private void derivePaymentMethods() {
|
||||||
java.util.Set<String> methods = new java.util.TreeSet<>();
|
java.util.Set<String> methods = new java.util.TreeSet<>();
|
||||||
for (SaleDTO s : cachedSales) {
|
for (SaleDTO s : cachedSales) {
|
||||||
|
|||||||
@@ -136,6 +136,23 @@
|
|||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="12dp"
|
||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvStoreFilterLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Store"
|
||||||
|
android:textColor="@color/text_light"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerFilterStore"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ public class AnalyticsController {
|
|||||||
@FXML
|
@FXML
|
||||||
private ComboBox<String> cbTopN;
|
private ComboBox<String> cbTopN;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ComboBox<String> cbStoreFilter;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private HBox hbViewToggle;
|
private HBox hbViewToggle;
|
||||||
|
|
||||||
@@ -138,6 +141,9 @@ public class AnalyticsController {
|
|||||||
cbPaymentFilter.setItems(FXCollections.observableArrayList("All"));
|
cbPaymentFilter.setItems(FXCollections.observableArrayList("All"));
|
||||||
cbPaymentFilter.getSelectionModel().selectFirst();
|
cbPaymentFilter.getSelectionModel().selectFirst();
|
||||||
|
|
||||||
|
cbStoreFilter.setItems(FXCollections.observableArrayList("All Stores"));
|
||||||
|
cbStoreFilter.getSelectionModel().selectFirst();
|
||||||
|
|
||||||
lblFilterSummary.setText("All time");
|
lblFilterSummary.setText("All time");
|
||||||
|
|
||||||
ToggleGroup tgViewMode = new ToggleGroup();
|
ToggleGroup tgViewMode = new ToggleGroup();
|
||||||
@@ -151,6 +157,7 @@ public class AnalyticsController {
|
|||||||
}
|
}
|
||||||
viewMode = (newVal == tbnMyAnalytics) ? "mine" : "store";
|
viewMode = (newVal == tbnMyAnalytics) ? "mine" : "store";
|
||||||
updateViewModeStyles();
|
updateViewModeStyles();
|
||||||
|
updateStoreFilterVisibility();
|
||||||
applyCurrentFilter();
|
applyCurrentFilter();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -213,6 +220,8 @@ public class AnalyticsController {
|
|||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
cachedSales = sales;
|
cachedSales = sales;
|
||||||
derivePaymentMethods();
|
derivePaymentMethods();
|
||||||
|
deriveStores();
|
||||||
|
updateStoreFilterVisibility();
|
||||||
applyCurrentFilter();
|
applyCurrentFilter();
|
||||||
btnRefresh.setDisable(false);
|
btnRefresh.setDisable(false);
|
||||||
});
|
});
|
||||||
@@ -250,6 +259,12 @@ public class AnalyticsController {
|
|||||||
} else {
|
} else {
|
||||||
salesForMode = cachedSales;
|
salesForMode = cachedSales;
|
||||||
}
|
}
|
||||||
|
String storeFilter = currentFilter.storeFilter;
|
||||||
|
if (!storeFilter.equals("All Stores") && !storeFilter.isBlank()) {
|
||||||
|
salesForMode = salesForMode.stream()
|
||||||
|
.filter(s -> storeFilter.equalsIgnoreCase(s.getStoreName() != null ? s.getStoreName() : ""))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
List<SaleResponse> filtered = filterSales(salesForMode, currentFilter);
|
List<SaleResponse> filtered = filterSales(salesForMode, currentFilter);
|
||||||
String start = currentFilter.startDate.isEmpty() ? LocalDate.now().minusDays(6).toString() : currentFilter.startDate;
|
String start = currentFilter.startDate.isEmpty() ? LocalDate.now().minusDays(6).toString() : currentFilter.startDate;
|
||||||
String end = currentFilter.endDate.isEmpty() ? LocalDate.now().toString() : currentFilter.endDate;
|
String end = currentFilter.endDate.isEmpty() ? LocalDate.now().toString() : currentFilter.endDate;
|
||||||
@@ -308,6 +323,31 @@ public class AnalyticsController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deriveStores() {
|
||||||
|
Set<String> stores = new TreeSet<>();
|
||||||
|
for (SaleResponse s : cachedSales) {
|
||||||
|
if (s.getStoreName() != null && !s.getStoreName().isBlank()) {
|
||||||
|
stores.add(s.getStoreName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> items = new ArrayList<>();
|
||||||
|
items.add("All Stores");
|
||||||
|
items.addAll(stores);
|
||||||
|
String current = cbStoreFilter.getValue();
|
||||||
|
cbStoreFilter.setItems(FXCollections.observableArrayList(items));
|
||||||
|
if (current != null && items.contains(current)) {
|
||||||
|
cbStoreFilter.setValue(current);
|
||||||
|
} else {
|
||||||
|
cbStoreFilter.getSelectionModel().selectFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStoreFilterVisibility() {
|
||||||
|
boolean show = UserSession.getInstance().isAdmin() && viewMode.equals("store");
|
||||||
|
cbStoreFilter.setVisible(show);
|
||||||
|
cbStoreFilter.setManaged(show);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateFilterSummary() {
|
private void updateFilterSummary() {
|
||||||
String start = currentFilter.startDate;
|
String start = currentFilter.startDate;
|
||||||
String end = currentFilter.endDate;
|
String end = currentFilter.endDate;
|
||||||
@@ -665,6 +705,7 @@ public class AnalyticsController {
|
|||||||
dpEndDate.setValue(null);
|
dpEndDate.setValue(null);
|
||||||
cbPaymentFilter.getSelectionModel().selectFirst();
|
cbPaymentFilter.getSelectionModel().selectFirst();
|
||||||
cbTopN.getSelectionModel().selectFirst();
|
cbTopN.getSelectionModel().selectFirst();
|
||||||
|
cbStoreFilter.getSelectionModel().selectFirst();
|
||||||
currentFilter = new FilterState();
|
currentFilter = new FilterState();
|
||||||
applyCurrentFilter();
|
applyCurrentFilter();
|
||||||
}
|
}
|
||||||
@@ -683,6 +724,8 @@ public class AnalyticsController {
|
|||||||
currentFilter.paymentMethod = pm != null ? pm : "All";
|
currentFilter.paymentMethod = pm != null ? pm : "All";
|
||||||
int topNPos = cbTopN.getSelectionModel().getSelectedIndex();
|
int topNPos = cbTopN.getSelectionModel().getSelectedIndex();
|
||||||
currentFilter.topN = (topNPos >= 0 && topNPos < TOP_N_VALUES.length) ? TOP_N_VALUES[topNPos] : 5;
|
currentFilter.topN = (topNPos >= 0 && topNPos < TOP_N_VALUES.length) ? TOP_N_VALUES[topNPos] : 5;
|
||||||
|
String sf = cbStoreFilter.getValue();
|
||||||
|
currentFilter.storeFilter = (sf != null && !sf.isBlank()) ? sf : "All Stores";
|
||||||
applyCurrentFilter();
|
applyCurrentFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,5 +734,6 @@ public class AnalyticsController {
|
|||||||
String endDate = "";
|
String endDate = "";
|
||||||
String paymentMethod = "All";
|
String paymentMethod = "All";
|
||||||
int topN = 5;
|
int topN = 5;
|
||||||
|
String storeFilter = "All Stores";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,7 @@
|
|||||||
</FlowPane>
|
</FlowPane>
|
||||||
<HBox alignment="CENTER_LEFT" spacing="8.0">
|
<HBox alignment="CENTER_LEFT" spacing="8.0">
|
||||||
<children>
|
<children>
|
||||||
|
<ComboBox fx:id="cbStoreFilter" prefWidth="145.0" promptText="All Stores" visible="false" managed="false" />
|
||||||
<ComboBox fx:id="cbPaymentFilter" prefWidth="145.0" promptText="All Payments" />
|
<ComboBox fx:id="cbPaymentFilter" prefWidth="145.0" promptText="All Payments" />
|
||||||
<ComboBox fx:id="cbTopN" prefWidth="110.0" />
|
<ComboBox fx:id="cbTopN" prefWidth="110.0" />
|
||||||
<Region HBox.hgrow="ALWAYS" />
|
<Region HBox.hgrow="ALWAYS" />
|
||||||
|
|||||||
Reference in New Issue
Block a user