diff --git a/frontend/src/api/history.ts b/frontend/src/api/history.ts new file mode 100644 index 0000000..09658f3 --- /dev/null +++ b/frontend/src/api/history.ts @@ -0,0 +1,51 @@ +import { API_BASE_URL } from '@/api/config.ts' +import type {DayStatus} from "@/api/dashboard.ts"; + +export type SingleDayEntry = { + date: string; + dayOfWeek: string; + status: DayStatus; +} + +export type HistoryData = { + addictionName: string + singleDayCost: number + totalSavings: number + entries: SingleDayEntry[] +}; + +export async function fetchHistoryData(token?: string) { + const res = await fetch(`${API_BASE_URL}/api/progress`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + ...(token ? { 'Authorization': `Bearer ${token}` } : {}) + } + }); + + if (!res.ok) { + const msg = await res.text(); + throw new Error(msg || 'Failed to fetch history data'); + } + + return await res.json() as HistoryData; +} + +export async function updateDayStatus(date: string, status: DayStatus, token?: string) { + const body = { status }; + + const res = await fetch(`${API_BASE_URL}/api/days/${date}`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + ...(token ? { 'Authorization': `Bearer ${token}` } : {}) + }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + const msg = await res.text(); + throw new Error(msg || 'Failed to update day status'); + } + return await res.json() +} diff --git a/frontend/src/components/HistoryStatusChangeDialog.vue b/frontend/src/components/HistoryStatusChangeDialog.vue index 730a6c1..345ec26 100644 --- a/frontend/src/components/HistoryStatusChangeDialog.vue +++ b/frontend/src/components/HistoryStatusChangeDialog.vue @@ -42,7 +42,7 @@ import { ref, watch } from 'vue'; import Dialog from 'primevue/dialog'; import SelectButton from 'primevue/selectbutton'; -type DayStatus = 'success' | 'relapse' | 'none'; +type DayStatus = 'success' | 'failure' | 'none'; interface HistoryEntry { date: Date; @@ -61,7 +61,7 @@ const internalEntry = ref({ ...props.entry }); const extendedStatusOptions = ref([ { label: 'Sukces', value: 'success', icon: 'pi pi-check-circle' }, { label: 'Brak', value: 'none', icon: 'pi pi-minus-circle' }, - { label: 'Wpadka', value: 'relapse', icon: 'pi pi-exclamation-circle' } + { label: 'Wpadka', value: 'failure', icon: 'pi pi-exclamation-circle' } ]); watch(() => props.entry, (newVal) => { diff --git a/frontend/src/components/LandingLast7Days.vue b/frontend/src/components/LandingLast7Days.vue index e714853..c4bfb41 100644 --- a/frontend/src/components/LandingLast7Days.vue +++ b/frontend/src/components/LandingLast7Days.vue @@ -62,7 +62,7 @@ const lastSevenDays = ref([]); const dashboard = useDashboardStore(); -async function submit() { +async function loadData() { try { const payload: Last7DaysResponse = await dashboard.historyLast7Days(); @@ -89,8 +89,12 @@ async function submit() { } } +defineExpose({ + loadData +}) + onMounted(() => { - submit(); + loadData(); }); diff --git a/frontend/src/components/LandingSummary.vue b/frontend/src/components/LandingSummary.vue index 91e62e8..51033fc 100644 --- a/frontend/src/components/LandingSummary.vue +++ b/frontend/src/components/LandingSummary.vue @@ -28,11 +28,11 @@
{{ streakDays }}

Kliknij, aby zatwierdzić dzisiejszy dzień bez @@ -69,6 +69,12 @@ + + @@ -79,14 +85,24 @@ import Card from 'primevue/card'; import Button from 'primevue/button'; import Knob from 'primevue/knob'; import {useDashboardStore} from "@/stores/dashboard.ts"; +import HistoryStatusChangeDialog from "@/components/HistoryStatusChangeDialog.vue"; +import {useHistoryStore} from "@/stores/history.ts"; +import type {DayStatus} from "@/api/dashboard.ts"; const savedMoney = ref(0); const streakDays = ref(0); -const streakActive = ref(false); const currentDays = ref(0); const goalDays = ref(10); const addictionName = ref('uzależnienia'); +const showDialog = ref(false); +const todayEntry = ref<{ date: Date, status: DayStatus }>({ + date: new Date(), + status: 'none' +}); + const dashboard = useDashboardStore() +const history = useHistoryStore() + async function submit() { try { @@ -100,21 +116,46 @@ async function submit() { } } -onMounted(() => { - submit(); -}); +const formatDateToPayload = (date: Date): string => { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; +}; + + +const openDialog = () => { + todayEntry.value = { + date: new Date(), + status: 'none' + }; + showDialog.value = true; +}; + +const emit = defineEmits(['refresh']); -const toggleStreak = () => { - if (!streakActive.value) { - streakDays.value++; - currentDays.value++; - streakActive.value = true; - } else { - streakDays.value--; - currentDays.value--; - streakActive.value = false; +const saveEntry = async (updatedEntry: { date: Date, status: DayStatus | null }) => { + try { + const dateStr = formatDateToPayload(updatedEntry.date); + + const statusToSend = updatedEntry.status ?? 'none'; + + await history.updateStatus(dateStr, statusToSend); + + showDialog.value = false; + + await submit(); + emit('refresh'); + + } catch (err) { + console.error("Błąd zapisu:", err); + alert("Nie udało się zapisać statusu."); } }; + +onMounted(() => { + submit(); +});