diff --git a/src/main/java/com/application/munera/views/expenses/DashboardView.java b/src/main/java/com/application/munera/views/expenses/DashboardView.java index 1af75fd..ada4c49 100644 --- a/src/main/java/com/application/munera/views/expenses/DashboardView.java +++ b/src/main/java/com/application/munera/views/expenses/DashboardView.java @@ -5,7 +5,9 @@ import com.application.munera.services.ExpenseService; import com.application.munera.views.MainLayout; import com.nimbusds.jose.shaded.gson.Gson; import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import java.time.Year; @@ -15,8 +17,10 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.stream.Collectors; //@HtmlImport("frontend://styles/shared-styles.html") // If you have custom styles +@PageTitle("Dashboard") @Route(value = "highcharts-view", layout = MainLayout.class) public class DashboardView extends Div { @@ -26,23 +30,76 @@ public class DashboardView extends Div { this.expenseService = expenseService; addClassName("highcharts-view"); // Optional CSS class for styling - VerticalLayout layout = new VerticalLayout(); - layout.setSizeFull(); + VerticalLayout mainLayout = new VerticalLayout(); + mainLayout.setSizeFull(); + mainLayout.getStyle().set("padding", "10px"); // Add padding to main layout - // Create a div to host the chart - Div chartDiv = new Div(); - chartDiv.setId("chart"); // Assign an ID to this div for later reference - chartDiv.getStyle().set("min-height", "400px"); // Set minimum height for the chart - layout.add(chartDiv); - add(layout); + // Create a horizontal layout for the top row + HorizontalLayout topRowLayout = new HorizontalLayout(); + topRowLayout.setSizeFull(); + topRowLayout.setHeight("50%"); // Make sure the top row occupies half of the page height + topRowLayout.getStyle().set("padding", "10px"); // Add padding to top row - String jsInit = generateChartInitializationScript(); + // Create and add the existing bar chart to the top left + Div barChartDiv = new Div(); + barChartDiv.setId("barChart"); + barChartDiv.getStyle().set("min-height", "100%"); // Ensure it occupies the full height of the container + barChartDiv.getStyle().set("width", "50%"); // Occupy half of the width + barChartDiv.getStyle().set("border", "1px solid #ccc"); // Add border + barChartDiv.getStyle().set("padding", "10px"); // Add padding inside the border + topRowLayout.add(barChartDiv); - // Execute the JavaScript to initialize the chart - getElement().executeJs(jsInit); + // Create and add the new pie chart to the top right + Div pieChartDiv = new Div(); + pieChartDiv.setId("pieChart"); + pieChartDiv.getStyle().set("min-height", "100%"); // Ensure it occupies the full height of the container + pieChartDiv.getStyle().set("width", "50%"); // Occupy half of the width + pieChartDiv.getStyle().set("border", "1px solid #ccc"); // Add border + pieChartDiv.getStyle().set("padding", "10px"); // Add padding inside the border + topRowLayout.add(pieChartDiv); + + mainLayout.add(topRowLayout); + + // Create a horizontal layout for the bottom row + HorizontalLayout bottomRowLayout = new HorizontalLayout(); + bottomRowLayout.setSizeFull(); + bottomRowLayout.setHeight("50%"); // Make sure the bottom row occupies the other half of the page height + bottomRowLayout.getStyle().set("padding", "10px"); // Add padding to bottom row + + // Create placeholder divs for the bottom charts + Div bottomLeftChartDiv = new Div(); + bottomLeftChartDiv.setId("bottomLeftChart"); + bottomLeftChartDiv.getStyle().set("min-height", "100%"); // Ensure it occupies the full height of the container + bottomLeftChartDiv.getStyle().set("width", "50%"); // Occupy half of the width + bottomLeftChartDiv.getStyle().set("border", "1px solid #ccc"); // Add border + bottomLeftChartDiv.getStyle().set("padding", "10px"); // Add padding inside the border + bottomRowLayout.add(bottomLeftChartDiv); + + Div bottomRightChartDiv = new Div(); + bottomRightChartDiv.setId("bottomRightChart"); + bottomRightChartDiv.getStyle().set("min-height", "100%"); // Ensure it occupies the full height of the container + bottomRightChartDiv.getStyle().set("width", "50%"); // Occupy half of the width + bottomRightChartDiv.getStyle().set("border", "1px solid #ccc"); // Add border + bottomRightChartDiv.getStyle().set("padding", "10px"); // Add padding inside the border + bottomRowLayout.add(bottomRightChartDiv); + + mainLayout.add(bottomRowLayout); + + add(mainLayout); + + String barChartJs = generateBarChartScript(); + String pieChartJs = generatePieChartScript(); + String bottomLeftChartJs = generatePlaceholderChartScript("bottomLeftChart", "Bottom Left Chart"); + String bottomRightChartJs = generatePlaceholderChartScript("bottomRightChart", "Bottom Right Chart"); + + // Execute the JavaScript to initialize the charts + getElement().executeJs(barChartJs); + getElement().executeJs(pieChartJs); + getElement().executeJs(bottomLeftChartJs); + getElement().executeJs(bottomRightChartJs); } - private String generateChartInitializationScript() { + private String generateBarChartScript() { List expenses = expenseService.findAllByYear(Year.now().getValue()); // Prepare data for Highcharts @@ -58,7 +115,6 @@ public class DashboardView extends Div { // Populate map with actual data for (Expense expense : expenses) { String monthName = expense.getDate().getMonth().getDisplayName(TextStyle.SHORT, Locale.ENGLISH); - // Convert BigDecimal to Double Double amount = expense.getCost().doubleValue(); monthlyData.put(monthName, monthlyData.get(monthName) + amount); } @@ -71,7 +127,7 @@ public class DashboardView extends Div { data.setCharAt(data.length() - 1, ']'); // Replace last comma with closing bracket // Generate JavaScript initialization - return "Highcharts.chart('chart', {" + + return "Highcharts.chart('barChart', {" + "chart: {" + "type: 'column'" + "}," + @@ -87,4 +143,61 @@ public class DashboardView extends Div { "}]" + "});"; } + + private String generatePieChartScript() { + List expenses = expenseService.findAllByYear(Year.now().getValue()); + + // Group expenses by category name and sum their costs + Map categoryData = expenses.stream() + .collect(Collectors.groupingBy( + expense -> expense.getCategory().getName(), + LinkedHashMap::new, + Collectors.summingDouble(expense -> expense.getCost().doubleValue()) + )); + + // Prepare series data for Highcharts + StringBuilder data = new StringBuilder("["); + for (Map.Entry entry : categoryData.entrySet()) { + data.append("{ name: '").append(entry.getKey()).append("', y: ").append(entry.getValue()).append(" },"); + } + data.setCharAt(data.length() - 1, ']'); // Replace last comma with closing bracket + + // Generate JavaScript initialization + return "Highcharts.chart('pieChart', {" + + "chart: {" + + "type: 'pie'" + + "}," + + "title: {" + + "text: 'Expenses by Category for " + Year.now().getValue() + "'" + + "}," + + "plotOptions: {" + + "pie: {" + + "size: '80%'" + // Adjust size to make the pie chart larger + "}" + + "}," + + "series: [{" + + "name: 'Expenses'," + + "colorByPoint: true," + + "data: " + data + // Use the data fetched from DB + "}]" + + "});"; + } + + private String generatePlaceholderChartScript(String chartId, String title) { + return "Highcharts.chart('" + chartId + "', {" + + "chart: {" + + "type: 'line'" + // Placeholder type + "}," + + "title: {" + + "text: '" + title + "'" + + "}," + + "xAxis: {" + + "categories: []" + // Placeholder empty categories + "}," + + "series: [{" + + "name: 'Placeholder'," + + "data: []" + // Placeholder empty data + "}]" + + "});"; + } } \ No newline at end of file