diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d4d1b4b26a..4844afab1b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "frontend", - "version": "1.0.94", + "version": "1.0.95", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "frontend", - "version": "1.0.94", + "version": "1.0.95", "dependencies": { "@angular/animations": "^17.3.12", "@angular/cdk": "^17.3.10", diff --git a/frontend/package.json b/frontend/package.json index fc81976b66..9003e5757a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "1.0.95", + "version": "1.0.103", "scripts": { "install:deps": "npm install", "start": "npm install && ng serve --configuration local --open", diff --git a/frontend/src/app/core/services/firestore.service.ts b/frontend/src/app/core/services/firestore.service.ts index e4ab475d79..1073919e4e 100644 --- a/frontend/src/app/core/services/firestore.service.ts +++ b/frontend/src/app/core/services/firestore.service.ts @@ -39,8 +39,4 @@ export class FirestoreService { const docRef = doc(this.heartbeatCollection, id); return deleteDoc(docRef); } - - getHeartbeatCollection() { - return this.heartbeatCollection; - } } diff --git a/frontend/src/app/features/leaderboard/leaderboard-apply/leaderboard-apply.component.html b/frontend/src/app/features/leaderboard/leaderboard-apply/leaderboard-apply.component.html new file mode 100644 index 0000000000..e5e3da605c --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-apply/leaderboard-apply.component.html @@ -0,0 +1,3 @@ + + Round 1 Applications Close in 5d 5h 12m - Apply arrow_right_alt + diff --git a/frontend/src/app/features/leaderboard/leaderboard-apply/leaderboard-apply.component.scss b/frontend/src/app/features/leaderboard/leaderboard-apply/leaderboard-apply.component.scss new file mode 100644 index 0000000000..447df2fdcb --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-apply/leaderboard-apply.component.scss @@ -0,0 +1,16 @@ +@import 'leaderboard-variables'; + +.gradient { + height: 52px; + background: $mina-brand-gradient; + top: 0; + left: 0; + font-family: "IBM Plex Mono", sans-serif; + font-size: 16px; + font-weight: 400; + color: $mina-base-primary; + + @media (max-width: 767px) { + font-size: 3.1vw; + } +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-apply/leaderboard-apply.component.ts b/frontend/src/app/features/leaderboard/leaderboard-apply/leaderboard-apply.component.ts new file mode 100644 index 0000000000..74c1035047 --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-apply/leaderboard-apply.component.ts @@ -0,0 +1,11 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'mina-leaderboard-apply', + templateUrl: './leaderboard-apply.component.html', + styleUrl: './leaderboard-apply.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class LeaderboardApplyComponent { + +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-details/leaderboard-details.component.html b/frontend/src/app/features/leaderboard/leaderboard-details/leaderboard-details.component.html new file mode 100644 index 0000000000..e62f0e1ccd --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-details/leaderboard-details.component.html @@ -0,0 +1,11 @@ + + +
+ +
+

Mina Web Node Testing Program

+

Details

+

TBD

+
+ +
diff --git a/frontend/src/app/features/leaderboard/leaderboard-details/leaderboard-details.component.scss b/frontend/src/app/features/leaderboard/leaderboard-details/leaderboard-details.component.scss new file mode 100644 index 0000000000..b5c5a9483d --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-details/leaderboard-details.component.scss @@ -0,0 +1,41 @@ +@import 'leaderboard-variables'; + +:host { + display: block; + height: 100%; + padding-top: 52px; + background-color: $mina-cta-primary; + color: $mina-base-primary; + font-family: "IBM Plex Sans", sans-serif; +} + +main, +mina-leaderboard-header, +mina-leaderboard-footer { + max-width: 1200px; + width: 100%; + padding: 0 48px; + margin: 0 auto; + + @media (max-width: 1023px) { + padding: 0; + } +} + +h2 { + margin-top: 72px; + margin-bottom: 16px; + color: $mina-base-secondary; + font-size: 20px; + font-weight: 500; + line-height: 28px; +} + +h1 { + margin-top: 0; + margin-bottom: 80px; + color: $mina-base-primary; + font-size: 80px; + font-weight: 400; + line-height: 80px; +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-details/leaderboard-details.component.ts b/frontend/src/app/features/leaderboard/leaderboard-details/leaderboard-details.component.ts new file mode 100644 index 0000000000..850603a0a0 --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-details/leaderboard-details.component.ts @@ -0,0 +1,11 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'mina-leaderboard-details', + templateUrl: './leaderboard-details.component.html', + styleUrl: './leaderboard-details.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class LeaderboardDetailsComponent { + +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-filters/leaderboard-filters.component.html b/frontend/src/app/features/leaderboard/leaderboard-filters/leaderboard-filters.component.html index ac68403582..0f9db55bdb 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-filters/leaderboard-filters.component.html +++ b/frontend/src/app/features/leaderboard/leaderboard-filters/leaderboard-filters.component.html @@ -14,7 +14,7 @@ arrow_upward - Block Production + Block Production diff --git a/frontend/src/app/features/leaderboard/leaderboard-footer/leaderboard-footer.component.html b/frontend/src/app/features/leaderboard/leaderboard-footer/leaderboard-footer.component.html index 63bc0a839f..cffccd6d15 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-footer/leaderboard-footer.component.html +++ b/frontend/src/app/features/leaderboard/leaderboard-footer/leaderboard-footer.component.html @@ -1,8 +1,8 @@
© 2025 Mina Foundation. All rights reserved.
- Terms of Service - Privacy Policy - Impressum + Terms and Conditions + Privacy Policy + Impressum
diff --git a/frontend/src/app/features/leaderboard/leaderboard-footer/leaderboard-footer.component.scss b/frontend/src/app/features/leaderboard/leaderboard-footer/leaderboard-footer.component.scss index f68a12943c..0515a8ec44 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-footer/leaderboard-footer.component.scss +++ b/frontend/src/app/features/leaderboard/leaderboard-footer/leaderboard-footer.component.scss @@ -24,6 +24,7 @@ } a { + color: $mina-base-primary; cursor: pointer; transition: .15s ease; diff --git a/frontend/src/app/features/leaderboard/leaderboard-header/leaderboard-header.component.html b/frontend/src/app/features/leaderboard/leaderboard-header/leaderboard-header.component.html index 66a6f65b40..2e93e9e1d0 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-header/leaderboard-header.component.html +++ b/frontend/src/app/features/leaderboard/leaderboard-header/leaderboard-header.component.html @@ -1,6 +1,5 @@ diff --git a/frontend/src/app/features/leaderboard/leaderboard-impressum/leaderboard-impressum.component.html b/frontend/src/app/features/leaderboard/leaderboard-impressum/leaderboard-impressum.component.html new file mode 100644 index 0000000000..d17e5c0faa --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-impressum/leaderboard-impressum.component.html @@ -0,0 +1,11 @@ + + +
+ +
+

Mina Web Node Testing Program

+

Impressum

+

TBD

+
+ +
diff --git a/frontend/src/app/features/leaderboard/leaderboard-impressum/leaderboard-impressum.component.scss b/frontend/src/app/features/leaderboard/leaderboard-impressum/leaderboard-impressum.component.scss new file mode 100644 index 0000000000..b5c5a9483d --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-impressum/leaderboard-impressum.component.scss @@ -0,0 +1,41 @@ +@import 'leaderboard-variables'; + +:host { + display: block; + height: 100%; + padding-top: 52px; + background-color: $mina-cta-primary; + color: $mina-base-primary; + font-family: "IBM Plex Sans", sans-serif; +} + +main, +mina-leaderboard-header, +mina-leaderboard-footer { + max-width: 1200px; + width: 100%; + padding: 0 48px; + margin: 0 auto; + + @media (max-width: 1023px) { + padding: 0; + } +} + +h2 { + margin-top: 72px; + margin-bottom: 16px; + color: $mina-base-secondary; + font-size: 20px; + font-weight: 500; + line-height: 28px; +} + +h1 { + margin-top: 0; + margin-bottom: 80px; + color: $mina-base-primary; + font-size: 80px; + font-weight: 400; + line-height: 80px; +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-impressum/leaderboard-impressum.component.ts b/frontend/src/app/features/leaderboard/leaderboard-impressum/leaderboard-impressum.component.ts new file mode 100644 index 0000000000..afa316342a --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-impressum/leaderboard-impressum.component.ts @@ -0,0 +1,11 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'mina-leaderboard-impressum', + templateUrl: './leaderboard-impressum.component.html', + styleUrl: './leaderboard-impressum.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class LeaderboardImpressumComponent { + +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.html b/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.html index 3a39c82699..c5a364c04b 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.html +++ b/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.html @@ -1,7 +1,4 @@ -
- Round 1 Applications Close in 5d 5h 12m - Apply arrow_right_alt -
- +
@@ -65,7 +62,7 @@

The Mina Web Node, part 1

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore .

diff --git a/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.scss b/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.scss index b5bfc76c70..0ee7917bcf 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.scss +++ b/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.scss @@ -10,20 +10,6 @@ font-family: "IBM Plex Sans", sans-serif; } -.gradient { - height: 52px; - background: $mina-brand-gradient; - top: 0; - font-family: "IBM Plex Mono", sans-serif; - font-size: 16px; - font-weight: 400; - color: $mina-base-primary; - - @media (max-width: 767px) { - font-size: 3.1vw; - } -} - main, mina-leaderboard-header, mina-leaderboard-footer { @@ -162,6 +148,10 @@ section { font-weight: 300; max-width: 760px; + @media (max-width: 1023px) { + font-size: 10vw; + } + span { color: $black5; } diff --git a/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.ts b/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.ts index 49e2cbb529..afce1668e7 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.ts +++ b/frontend/src/app/features/leaderboard/leaderboard-landing-page/leaderboard-landing-page.component.ts @@ -1,6 +1,4 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { StoreDispatcher } from '@shared/base-classes/store-dispatcher.class'; -import { LeaderboardActions } from '@leaderboard/leaderboard.actions'; @Component({ selector: 'mina-leaderboard-landing-page', @@ -9,10 +7,9 @@ import { LeaderboardActions } from '@leaderboard/leaderboard.actions'; changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'flex-column h-100 align-center' }, }) -export class LeaderboardLandingPageComponent extends StoreDispatcher implements OnInit { +export class LeaderboardLandingPageComponent implements OnInit { ngOnInit(): void { - this.dispatch2(LeaderboardActions.getHeartbeats()); } } diff --git a/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.html b/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.html index 75a4bf0380..dcdc8794c2 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.html +++ b/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.html @@ -1,6 +1,4 @@ -
- Round 1 Applications Close in 5d 5h 12m - Apply arrow_right_alt -
+
diff --git a/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.scss b/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.scss index 3badebe741..557f63b4eb 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.scss +++ b/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.scss @@ -5,20 +5,6 @@ background-color: $mina-cta-primary; } -.gradient { - height: 52px; - background: $mina-brand-gradient; - top: 0; - font-family: "IBM Plex Mono", sans-serif; - font-size: 16px; - font-weight: 400; - color: $mina-base-primary; - - @media (max-width: 767px) { - font-size: 3.1vw; - } -} - main, mina-leaderboard-header, mina-leaderboard-footer { diff --git a/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.ts b/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.ts index c5a6f20c2d..15e87823ce 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.ts +++ b/frontend/src/app/features/leaderboard/leaderboard-page/leaderboard-page.component.ts @@ -1,6 +1,8 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { StoreDispatcher } from '@shared/base-classes/store-dispatcher.class'; import { LeaderboardActions } from '@leaderboard/leaderboard.actions'; +import { timer } from 'rxjs'; +import { untilDestroyed } from '@ngneat/until-destroy'; @Component({ selector: 'mina-leaderboard-page', @@ -12,7 +14,11 @@ import { LeaderboardActions } from '@leaderboard/leaderboard.actions'; export class LeaderboardPageComponent extends StoreDispatcher implements OnInit { ngOnInit(): void { - this.dispatch2(LeaderboardActions.getHeartbeats()); + timer(0, 5000) + .pipe(untilDestroyed(this)) + .subscribe(() => { + this.dispatch2(LeaderboardActions.getHeartbeats()); + }); } } diff --git a/frontend/src/app/features/leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component.html b/frontend/src/app/features/leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component.html new file mode 100644 index 0000000000..06a069d919 --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component.html @@ -0,0 +1,11 @@ + + +
+ +
+

Mina Web Node Testing Program

+

Privacy Policy

+

TBD

+
+ +
diff --git a/frontend/src/app/features/leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component.scss b/frontend/src/app/features/leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component.scss new file mode 100644 index 0000000000..b5c5a9483d --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component.scss @@ -0,0 +1,41 @@ +@import 'leaderboard-variables'; + +:host { + display: block; + height: 100%; + padding-top: 52px; + background-color: $mina-cta-primary; + color: $mina-base-primary; + font-family: "IBM Plex Sans", sans-serif; +} + +main, +mina-leaderboard-header, +mina-leaderboard-footer { + max-width: 1200px; + width: 100%; + padding: 0 48px; + margin: 0 auto; + + @media (max-width: 1023px) { + padding: 0; + } +} + +h2 { + margin-top: 72px; + margin-bottom: 16px; + color: $mina-base-secondary; + font-size: 20px; + font-weight: 500; + line-height: 28px; +} + +h1 { + margin-top: 0; + margin-bottom: 80px; + color: $mina-base-primary; + font-size: 80px; + font-weight: 400; + line-height: 80px; +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component.ts b/frontend/src/app/features/leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component.ts new file mode 100644 index 0000000000..54daff4012 --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component.ts @@ -0,0 +1,11 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'mina-leaderboard-privacy-policy', + templateUrl: './leaderboard-privacy-policy.component.html', + styleUrl: './leaderboard-privacy-policy.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class LeaderboardPrivacyPolicyComponent { + +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.html b/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.html index d225b8fa1c..6c9f2f3686 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.html +++ b/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.html @@ -5,20 +5,46 @@ Produced Blocks
-
- @for (row of rows; track $index) { -
-
- - circle - {{ row.publicKey | truncateMid: (desktop ? 15 : 6): 6 }} - - - {{ row.uptimePercentage }}% - bookmark_check - - {{ row.blocksProduced ?? 0 }} +
+ @if (!isLoading) { + @for (row of rows; track $index) { +
+
+ + circle + {{ row.publicKey | truncateMid: (desktop ? 15 : 6): 6 }} + + + {{ row.uptimePercentage }}% + @if (row.uptimePercentage > 33.33) { + bookmark_check + } + @if (row.uptimePrize) { + + } + + + {{ row.blocksProduced ?? 0 }} + @if (row.blocksPrize) { + + } + +
+ } + } @else { +
+ +
Loading
}
+ + + + + + diff --git a/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.scss b/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.scss index 81c62669a9..a4868d0b6c 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.scss +++ b/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.scss @@ -11,7 +11,6 @@ } .row-wrap { - &.head { max-width: unset; height: 56px; @@ -22,7 +21,7 @@ } } - &:nth-child(odd):not(.head) { + &.odd:not(.head) { background-color: $mina-base-container; } } @@ -55,7 +54,10 @@ } .perc { - width: 50px; + width: 37px; + @media (max-width: 480px) { + width: 26px; + } } .circle.active { @@ -77,3 +79,17 @@ padding-left: 2px; } } + +:host ::ng-deep mina-loading-spinner .loading { + border: 1px solid $mina-base-primary !important; + border-top-color: transparent !important; +} + +.p-absolute { + background-color: $mina-cta-primary; +} + +mina-loading-spinner + div { + font-family: "IBM Plex Sans", sans-serif; + color: $mina-base-primary; +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.ts b/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.ts index e8c77a914c..a36b6fcc7a 100644 --- a/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.ts +++ b/frontend/src/app/features/leaderboard/leaderboard-table/leaderboard-table.component.ts @@ -3,6 +3,7 @@ import { LeaderboardSelectors } from '@leaderboard/leaderboard.state'; import { HeartbeatSummary } from '@shared/types/leaderboard/heartbeat-summary.type'; import { StoreDispatcher } from '@shared/base-classes/store-dispatcher.class'; import { isDesktop } from '@openmina/shared'; +import { animate, style, transition, trigger } from '@angular/animations'; @Component({ selector: 'mina-leaderboard-table', @@ -10,10 +11,21 @@ import { isDesktop } from '@openmina/shared'; styleUrl: './leaderboard-table.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'flex-column w-100 h-100' }, + animations: [ + trigger('fadeInOut', [ + transition(':enter', [ + style({ opacity: 0 }), + animate('400ms linear', style({ opacity: 1 })), + ]), + transition(':leave', [ + animate('400ms linear', style({ opacity: 0 })), + ]), + ]), + ], }) export class LeaderboardTableComponent extends StoreDispatcher implements OnInit { - isLoading: boolean; + isLoading: boolean = true; rows: HeartbeatSummary[] = []; desktop: boolean = isDesktop(); diff --git a/frontend/src/app/features/leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component.html b/frontend/src/app/features/leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component.html new file mode 100644 index 0000000000..2c5e2dcd0c --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component.html @@ -0,0 +1,11 @@ + + +
+ +
+

Mina Web Node Testing Program

+

Terms and Conditions

+

TBD

+
+ +
diff --git a/frontend/src/app/features/leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component.scss b/frontend/src/app/features/leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component.scss new file mode 100644 index 0000000000..b5c5a9483d --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component.scss @@ -0,0 +1,41 @@ +@import 'leaderboard-variables'; + +:host { + display: block; + height: 100%; + padding-top: 52px; + background-color: $mina-cta-primary; + color: $mina-base-primary; + font-family: "IBM Plex Sans", sans-serif; +} + +main, +mina-leaderboard-header, +mina-leaderboard-footer { + max-width: 1200px; + width: 100%; + padding: 0 48px; + margin: 0 auto; + + @media (max-width: 1023px) { + padding: 0; + } +} + +h2 { + margin-top: 72px; + margin-bottom: 16px; + color: $mina-base-secondary; + font-size: 20px; + font-weight: 500; + line-height: 28px; +} + +h1 { + margin-top: 0; + margin-bottom: 80px; + color: $mina-base-primary; + font-size: 80px; + font-weight: 400; + line-height: 80px; +} diff --git a/frontend/src/app/features/leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component.ts b/frontend/src/app/features/leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component.ts new file mode 100644 index 0000000000..ebb2ba6d5c --- /dev/null +++ b/frontend/src/app/features/leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component.ts @@ -0,0 +1,11 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'mina-leaderboard-terms-and-conditions', + templateUrl: './leaderboard-terms-and-conditions.component.html', + styleUrl: './leaderboard-terms-and-conditions.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class LeaderboardTermsAndConditionsComponent { + +} diff --git a/frontend/src/app/features/leaderboard/leaderboard.module.ts b/frontend/src/app/features/leaderboard/leaderboard.module.ts index b44db7f664..44c318a2f0 100644 --- a/frontend/src/app/features/leaderboard/leaderboard.module.ts +++ b/frontend/src/app/features/leaderboard/leaderboard.module.ts @@ -13,6 +13,11 @@ import { EffectsModule } from '@ngrx/effects'; import { LeaderboardEffects } from '@leaderboard/leaderboard.effects'; import { LeaderboardFooterComponent } from '@leaderboard/leaderboard-footer/leaderboard-footer.component'; import { LeaderboardLandingPageComponent } from '@leaderboard/leaderboard-landing-page/leaderboard-landing-page.component'; +import { LeaderboardDetailsComponent } from '@leaderboard/leaderboard-details/leaderboard-details.component'; +import { LeaderboardTermsAndConditionsComponent } from '@leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component'; +import { LeaderboardImpressumComponent } from '@leaderboard/leaderboard-impressum/leaderboard-impressum.component'; +import { LeaderboardPrivacyPolicyComponent } from '@leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component'; +import { LeaderboardApplyComponent } from '@leaderboard/leaderboard-apply/leaderboard-apply.component'; @NgModule({ @@ -24,6 +29,11 @@ import { LeaderboardLandingPageComponent } from '@leaderboard/leaderboard-landin LeaderboardTitleComponent, LeaderboardFooterComponent, LeaderboardLandingPageComponent, + LeaderboardDetailsComponent, + LeaderboardTermsAndConditionsComponent, + LeaderboardImpressumComponent, + LeaderboardPrivacyPolicyComponent, + LeaderboardApplyComponent, ], imports: [ CommonModule, diff --git a/frontend/src/app/features/leaderboard/leaderboard.routing.ts b/frontend/src/app/features/leaderboard/leaderboard.routing.ts index 32e605a291..69b819e42c 100644 --- a/frontend/src/app/features/leaderboard/leaderboard.routing.ts +++ b/frontend/src/app/features/leaderboard/leaderboard.routing.ts @@ -1,12 +1,32 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { LeaderboardPageComponent } from '@leaderboard/leaderboard-page/leaderboard-page.component'; +import { LeaderboardDetailsComponent } from '@leaderboard/leaderboard-details/leaderboard-details.component'; +import { LeaderboardPrivacyPolicyComponent } from '@leaderboard/leaderboard-privacy-policy/leaderboard-privacy-policy.component'; +import { LeaderboardTermsAndConditionsComponent } from '@leaderboard/leaderboard-terms-and-conditions/leaderboard-terms-and-conditions.component'; +import { LeaderboardImpressumComponent } from '@leaderboard/leaderboard-impressum/leaderboard-impressum.component'; const routes: Routes = [ { path: 'leaderboard', component: LeaderboardPageComponent, }, + { + path: 'leaderboard/details', + component: LeaderboardDetailsComponent, + }, + { + path: 'leaderboard/impressum', + component: LeaderboardImpressumComponent, + }, + { + path: 'leaderboard/privacy-policy', + component: LeaderboardPrivacyPolicyComponent, + }, + { + path: 'leaderboard/terms-and-conditions', + component: LeaderboardTermsAndConditionsComponent, + }, { path: '**', redirectTo: '', diff --git a/frontend/src/app/features/leaderboard/leaderboard.service.ts b/frontend/src/app/features/leaderboard/leaderboard.service.ts index e18eb7efbe..6c19937356 100644 --- a/frontend/src/app/features/leaderboard/leaderboard.service.ts +++ b/frontend/src/app/features/leaderboard/leaderboard.service.ts @@ -1,258 +1,47 @@ import { Injectable } from '@angular/core'; -import { Observable, of } from 'rxjs'; +import { combineLatest, map, Observable } from 'rxjs'; import { HeartbeatSummary } from '@shared/types/leaderboard/heartbeat-summary.type'; +import { collection, collectionData, CollectionReference, Firestore } from '@angular/fire/firestore'; @Injectable({ providedIn: 'root', }) export class LeaderboardService { - constructor() { } + private scoresCollection: CollectionReference; + private maxScoreCollection: CollectionReference; + + constructor(private firestore: Firestore) { + this.scoresCollection = collection(this.firestore, 'scores'); + this.maxScoreCollection = collection(this.firestore, 'maxScore'); + } getHeartbeatsSummaries(): Observable { - const mockData: HeartbeatSummary[] = [ - { - publicKey: '0x7a23c98f21345dc98e23a5b1c98d23b1c98d23b1c', - isActive: true, - uptimePercentage: 99.8, - blocksProduced: 1243, - }, - { - publicKey: '0x8b34d09e32456ed09f34b6c2d09f34b6c2d09f34', - isActive: true, - uptimePercentage: 98.2, - blocksProduced: 982, - }, - { - publicKey: '0x9c45e10f43567fe10a45c7d3e10a45c7d3e10a45', - isActive: false, - uptimePercentage: 45.6, - blocksProduced: 234, - }, - { - publicKey: '0x0d56f21g54678gf21b56d8e4f21b56d8e4f21b56', - isActive: true, - uptimePercentage: 56.9, - blocksProduced: 876, - }, - { - publicKey: '0x1e67g32h65789hg32c67e9f5g32c67e9f5g32c67', - isActive: true, - uptimePercentage: 23.1, - blocksProduced: 1102, - }, - { - publicKey: '0x7a23c98f21345dc98e23a5b1c98d23b1c98d23b1c', - isActive: true, - uptimePercentage: 99.8, - blocksProduced: 1243, - }, - { - publicKey: '0x8b34d09e32456ed09f34b6c2d09f34b6c2d09f34', - isActive: false, - uptimePercentage: 98.2, - blocksProduced: 982, - }, - { - publicKey: '0x9c45e10f43567fe10a45c7d3e10a45c7d3e10a45', - isActive: false, - uptimePercentage: 45.6, - blocksProduced: 234, - }, - { - publicKey: '0x0d56f21g54678gf21b56d8e4f21b56d8e4f21b56', - isActive: true, - uptimePercentage: 56.9, - blocksProduced: 876, - }, - { - publicKey: '0x1e67g32h65789hg32c67e9f5g32c67e9f5g32c67', - isActive: false, - uptimePercentage: 23.1, - blocksProduced: 1102, - }, - { - publicKey: '0x7a23c98f21345dc98e23a5b1c98d23b1c98d23b1c', - isActive: false, - uptimePercentage: 99.8, - blocksProduced: 1243, - }, - { - publicKey: '0x8b34d09e32456ed09f34b6c2d09f34b6c2d09f34', - isActive: false, - uptimePercentage: 98.2, - blocksProduced: 982, - }, - { - publicKey: '0x9c45e10f43567fe10a45c7d3e10a45c7d3e10a45', - isActive: false, - uptimePercentage: 45.6, - blocksProduced: 234, - }, - { - publicKey: '0x0d56f21g54678gf21b56d8e4f21b56d8e4f21b56', - isActive: true, - uptimePercentage: 56.9, - blocksProduced: 876, - }, - { - publicKey: '0x1e67g32h65789hg32c67e9f5g32c67e9f5g32c67', - isActive: true, - uptimePercentage: 23.1, - blocksProduced: 1102, - }, - { - publicKey: '0x7a23c98f21345dc98e23a5b1c98d23b1c98d23b1c', - isActive: true, - uptimePercentage: 99.8, - blocksProduced: 1243, - }, - { - publicKey: '0x8b34d09e32456ed09f34b6c2d09f34b6c2d09f34', - isActive: true, - uptimePercentage: 98.2, - blocksProduced: 982, - }, - { - publicKey: '0x9c45e10f43567fe10a45c7d3e10a45c7d3e10a45', - isActive: false, - uptimePercentage: 45.6, - blocksProduced: 234, - }, - { - publicKey: '0x0d56f21g54678gf21b56d8e4f21b56d8e4f21b56', - isActive: true, - uptimePercentage: 56.9, - blocksProduced: 876, - }, - { - publicKey: '0x1e67g32h65789hg32c67e9f5g32c67e9f5g32c67', - isActive: true, - uptimePercentage: 23.1, - blocksProduced: 1102, - }, - { - publicKey: '0x7a23c98f21345dc98e23a5b1c98d23b1c98d23b1c', - isActive: true, - uptimePercentage: 99.8, - blocksProduced: 1243, - }, - { - publicKey: '0x8b34d09e32456ed09f34b6c2d09f34b6c2d09f34', - isActive: true, - uptimePercentage: 98.2, - blocksProduced: 982, - }, - { - publicKey: '0x9c45e10f43567fe10a45c7d3e10a45c7d3e10a45', - isActive: false, - uptimePercentage: 45.6, - blocksProduced: 234, - }, - { - publicKey: '0x0d56f21g54678gf21b56d8e4f21b56d8e4f21b56', - isActive: true, - uptimePercentage: 56.9, - blocksProduced: 876, - }, - { - publicKey: '0x1e67g32h65789hg32c67e9f5g32c67e9f5g32c67', - isActive: true, - uptimePercentage: 23.1, - blocksProduced: 1102, - }, - { - publicKey: '0x7a23c98f21345dc98e23a5b1c98d23b1c98d23b1c', - isActive: true, - uptimePercentage: 99.8, - blocksProduced: 1243, - }, - { - publicKey: '0x8b34d09e32456ed09f34b6c2d09f34b6c2d09f34', - isActive: false, - uptimePercentage: 98.2, - blocksProduced: 982, - }, - { - publicKey: '0x9c45e10f43567fe10a45c7d3e10a45c7d3e10a45', - isActive: false, - uptimePercentage: 45.6, - blocksProduced: 234, - }, - { - publicKey: '0x0d56f21g54678gf21b56d8e4f21b56d8e4f21b56', - isActive: true, - uptimePercentage: 56.9, - blocksProduced: 876, - }, - { - publicKey: '0x1e67g32h65789hg32c67e9f5g32c67e9f5g32c67', - isActive: false, - uptimePercentage: 23.1, - blocksProduced: 1102, - }, - { - publicKey: '0x7a23c98f21345dc98e23a5b1c98d23b1c98d23b1c', - isActive: false, - uptimePercentage: 99.8, - blocksProduced: 1243, - }, - { - publicKey: '0x8b34d09e32456ed09f34b6c2d09f34b6c2d09f34', - isActive: false, - uptimePercentage: 98.2, - blocksProduced: 982, - }, - { - publicKey: '0x9c45e10f43567fe10a45c7d3e10a45c7d3e10a45', - isActive: false, - uptimePercentage: 45.6, - blocksProduced: 234, - }, - { - publicKey: '0x0d56f21g54678gf21b56d8e4f21b56d8e4f21b56', - isActive: true, - uptimePercentage: 56.9, - blocksProduced: 876, - }, - { - publicKey: '0x1e67g32h65789hg32c67e9f5g32c67e9f5g32c67', - isActive: true, - uptimePercentage: 23.1, - blocksProduced: 1102, - }, - { - publicKey: '0x7a23c98f21345dc98e23a5b1c98d23b1c98d23b1c', - isActive: true, - uptimePercentage: 99.8, - blocksProduced: 1243, - }, - { - publicKey: '0x8b34d09e32456ed09f34b6c2d09f34b6c2d09f34', - isActive: true, - uptimePercentage: 98.2, - blocksProduced: 982, - }, - { - publicKey: '0x9c45e10f43567fe10a45c7d3e10a45c7d3e10a45', - isActive: false, - uptimePercentage: 45.6, - blocksProduced: 234, - }, - { - publicKey: '0x0d56f21g54678gf21b56d8e4f21b56d8e4f21b56', - isActive: true, - uptimePercentage: 56.9, - blocksProduced: 876, - }, - { - publicKey: '0x1e67g32h65789hg32c67e9f5g32c67e9f5g32c67', - isActive: true, - uptimePercentage: 23.1, - blocksProduced: 1102, - }, - ]; + return combineLatest([ + collectionData(this.scoresCollection, { idField: 'id' }), + collectionData(this.maxScoreCollection, { idField: 'id' }), + ]).pipe( + map(([scores, maxScore]) => { + const maxScoreRightNow = maxScore.find(c => c.id === 'current')['value']; + + const items = scores.map(score => ({ + publicKey: score['publicKey'], + blocksProduced: score['blocksProduced'], + isActive: score['lastUpdated'] > Date.now() - 120000, + uptimePercentage: Math.floor((score['score'] / maxScoreRightNow) * 100), + uptimePrize: false, + blocksPrize: false, + } as HeartbeatSummary)); - return of(mockData); + const sortedItemsByUptime = [...items].sort((a, b) => b.uptimePercentage - a.uptimePercentage); + const fifthPlacePercentageByUptime = sortedItemsByUptime[4]?.uptimePercentage ?? 0; + const highestProducedBlocks = Math.max(...items.map(item => item.blocksProduced)); + return items.map(item => ({ + ...item, + uptimePrize: item.uptimePercentage >= fifthPlacePercentageByUptime, + blocksPrize: item.blocksProduced === highestProducedBlocks, + })); + }), + ); } } diff --git a/frontend/src/app/features/web-node/web-node.component.ts b/frontend/src/app/features/web-node/web-node.component.ts index 68de34ddd1..81f919da09 100644 --- a/frontend/src/app/features/web-node/web-node.component.ts +++ b/frontend/src/app/features/web-node/web-node.component.ts @@ -31,6 +31,7 @@ export class WebNodeComponent extends StoreDispatcher implements OnInit { private webNodeService: WebNodeService) { super(); } ngOnInit(): void { + document.body.style.backgroundColor = 'var(--base-background)'; this.listenToFileUploadingEvents(); this.checkIfDeviceIsSupported(); this.listenToRoute(); diff --git a/frontend/src/app/shared/types/leaderboard/heartbeat-summary.type.ts b/frontend/src/app/shared/types/leaderboard/heartbeat-summary.type.ts index db5e249ab2..a134981c2f 100644 --- a/frontend/src/app/shared/types/leaderboard/heartbeat-summary.type.ts +++ b/frontend/src/app/shared/types/leaderboard/heartbeat-summary.type.ts @@ -3,4 +3,6 @@ export interface HeartbeatSummary { isActive: boolean; uptimePercentage: number; blocksProduced: number; + uptimePrize: boolean; + blocksPrize: boolean; } diff --git a/frontend/src/index.html b/frontend/src/index.html index 874924d364..e627af2266 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -49,13 +49,18 @@