Fixed couple of endpoints, implemented more of the frontend

This commit is contained in:
2023-10-25 01:24:28 +03:00
parent e4de55f255
commit 0baac602e4
18 changed files with 300 additions and 204 deletions

View File

@@ -22,11 +22,7 @@
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>

View File

@@ -8,6 +8,9 @@ import com.faf223.expensetrackerfaf.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
@@ -33,12 +36,17 @@ public class UserController {
}
}
@GetMapping("/{userUuid}")
public ResponseEntity<UserDTO> getUser(@PathVariable String userUuid) {
User user = userService.getUserById(userUuid);
@GetMapping("/getUserData")
public ResponseEntity<UserDTO> getUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof UserDetails userDetails) {
User user = userService.getUserByEmail(userDetails.getUsername());
if (user != null) return ResponseEntity.ok(userMapper.toDto(user));
else return ResponseEntity.notFound().build();
}
return ResponseEntity.notFound().build();
}
@GetMapping()
@PreAuthorize("hasRole('ADMIN')")

View File

@@ -1,7 +1,6 @@
package com.faf223.expensetrackerfaf.dto;
import com.faf223.expensetrackerfaf.model.ExpenseCategory;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -10,7 +9,6 @@ import java.time.LocalDate;
@Data
@AllArgsConstructor
@JsonIgnoreProperties({"expenseCategory"})
public class ExpenseDTO {
private long expenseId;
private UserDTO userDTO;

View File

@@ -1,7 +1,6 @@
package com.faf223.expensetrackerfaf.dto;
import com.faf223.expensetrackerfaf.model.IncomeCategory;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -10,7 +9,6 @@ import java.time.LocalDate;
@Data
@AllArgsConstructor
@JsonIgnoreProperties({"incomeCategory"})
public class IncomeDTO {
private long incomeId;
private UserDTO userDTO;

View File

@@ -34,6 +34,7 @@
setCookie('access_token', access_token);
setCookie('refresh_token', refresh_token);
console.log(access_token, refresh_token);
window.location.href = '/dashboard'
} catch (error) {
console.error('Login failed:', error);
}

View File

@@ -16,5 +16,6 @@
display: flex;
align-items: stretch;
min-height: 100vh;
max-height: 100%;
}
</style>

View File

@@ -2,7 +2,14 @@
import DashHeader from "./DashHeader.svelte";
import DataMenu from "./DataMenu.svelte";
import QuickInfobar from "./QuickInfobar.svelte";
import NotificationBoard from "./NotificationBoard.svelte";
import { getCookie } from "svelte-cookie";
import {onMount} from "svelte";
onMount(() => {
if (getCookie('access_token') === null ) {
window.location.href = '/auth/login';
}
})
</script>
<div id="dashboard">

View File

@@ -2,8 +2,8 @@
import Graph1 from './graphs/Graph1.svelte';
import Graph2 from './graphs/Graph2.svelte';
import Graph3 from './graphs/Graph3.svelte';
import Graph4 from './graphs/Graph4.svelte';
import Graph5 from './graphs/Graph5.svelte';
import Expenses from "./Expenses.svelte";
import Incomes from "./Incomes.svelte";
</script>
<div id="dataMenu">
@@ -14,9 +14,9 @@
<div id="oneVertical">
<Graph3 />
</div>
<div id="twoHorizontal">
<Graph4 />
<Graph5 />
<div id="dataPanel">
<Incomes />
<Expenses />
</div>
</div>
@@ -34,7 +34,6 @@
}
#twoVertical {
display: flex;
flex-direction: column;
@@ -53,9 +52,9 @@
min-height:0;
}
#twoHorizontal {
#dataPanel {
display: flex;
flex-direction: column;
flex-direction: row;
align-self: stretch;
flex-grow: 1;
min-width: 0;

View File

