1+ import { Component , OnInit } from '@angular/core' ;
2+ import { CommonModule , DecimalPipe , DatePipe } from '@angular/common' ;
3+ import { FormsModule } from '@angular/forms' ;
4+ import { GoalService , Goal } from '../../../service/localStorage/goal.service' ;
5+ import { SavingsService , Saving } from '../../../service/localStorage/savings.service' ;
6+ import { ConfigService } from '../../../service/config/config.service' ;
7+
8+ @Component ( {
9+ selector : 'app-saving' ,
10+ standalone : true ,
11+ imports : [ CommonModule , DecimalPipe , DatePipe , FormsModule ] ,
12+ templateUrl : './saving.component.html' ,
13+ styleUrl : './saving.component.css'
14+ } )
15+ export class SavingComponent implements OnInit {
16+ currentGoal : Goal | null = null ;
17+ savings : Saving [ ] = [ ] ;
18+
19+ showSavingModal = false ;
20+ showGoalModal = false ;
21+ showGoalDetailsModal = false ;
22+ editingSavingId : string | null = null ;
23+
24+ todayDateStr = '' ;
25+ savingForm : Partial < Saving > = { } ;
26+ goalForm : Partial < Goal > = { } ;
27+
28+ // Dashboard Stats
29+ totalSavedAmount = 0 ;
30+ goalTarget = 0 ;
31+ progressPercentage = 0 ;
32+ remainingPercentage = 0 ;
33+ currentMonthAdded = 0 ;
34+ averageSavedPerDay = 0 ;
35+
36+ constructor (
37+ private goalService : GoalService ,
38+ private savingsService : SavingsService ,
39+ private configService : ConfigService
40+ ) {
41+ this . todayDateStr = this . configService . getLocalTime ( ) . split ( 'T' ) [ 0 ] ;
42+ }
43+
44+ ngOnInit ( ) {
45+ this . refreshData ( ) ;
46+ }
47+
48+ refreshData ( ) : void {
49+ this . currentGoal = this . goalService . getAll ( ) [ 0 ] || null ;
50+ this . savings = this . savingsService . getAll ( ) || [ ] ;
51+ this . calculateStats ( ) ;
52+ }
53+
54+ calculateStats ( ) {
55+ this . totalSavedAmount = this . savings . reduce ( ( sum , s ) => sum + Number ( s . amount || 0 ) , 0 ) ;
56+ this . goalTarget = Number ( this . currentGoal ?. target_amount || 0 ) ;
57+
58+ const progress = this . goalTarget > 0 ? ( this . totalSavedAmount / this . goalTarget ) * 100 : 0 ;
59+ this . progressPercentage = Math . min ( Math . max ( progress , 0 ) , 100 ) ;
60+ this . remainingPercentage = Math . max ( 100 - this . progressPercentage , 0 ) ;
61+
62+ const now = new Date ( ) ;
63+ this . currentMonthAdded = ( this . goalTarget - this . totalSavedAmount ) > 0 ? this . goalTarget - this . totalSavedAmount : 0 ;
64+
65+ if ( this . currentGoal ?. start_date && this . totalSavedAmount > 0 ) {
66+ const start = new Date ( this . currentGoal . start_date ) . getTime ( ) ;
67+ const today = new Date ( ) . getTime ( ) ;
68+ let days = Math . ceil ( ( today - start ) / ( 1000 * 3600 * 24 ) ) ;
69+ this . averageSavedPerDay = this . totalSavedAmount / ( days <= 0 ? 1 : days ) ;
70+ } else {
71+ this . averageSavedPerDay = 0 ;
72+ }
73+ }
74+
75+ /* ---------- Validation Getters ---------- */
76+
77+ get savingDateError ( ) : string | null {
78+ if ( ! this . savingForm . date ) return "Date is required." ;
79+ if ( new Date ( this . savingForm . date ) > new Date ( this . todayDateStr ) ) return "Date cannot be in the future." ;
80+ return null ;
81+ }
82+
83+ get isSavingFormValid ( ) : boolean {
84+ return ! ! this . savingForm . amount && this . savingForm . amount > 0 && ! this . savingDateError ;
85+ }
86+
87+ get goalDateError ( ) : string | null {
88+ const { start_date, target_date } = this . goalForm ;
89+
90+ if ( ! start_date || ! target_date ) {
91+ return "Both Start Date and Target Date are required." ;
92+ }
93+
94+ if ( new Date ( start_date ) > new Date ( target_date ) ) {
95+ return "Start date cannot be after target date." ;
96+ }
97+
98+ return null ;
99+ }
100+
101+ get isGoalFormValid ( ) : boolean {
102+ return (
103+ ! ! this . goalForm . goal_name &&
104+ ! ! this . goalForm . target_amount &&
105+ this . goalForm . target_amount > 0 &&
106+ ! ! this . goalForm . start_date && // Ensure start date exists
107+ ! ! this . goalForm . target_date && // Ensure target date exists
108+ ! this . goalDateError
109+ ) ;
110+ }
111+ /* ---------- Actions ---------- */
112+
113+ saveSavingsData ( ) {
114+ if ( ! this . isSavingFormValid ) return ;
115+
116+ const savingData : Saving = {
117+ saving_id : this . editingSavingId || 'sav_' + Date . now ( ) ,
118+ amount : Number ( this . savingForm . amount ) ,
119+ date : this . savingForm . date ! ,
120+ note : this . savingForm . note || ''
121+ } ;
122+
123+ if ( this . editingSavingId ) {
124+ this . savingsService . update ( this . editingSavingId , savingData ) ;
125+ } else {
126+ this . savingsService . add ( savingData ) ;
127+ }
128+
129+ this . closeModals ( ) ;
130+ this . refreshData ( ) ;
131+ }
132+
133+ saveGoalData ( ) {
134+ if ( ! this . isGoalFormValid ) return ;
135+
136+ const goalData : Goal = {
137+ goal_id : this . currentGoal ?. goal_id || 'goal_' + Date . now ( ) ,
138+ goal_name : this . goalForm . goal_name ! ,
139+ target_amount : Number ( this . goalForm . target_amount ) ,
140+ start_date : this . goalForm . start_date ! ,
141+ target_date : this . goalForm . target_date || '' ,
142+ note : this . goalForm . note || ''
143+ } ;
144+
145+ if ( this . currentGoal ) {
146+ this . goalService . update ( goalData . goal_id , goalData ) ;
147+ } else {
148+ this . goalService . add ( goalData ) ;
149+ }
150+
151+ this . closeModals ( ) ;
152+ this . refreshData ( ) ;
153+ }
154+
155+ deleteSaving ( id : string ) {
156+ if ( confirm ( 'Delete this saving record?' ) ) {
157+ this . savingsService . delete ( id ) ;
158+ this . refreshData ( ) ;
159+ }
160+ }
161+
162+ deleteGoal ( ) {
163+ if ( confirm ( 'Delete your entire goal? Progress will be kept but the target will be removed.' ) ) {
164+ if ( this . currentGoal ) {
165+ this . goalService . delete ( this . currentGoal . goal_id ) ;
166+ this . currentGoal = null ;
167+ this . refreshData ( ) ;
168+ }
169+ this . closeModals ( ) ;
170+ }
171+ }
172+
173+ // --- Modal Control ---
174+ openAddModal ( ) {
175+ this . editingSavingId = null ;
176+ this . savingForm = { amount : undefined , date : this . todayDateStr , note : '' } ;
177+ this . showSavingModal = true ;
178+ }
179+
180+ editSaving ( saving : Saving ) {
181+ this . editingSavingId = saving . saving_id ;
182+ this . savingForm = { ...saving } ;
183+ this . showSavingModal = true ;
184+ }
185+
186+ openGoalModal ( ) {
187+ this . showGoalDetailsModal = false ;
188+ this . goalForm = this . currentGoal ? { ...this . currentGoal } : {
189+ goal_name : '' , target_amount : undefined , start_date : this . todayDateStr , target_date : '' , note : ''
190+ } ;
191+ this . showGoalModal = true ;
192+ }
193+
194+ handleGoalCardClick ( ) {
195+ this . currentGoal ? ( this . showGoalDetailsModal = true ) : this . openGoalModal ( ) ;
196+ }
197+
198+ closeModals ( ) {
199+ this . showSavingModal = false ;
200+ this . showGoalModal = false ;
201+ this . showGoalDetailsModal = false ;
202+ }
203+ }
0 commit comments