added personal and store analytics

This commit is contained in:
Alex
2026-04-14 23:10:03 -06:00
parent 7340a5616e
commit ec0d2d1ec7
5 changed files with 173 additions and 17 deletions

View File

@@ -7,11 +7,13 @@ import android.widget.*;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.petstoremobile.api.auth.TokenManager;
import com.example.petstoremobile.databinding.FragmentAnalyticsBinding;
import com.example.petstoremobile.utils.SpinnerUtils;
import com.example.petstoremobile.utils.UIUtils;
import com.example.petstoremobile.viewmodels.AnalyticsViewModel;
import dagger.hilt.android.AndroidEntryPoint;
import javax.inject.Inject;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
@@ -19,6 +21,9 @@ import java.util.*;
@AndroidEntryPoint
public class AnalyticsFragment extends Fragment {
@Inject
TokenManager tokenManager;
private FragmentAnalyticsBinding binding;
private AnalyticsViewModel viewModel;
private boolean filtersExpanded = false;
@@ -33,6 +38,7 @@ public class AnalyticsFragment extends Fragment {
viewModel = new ViewModelProvider(this).get(AnalyticsViewModel.class);
setupFilterPanel();
setupViewModeToggle();
observeViewModel();
viewModel.loadAnalytics();
@@ -42,6 +48,30 @@ public class AnalyticsFragment extends Fragment {
return binding.getRoot();
}
private static final int COLOR_SELECTED = 0xFF4ECDC4;
private static final int COLOR_UNSELECTED = 0xFFCBD5E1;
private void setupViewModeToggle() {
updateViewModeButtonStyles(viewModel.getViewMode());
binding.btnMyAnalytics.setOnClickListener(v -> {
viewModel.setViewMode("mine");
updateViewModeButtonStyles("mine");
});
binding.btnStoreAnalytics.setOnClickListener(v -> {
viewModel.setViewMode("store");
updateViewModeButtonStyles("store");
});
}
private void updateViewModeButtonStyles(String mode) {
binding.btnMyAnalytics.setBackgroundTintList(
android.content.res.ColorStateList.valueOf(mode.equals("mine") ? COLOR_SELECTED : COLOR_UNSELECTED));
binding.btnStoreAnalytics.setBackgroundTintList(
android.content.res.ColorStateList.valueOf(mode.equals("store") ? COLOR_SELECTED : COLOR_UNSELECTED));
}
// Filter Panel
private void setupFilterPanel() {
@@ -224,17 +254,22 @@ public class AnalyticsFragment extends Fragment {
}
// Employee Performance
binding.llEmployeePerformance.removeAllViews();
if (data.employeePerformance != null && !data.employeePerformance.isEmpty()) {
BigDecimal maxEmp = data.employeePerformance.get(0).getValue();
if (maxEmp.compareTo(BigDecimal.ZERO) == 0) maxEmp = BigDecimal.ONE;
for (Map.Entry<String, BigDecimal> e : data.employeePerformance) {
addBarRow(binding.llEmployeePerformance, e.getKey(),
"$" + e.getValue().setScale(2, RoundingMode.HALF_UP),
e.getValue().floatValue() / maxEmp.floatValue(), "#1a759f");
boolean showEmployeeSection = viewModel.getViewMode().equals("store");
View empParent = (View) binding.llEmployeePerformance.getParent();
if (empParent != null) empParent.setVisibility(showEmployeeSection ? View.VISIBLE : View.GONE);
if (showEmployeeSection) {
binding.llEmployeePerformance.removeAllViews();
if (data.employeePerformance != null && !data.employeePerformance.isEmpty()) {
BigDecimal maxEmp = data.employeePerformance.get(0).getValue();
if (maxEmp.compareTo(BigDecimal.ZERO) == 0) maxEmp = BigDecimal.ONE;
for (Map.Entry<String, BigDecimal> e : data.employeePerformance) {
addBarRow(binding.llEmployeePerformance, e.getKey(),
"$" + e.getValue().setScale(2, RoundingMode.HALF_UP),
e.getValue().floatValue() / maxEmp.floatValue(), "#1a759f");
}
} else {
addEmptyRow(binding.llEmployeePerformance, "No data");
}
} else {
addEmptyRow(binding.llEmployeePerformance, "No data");
}
// Daily Revenue

View File

@@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.example.petstoremobile.api.auth.TokenManager;
import com.example.petstoremobile.dtos.SaleDTO;
import com.example.petstoremobile.repositories.SaleRepository;
import com.example.petstoremobile.utils.Resource;
@@ -21,6 +22,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -29,6 +31,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel;
@HiltViewModel
public class AnalyticsViewModel extends ViewModel {
private final SaleRepository saleRepository;
private final TokenManager tokenManager;
private final MutableLiveData<AnalyticsData> analyticsData = new MutableLiveData<>();
private final MutableLiveData<Boolean> isLoading = new MutableLiveData<>(false);
@@ -37,10 +40,12 @@ public class AnalyticsViewModel extends ViewModel {
private List<SaleDTO> cachedSales = new ArrayList<>();
private FilterState currentFilter = new FilterState();
private String viewMode = "store";
@Inject
public AnalyticsViewModel(SaleRepository saleRepository) {
public AnalyticsViewModel(SaleRepository saleRepository, TokenManager tokenManager) {
this.saleRepository = saleRepository;
this.tokenManager = tokenManager;
}
public LiveData<AnalyticsData> getAnalyticsData() { return analyticsData; }
@@ -76,8 +81,26 @@ public class AnalyticsViewModel extends ViewModel {
applyCurrentFilter();
}
public void setViewMode(String mode) {
viewMode = mode;
applyCurrentFilter();
}
public String getViewMode() {
return viewMode;
}
private void applyCurrentFilter() {
List<SaleDTO> filtered = filterSales(cachedSales, currentFilter);
List<SaleDTO> salesForMode;
if (viewMode.equals("mine")) {
String currentUser = tokenManager.getUsername();
salesForMode = cachedSales.stream()
.filter(s -> currentUser != null && currentUser.equalsIgnoreCase(s.getEmployeeName() != null ? s.getEmployeeName() : ""))
.collect(Collectors.toList());
} else {
salesForMode = cachedSales;
}
List<SaleDTO> filtered = filterSales(salesForMode, currentFilter);
computeAnalytics(filtered, currentFilter);
}

View File

@@ -45,6 +45,40 @@
</LinearLayout>
<LinearLayout
android:id="@+id/llViewModeToggle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="4dp">
<Button
android:id="@+id/btnMyAnalytics"
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_weight="1"
android:text="My Analytics"
android:textSize="12sp"
android:backgroundTint="#CBD5E1"
android:textColor="@color/white"
android:layout_marginEnd="4dp"/>
<Button
android:id="@+id/btnStoreAnalytics"
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_weight="1"
android:text="Store Analytics"
android:textSize="12sp"
android:backgroundTint="@color/primary_medium"
android:textColor="@color/white"
android:layout_marginStart="4dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"