Skip to content

Commit

Permalink
Add countdown timer component to explore template for project timing …
Browse files Browse the repository at this point in the history
…display
  • Loading branch information
miladsoft committed Dec 13, 2024
1 parent 77cb35d commit 809f2df
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 0 deletions.
155 changes: 155 additions & 0 deletions src/app/components/countdown-timer/countdown-timer.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { interval, Subscription } from 'rxjs';
import { trigger, state, style, transition, animate } from '@angular/animations';

@Component({
selector: 'countdown-timer',
standalone: true,
imports: [CommonModule],
styles: [`
.countdown-container {
display: flex;
justify-content: center;
gap: 1rem;
padding: 1rem;
}
.time-box {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(5px);
border-radius: 8px;
padding: 0.5rem;
min-width: 70px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
text-align: center;
}
.time-value {
font-size: 1.5rem;
font-weight: bold;
font-family: 'Monaco', monospace;
margin-bottom: 0.25rem;
}
.time-label {
font-size: 0.75rem;
text-transform: uppercase;
opacity: 0.8;
}
.flip {
animation: flipAnimation 0.6s ease-in-out;
}
@keyframes flipAnimation {
0% { transform: perspective(400px) rotateX(0); }
50% { transform: perspective(400px) rotateX(-90deg); }
100% { transform: perspective(400px) rotateX(0); }
}
`],
template: `
<div class="text-center mb-2 font-bold" [style.color]="hasStarted ? '#ef4444' : '#22c55e'">
{{ displayText }}
</div>
<div class="countdown-container">
<div class="time-box">
<div class="time-value" [class.flip]="days !== previousDays">{{ days }}</div>
<div class="time-label">Days</div>
</div>
<div class="time-box">
<div class="time-value" [class.flip]="hours !== previousHours">{{ hours }}</div>
<div class="time-label">Hours</div>
</div>
<div class="time-box">
<div class="time-value" [class.flip]="minutes !== previousMinutes">{{ minutes }}</div>
<div class="time-label">Minutes</div>
</div>
<div class="time-box">
<div class="time-value" [class.flip]="seconds !== previousSeconds">{{ seconds }}</div>
<div class="time-label">Seconds</div>
</div>
</div>
`,
animations: [
trigger('numberChange', [
transition(':increment', [
style({ transform: 'translateY(-100%)', opacity: 0 }),
animate('300ms ease-out', style({ transform: 'translateY(0)', opacity: 1 }))
]),
transition(':decrement', [
style({ transform: 'translateY(100%)', opacity: 0 }),
animate('300ms ease-out', style({ transform: 'translateY(0)', opacity: 1 }))
])
])
]
})
export class CountdownTimerComponent implements OnInit, OnDestroy {
@Input() startDate: number;
@Input() expiryDate: number;

private subscription: Subscription;
displayText: string = '';
hasStarted: boolean = false;

days: string = '00';
hours: string = '00';
minutes: string = '00';
seconds: string = '00';

previousDays: string = '00';
previousHours: string = '00';
previousMinutes: string = '00';
previousSeconds: string = '00';

ngOnInit() {
this.subscription = interval(1000).subscribe(() => {
this.updateTime();
});

this.updateTime();
}

ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}

private updateTime() {
const now = Math.floor(Date.now() / 1000);
const targetDate = this.hasStarted ? this.expiryDate : this.startDate;
const difference = targetDate - now;

if (now >= this.startDate && now < this.expiryDate) {
this.hasStarted = true;
this.displayText = 'Time Remaining:';
} else if (now < this.startDate) {
this.hasStarted = false;
this.displayText = 'Starting in:';
} else {
this.hasStarted = true;
this.displayText = 'Expired';
this.days = this.hours = this.minutes = this.seconds = '00';
return;
}

if (difference > 0) {
const days = Math.floor(difference / 86400);
const hours = Math.floor((difference % 86400) / 3600);
const minutes = Math.floor((difference % 3600) / 60);
const seconds = difference % 60;

this.previousDays = this.days;
this.previousHours = this.hours;
this.previousMinutes = this.minutes;
this.previousSeconds = this.seconds;

this.days = this.formatTimeUnit(days);
this.hours = this.formatTimeUnit(hours);
this.minutes = this.formatTimeUnit(minutes);
this.seconds = this.formatTimeUnit(seconds);
} else {
this.days = this.hours = this.minutes = this.seconds = '00';
}
}

private formatTimeUnit(unit: number): string {
return unit < 10 ? '0' + unit : unit.toString();
}
}
5 changes: 5 additions & 0 deletions src/app/components/explore/explore.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ <h2 class="text-xl font-semibold">Explore Projects</h2>
<hr class="my-6 w-full border-t" />

<!-- projectDetails -->
<countdown-timer
[startDate]="project.startDate"
[expiryDate]="project.expiryDate"
class="mb-4">
</countdown-timer>
<div class="grid grid-cols-2 gap-4">
<div class="flex flex-col">
<span class="text-sm text-gray-500">Target Amount</span>
Expand Down
2 changes: 2 additions & 0 deletions src/app/components/explore/explore.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { catchError, Observable, of, Subject, takeUntil, tap } from 'rxjs';
import { BookmarkService } from 'app/services/bookmark.service';
import { Project, ProjectDetails, ProjectStatistics } from 'app/interface/project.interface';
import { ProjectsService } from 'app/services/projects.service';
import { CountdownTimerComponent } from '../countdown-timer/countdown-timer.component';

@Component({
selector: 'explore',
Expand All @@ -52,6 +53,7 @@ import { ProjectsService } from 'app/services/projects.service';
MatProgressBarModule,
CommonModule,
MatProgressSpinnerModule,
CountdownTimerComponent,
]
})
export class ExploreComponent implements OnInit, OnDestroy {
Expand Down

0 comments on commit 809f2df

Please sign in to comment.