From f1b829a10046546bf6ef54c3dba8798e976426d3 Mon Sep 17 00:00:00 2001 From: Jaanu423 Date: Fri, 26 Jun 2026 18:38:11 +0530 Subject: [PATCH] feat(election): candidate photos/symbols, voting interface, withdrawal, live vote counts - Candidate board: show client profile photos and election symbols via CBS ContentStore (lazy-fetch base64 via GET /election/{id}/candidate/{id}/symbol), zoom/drag viewer - Candidate board: live vote count badge per candidate (VOTING_OPEN/CLOSED only) - Election dashboard: total voters/votes chips on VOTING_OPEN election cards - Voting interface: fix candidates not loading (paged response .content extraction), lazy-load candidate photos and symbols, gold-bordered symbol on ballot card - Nomination withdrawal: implement withdraw button in nomination-detail and nomination-list - ImagePreviewDialogComponent: DomSanitizer support for data: URLs - election.service: uploadCandidateSymbol (FormData), getCandidateSymbol, getClientImage, getVoteSummary methods - main.scss: ipd-dialog / ipd-backdrop styles for image preview dialog Co-Authored-By: Claude Sonnet 4.6 --- .../transaction-entry.component.ts | 8 +- src/app/core/shell/shell.component.html | 10 +- src/app/core/shell/shell.component.ts | 10 +- .../candidate-board.component.html | 194 +++++- .../candidate-board.component.scss | 574 ++++++++++++++++-- .../candidate-board.component.ts | 147 ++++- .../election-dashboard.component.html | 12 +- .../election-dashboard.component.scss | 210 ++++--- .../election-dashboard.component.ts | 12 + .../nomination-detail.component.html | 15 +- .../nomination-detail.component.ts | 27 + .../nomination-list.component.html | 15 +- .../nomination-list.component.scss | 37 ++ .../nomination-list.component.ts | 28 + .../voting-interface.component.html | 8 +- .../voting-interface.component.scss | 10 +- .../voting-interface.component.ts | 40 +- src/app/election/election.service.ts | 31 + src/main.scss | 11 + 19 files changed, 1217 insertions(+), 182 deletions(-) diff --git a/src/app/cashier/transaction-entry/transaction-entry.component.ts b/src/app/cashier/transaction-entry/transaction-entry.component.ts index f20434ee7..4195071e1 100644 --- a/src/app/cashier/transaction-entry/transaction-entry.component.ts +++ b/src/app/cashier/transaction-entry/transaction-entry.component.ts @@ -8,6 +8,7 @@ import { Component, OnInit, OnDestroy, inject, Input } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { HttpClient, HttpParams } from '@angular/common/http'; import { catchError, debounceTime, distinctUntilChanged } from 'rxjs/operators'; @@ -439,7 +440,7 @@ export class JointHolderDialogComponent implements OnInit { [style.cursor]="dragging ? 'grabbing' : zoom > 1 ? 'grab' : 'zoom-in'" > >(MatDialogRef); data = inject<{ url: string; title: string }>(MAT_DIALOG_DATA); + private sanitizer = inject(DomSanitizer); + + get safeUrl(): SafeResourceUrl { + return this.sanitizer.bypassSecurityTrustResourceUrl(this.data.url); + } zoom = 1; tx = 0; diff --git a/src/app/core/shell/shell.component.html b/src/app/core/shell/shell.component.html index 2a331ead8..9a38e1bcd 100644 --- a/src/app/core/shell/shell.component.html +++ b/src/app/core/shell/shell.component.html @@ -57,10 +57,16 @@ - + @if (hideShellLayout && !isWithdrawalReviewUrl) { + + @if (currentUrl.includes('/election')) { + + } - @if (currentUrl.includes('/clerk/')) { + @else if (currentUrl.includes('/clerk/')) {