@@ -2,8 +2,9 @@ import { Component, OnInit } from '@angular/core';
22import { ExpenseService , Expense } from '../../service/localStorage/expense.service' ;
33import { CommonModule } from '@angular/common' ;
44import { UserService } from '../../service/localStorage/user.service' ;
5- import { FormsModule } from '@angular/forms' ;
65import { HeatmapSummary } from '../../models/heatMap-summary.service' ;
6+ import { FormModelComponent } from '../../component/form-model/form-model.component' ;
7+ import { FormBuilder , FormGroup , FormsModule , ReactiveFormsModule , Validators } from '@angular/forms' ;
78
89/**
910 * Component that renders a monthly calendar view with expense tracking.
@@ -16,9 +17,9 @@ import { HeatmapSummary } from '../../models/heatMap-summary.service';
1617 */
1718@Component ( {
1819 selector : 'app-calendar' ,
19- imports : [ CommonModule , FormsModule ] ,
20+ imports : [ CommonModule , FormModelComponent , FormsModule , ReactiveFormsModule ] ,
2021 templateUrl : './calendar.component.html' ,
21- styleUrl : './calendar.component.css'
22+ styleUrls : [ './calendar.component.css' ]
2223} )
2324export class CalendarComponent implements OnInit {
2425
@@ -65,16 +66,32 @@ export class CalendarComponent implements OnInit {
6566 */
6667 heatmapSummary : HeatmapSummary [ ] = [ ] ;
6768
69+ /** Controls the visibility of the Edit Heatmap modal */
70+ showEditHeatMapModel = false ;
71+
72+ /** Form group for handling Heatmap edit form inputs and validations */
73+ heatMapForm ! : FormGroup ;
74+
75+ /** Tracks whether the Rose color modal is currently open */
76+ isRoseModelOpen : boolean = false ;
77+
78+ /** Tracks whether the Emerald color modal is currently open */
79+ isEmeraldModelOpen : boolean = false ;
80+
81+ /** Tracks whether the Amber color modal is currently open */
82+ isAmberModelOpen : boolean = false ;
6883
6984 /**
7085 * Creates an instance of CalendarComponent.
7186 *
7287 * @param expenseService Service to retrieve expenses from local storage.
7388 * @param userService Service to retrieve user settings such as currency.
89+ * @param fb Angular `FormBuilder` to build the reactive form.
7490 */
7591 constructor (
7692 private expenseService : ExpenseService ,
77- public userService : UserService
93+ public userService : UserService ,
94+ private fb : FormBuilder ,
7895 ) {
7996 this . currency = this . userService . getValue < string > ( 'currency' ) ;
8097 this . isShowHeatmap = this . userService . getValue < boolean > ( 'is_show_heatmap' ) ?? false ;
@@ -84,6 +101,9 @@ export class CalendarComponent implements OnInit {
84101 /** Angular lifecycle hook that initializes the calendar view */
85102 ngOnInit ( ) : void {
86103 this . renderCalendar ( this . currentYear , this . currentMonth ) ;
104+ this . heatMapForm = this . fb . group ( {
105+ amount : [ 0 , [ Validators . required ] ]
106+ } ) ;
87107 }
88108
89109 /**
@@ -208,19 +228,21 @@ export class CalendarComponent implements OnInit {
208228 */
209229 private getHeatClass ( amount : number ) : string {
210230 if ( this . isShowHeatmap === false ) return 'bg-[var(--color-surface)]' ;
231+ const rose_amount = this . userService . getValue < number > ( 'rose_amount' ) ?? 1000 ;
232+ const emerald_amount = this . userService . getValue < number > ( 'emerald_amount' ) ?? 300 ;
211233 if ( amount === 0 ) {
212- this . addOrUpdateHeatMapSummary ( 'bg-[var(--color-gray)]' , amount )
234+ this . addOrUpdateHeatMapSummary ( 'bg-[var(--color-gray)]' , amount , 'No expenses' )
213235 return 'bg-[var(--color-gray)]' ;
214236 }
215- if ( amount < 300 ) {
216- this . addOrUpdateHeatMapSummary ( 'bg-[var(--color-emerald)]' , amount )
237+ if ( amount < emerald_amount ) {
238+ this . addOrUpdateHeatMapSummary ( 'bg-[var(--color-emerald)]' , amount , `< ${ emerald_amount } ` )
217239 return 'bg-[var(--color-emerald)]' ;
218240 }
219- if ( amount < 1000 ) {
220- this . addOrUpdateHeatMapSummary ( 'bg-[var(--color-amber)]' , amount )
241+ if ( amount < rose_amount ) {
242+ this . addOrUpdateHeatMapSummary ( 'bg-[var(--color-amber)]' , amount , ` ${ emerald_amount } - ${ rose_amount } ` )
221243 return 'bg-[var(--color-amber)]' ;
222244 }
223- this . addOrUpdateHeatMapSummary ( 'bg-[var(--color-rose)]' , amount )
245+ this . addOrUpdateHeatMapSummary ( 'bg-[var(--color-rose)]' , amount , `> ${ rose_amount } ` )
224246 return 'bg-[var(--color-rose)]' ;
225247 }
226248
@@ -252,7 +274,7 @@ export class CalendarComponent implements OnInit {
252274 * it increments the `days` count by 1 and adds the `amount` to the existing total.
253275 * Otherwise, it creates a new entry with `days` initialized to 1 and `amount` as provided.
254276 */
255- addOrUpdateHeatMapSummary ( color : string , amount : number ) {
277+ addOrUpdateHeatMapSummary ( color : string , amount : number , message : string ) {
256278 const existing = this . heatmapSummary . find ( item => item . color === color ) ;
257279 if ( existing ) {
258280 existing . days += 1 ;
@@ -261,8 +283,68 @@ export class CalendarComponent implements OnInit {
261283 this . heatmapSummary . push ( {
262284 color : color ,
263285 days : 1 ,
264- amount : amount
286+ amount : amount ,
287+ text : message
288+ } ) ;
289+ }
290+ this . heatmapSummary . sort ( ( a , b ) => b . amount - a . amount ) ;
291+ }
292+
293+ /**
294+ * Closes the Edit Heatmap modal and resets all color-specific modal states.
295+ */
296+ closeEditHeatMapModel ( ) : void {
297+ this . showEditHeatMapModel = false ;
298+ this . isEmeraldModelOpen = false ;
299+ this . isRoseModelOpen = false ;
300+ this . isAmberModelOpen = false ;
301+ }
302+
303+ /**
304+ * Opens the Edit Heatmap modal for a specific color.
305+ * Resets the form with the corresponding saved amount value.
306+ *
307+ * @param color - The background color class of the heatmap block ('bg-[var(--color-rose)]', 'bg-[var(--color-emerald)]', 'bg-[var(--color-amber)]')
308+ */
309+ openEditHeapMapModel ( color : string ) : void {
310+ if ( color === 'bg-[var(--color-rose)]' ) {
311+ this . heatMapForm . reset ( {
312+ amount : this . userService . getValue < number > ( 'rose_amount' ) ?? 1000 ,
313+ } ) ;
314+ this . isRoseModelOpen = true ;
315+ }
316+ if ( color === 'bg-[var(--color-emerald)]' ) {
317+ this . heatMapForm . reset ( {
318+ amount : this . userService . getValue < number > ( 'emerald_amount' ) ?? 300 ,
265319 } ) ;
320+ this . isEmeraldModelOpen = true ;
266321 }
322+ if ( color === 'bg-[var(--color-amber)]' ) {
323+ this . heatMapForm . reset ( {
324+ amount : this . userService . getValue < number > ( 'emerald_amount' ) ?? 300 ,
325+ } ) ;
326+ this . isAmberModelOpen = true ;
327+ }
328+ this . showEditHeatMapModel = ! this . showEditHeatMapModel ;
329+ }
330+
331+ /**
332+ * Validates and updates the Heatmap amount for the currently open color modal.
333+ * Persists the new amount to the user service and refreshes the calendar view.
334+ */
335+ updateHeatMap ( ) : void {
336+ if ( this . heatMapForm . invalid ) {
337+ this . heatMapForm . markAllAsTouched ( ) ;
338+ return ;
339+ }
340+ const { amount } = this . heatMapForm . value ;
341+ if ( this . isEmeraldModelOpen || this . isAmberModelOpen ) {
342+ this . userService . update ( 'emerald_amount' , amount ) ;
343+ }
344+ if ( this . isRoseModelOpen ) {
345+ this . userService . update ( 'rose_amount' , amount ) ;
346+ }
347+ this . renderCalendar ( this . currentYear , this . currentMonth ) ;
348+ this . closeEditHeatMapModel ( ) ;
267349 }
268350}
0 commit comments