@@ -0,0 +1,71 @@
<script>
import { onMount, afterUpdate } from 'svelte';
import axios from 'axios';
import { getCookie } from "svelte-cookie";
let data = [];
let parentHeight;
onMount(async () => {
const token = getCookie('access_token');
const config = {
headers: {
'Authorization': `Bearer ${token}`
}
};
try {
const response = await axios.get('http://localhost:8081/expenses/personal-expenses', config);
data = response.data;
parentHeight = document.querySelector('#expenseInfo').offsetHeight;
} catch (error) {
console.error('Error:', error);
}
});
afterUpdate(() => {
parentHeight = document.querySelector('#expenseInfo').offsetHeight;
});
</script>
<div id="expenseInfo" style="max-height: {parentHeight}px;">
<h2>Expenses</h2>
<ul>
{#each data as item}
<li>
{item.incomeCategory ? `${item.incomeCategory.name}: ` : `${item.expenseCategory.name}: `}
{item.incomeCategory ? `+${item.amount}$` : `-${item.amount}$`}
{`${item.date}`}
</li>
{/each}
</ul>
</div>
<style>
#expenseInfo {
flex: 1;
border-radius: 10px;
margin: 10px;
overflow-y: auto;
max-height: 100%;
}
ul {
list-style: none;
padding: 0;
}
li {
margin-bottom: 20px;
background-color: #f2f2f2;
padding: 10px;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
}
li:hover {
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
</style>

View File

@@ -0,0 +1,71 @@
<script>
import { onMount, afterUpdate } from 'svelte';
import axios from 'axios';
import { getCookie } from "svelte-cookie";
let data = [];
let parentHeight;
onMount(async () => {
const token = getCookie('access_token');
const config = {
headers: {
'Authorization': `Bearer ${token}`
}
};
try {
const response = await axios.get('http://localhost:8081/incomes/personal-incomes', config);
data = response.data;
parentHeight = document.querySelector('#incomeInfo').offsetHeight;
} catch (error) {
console.error('Error:', error);
}
});
afterUpdate(() => {
parentHeight = document.querySelector('#incomeInfo').offsetHeight;
});
</script>
<div id="incomeInfo" style="max-height: {parentHeight}px;">
<h2>Incomes</h2>
<ul>
{#each data as item}
<li>
{item.incomeCategory ? `${item.incomeCategory.name}: ` : `${item.expenseCategory.name}: `}
{item.incomeCategory ? `+${item.amount}$` : `-${item.amount}$`}
{`${item.date}`}
</li>
{/each}
</ul>
</div>
<style>
#incomeInfo {
flex: 1;
border-radius: 10px;
margin: 10px;
overflow-y: auto;
max-height: 100%;
}
ul {
list-style: none;
padding: 0;
}
li {
margin-bottom: 20px;
background-color: #f2f2f2;
padding: 10px;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
}
li:hover {
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
</style>

View File

@@ -1,15 +0,0 @@
<script>
</script>
<div id="notificationBoard">
</div>
<style>
#notificationBoard {
display: none;
width:0;
height:0;
}
</style>

View File

@@ -23,15 +23,12 @@
height: 100px;
padding: 10px;
border-radius: 10px;
background-color: #ffdde2;
background-color: #d3d3d3;
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
/* border: 1px solid black; */
}
.infobarElement:hover {
/* color:white; */
/* background-color: black; */
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
</style>

View File

@@ -10,6 +10,7 @@
onMount(async () => {
const token = getCookie('access_token');
const config = {
headers: {
'Authorization': `Bearer ${token}`
@@ -17,21 +18,22 @@
};
try {
const response = await axios.get('http://localhost:8081/incomes/00112233-4455-6677-8899-aabbccddeeaa', config);
const response = await axios.get('http://localhost:8081/incomes/personal-incomes', config);
console.log(response.data);
const incomeData = response.data;
const chartLabels = incomeData.map(item => item.category.categoryName);
const chartLabels = incomeData.map(item => item.incomeCategory.name);
const chartValues = incomeData.map(item => item.amount);
ctx = chartCanvas.getContext('2d');
new Chart(ctx, {
type: 'bar', // Set chart type to 'bar' for a bar graph
type: 'bar',
data: {
labels: chartLabels,
datasets: [{
label: 'Revenue',
backgroundColor: 'rgb(255, 99, 132)',
data: chartValues // Changed from 'data' to 'chartValues'
data: chartValues
}]
},
options: {
@@ -56,7 +58,7 @@
flex: 1;
border-radius: 10px;
margin: 10px;
background-color: #ffdde2;
background-color: #d3d3d3;
}
#chart:hover {

View File

@@ -1,48 +1,70 @@
<script>
import chartjs from 'chart.js/auto';
import Chart from 'chart.js/auto';
import { onMount } from 'svelte';
import axios from 'axios';
import {getCookie} from "svelte-cookie";
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var config = {
type: 'line',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
fill: false,
data: [
5,
6,
3,
4
]
}, {
label: "My Second dataset ",
fill: false,
data: [
5,
6,
3,
4
]
}]
},
options: {
title:{
display:true,
text: "Chart.js Line Chart - Animation Progress Bar"
},
maintainAspectRatio: false
}
};
let chartValues = [20, 10, 5, 2, 20, 30, 45];
let chartLabels = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
let ctx;
let chartCanvas;
onMount(async (promise) => {
onMount(async () => {
const token = getCookie('access_token');
const config = {
headers: {
'Authorization': `Bearer ${token}`
}
};
try {
const response = await axios.get('http://localhost:8081/expenses/personal-expenses', config);
const aggregatedData = {};
response.data.forEach(item => {
const category = item.expenseCategory.name;
const amount = item.amount;
if (aggregatedData[category]) {
aggregatedData[category] += amount;
} else {
aggregatedData[category] = amount;
}
});
const chartLabels = Object.keys(aggregatedData);
const chartValues = Object.values(aggregatedData);
ctx = chartCanvas.getContext('2d');
var chart = new chartjs(ctx, config);
new Chart(ctx, {
type: 'bar',
data: {
labels: chartLabels,
datasets: [{
label: 'Revenue',
backgroundColor: 'rgb(255, 99, 132)',
data: chartValues
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false
},
tooltips: {
callbacks: {
label: (tooltipItem) => {
return tooltipItem.yLabel;
}
}
}
}
});
} catch (error) {
console.error('Error:', error);
}
});
</script>
@@ -56,8 +78,8 @@
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
flex: 1;
border-radius: 10px;
margin:10px;
background-color: #ffdde2;
margin: 10px;
background-color: #d3d3d3;
}
#chart:hover {

View File

@@ -2,33 +2,44 @@
import chartjs from 'chart.js/auto';
import { onMount } from 'svelte';
import axios from 'axios';
import { getCookie } from "svelte-cookie";
let ctx;
let chartCanvas;
onMount(async () => {
const token = getCookie('access_token');
const config = {
headers: {
'Authorization': `Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkYW4uYmFsYW5AZ21haWwuY29tIiwiaWF0IjoxNjk3NzQ0MjY3LCJleHAiOjE2OTc4MzA2Njd9.hzbEDDuOVCY_EQAA8xGlJskQ2FQjw8o0CtFKB1dKYOU`
'Authorization': `Bearer ${token}`
}
};
try {
const response = await axios.get('http://localhost:8081/incomes/00112233-4455-6677-8899-aabbccddeeaa', config);
const incomeData = response.data; // Assuming the response is an array of income data
const [incomesResponse, expensesResponse] = await Promise.all([
axios.get('http://localhost:8081/incomes/personal-incomes', config),
axios.get('http://localhost:8081/expenses/personal-expenses', config)
]);
// Extract income categories and their values
const chartLabels = incomeData.map(item => item.category.categoryName);
const chartValues = incomeData.map(item => item.amount);
const incomesData = incomesResponse.data;
const expensesData = expensesResponse.data;
const totalIncomes = incomesData.reduce((total, item) => total + item.amount, 0);
const totalExpenses = expensesData.reduce((total, item) => total + item.amount, 0);
const chartLabels = ['Incomes', 'Expenses'];
const chartValues = [totalIncomes, totalExpenses];
ctx = chartCanvas.getContext('2d');
new chartjs(ctx, {
type: 'pie', // Set chart type to 'pie' for a pie chart
type: 'pie',
data: {
labels: chartLabels,
datasets: [{
data: chartValues,
backgroundColor: ['red', 'orange', 'yellow', 'green', 'blue'], // Customize colors as needed
backgroundColor: ['green', 'red'],
}]
},
options: {
@@ -53,7 +64,7 @@
flex: 1;
border-radius: 10px;
margin: 10px;
background-color: #ffdde2;
background-color: #d3d3d3;
}
#chart:hover {

View File

@@ -1,48 +0,0 @@
<script>
import chartjs from 'chart.js/auto';
import { onMount } from 'svelte';
let chartValues = [20, 10, 5, 2, 20, 30, 45];
let chartLabels = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
let ctx;
let chartCanvas;
onMount(async (promise) => {
ctx = chartCanvas.getContext('2d');
var chart = new chartjs(ctx, {
type: 'line',
data: {
labels: chartLabels,
datasets: [{
label: 'Revenue',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: chartValues
}]
},
options: {
responsive: true,
maintainAspectRatio: false
}
});
});
</script>
<div id="chart">
<canvas bind:this={chartCanvas}></canvas>
</div>
<style>
#chart {
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
flex: 1;
border-radius: 10px;
margin:10px;
background-color: #ffdde2;
}
#chart:hover {
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
</style>

View File

@@ -1,48 +0,0 @@
<script>
import chartjs from 'chart.js/auto';
import { onMount } from 'svelte';
let chartValues = [20, 10, 5, 2, 20, 30, 45];
let chartLabels = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
let ctx;
let chartCanvas;
onMount(async (promise) => {
ctx = chartCanvas.getContext('2d');
var chart = new chartjs(ctx, {
type: 'line',
data: {
labels: chartLabels,
datasets: [{
label: 'Revenue',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: chartValues
}]
},
options: {
responsive: true,
maintainAspectRatio: false
}
});
});
</script>
<div id="chart">
<canvas bind:this={chartCanvas}></canvas>
</div>
<style>
#chart {
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
flex: 1;
border-radius: 10px;
margin:10px;
background-color: #ffdde2;
}
#chart:hover {
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
</style>

View File

@@ -1,4 +1,29 @@
<script>
import { onMount } from 'svelte';
import axios from 'axios';
import { getCookie } from "svelte-cookie";
let username;
onMount(async () => {
const token = getCookie('access_token');
const config = {
headers: {
'Authorization': `Bearer ${token}`
}
};
try {
const response = await axios.get('http://localhost:8081/users/getUserData', config);
const data = response.data;
username = data.username;
console.log(username)
} catch (error) {
console.error('Error:', error);
}
});
</script>
@@ -37,7 +62,7 @@
</div>
<div id="profileSpace">
<div id="profileInfo">Profile Info</div>
<div id="profileInfo">Hello, {username}</div>
</div>
</div>