diff --git a/frontend/src/app/components/custom-dashboard/custom-dashboard.component.html b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.html index 543c8eedb..02c860cae 100644 --- a/frontend/src/app/components/custom-dashboard/custom-dashboard.component.html +++ b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.html @@ -334,6 +334,7 @@ +
View more »
diff --git a/frontend/src/app/components/simpleproof-widget/simpleproof-cubo-widget.component.html b/frontend/src/app/components/simpleproof-widget/simpleproof-cubo-widget.component.html index dc82e7215..fd16910b5 100644 --- a/frontend/src/app/components/simpleproof-widget/simpleproof-cubo-widget.component.html +++ b/frontend/src/app/components/simpleproof-widget/simpleproof-cubo-widget.component.html @@ -29,10 +29,22 @@ i18n-placeholder="simpleproof.search_placeholder" > - +
- - + + @@ -50,19 +62,34 @@ - - + @if (widget) { + + } @else { + + + }
Student NameID + Student Name +
+ + +
+
+ ID +
+ + +
+
Proof
{{ item.student_name }} - @if (item.sanitized_download_url) { - - {{ item.id_code }} - - - - - } @else { - {{ item.id_code }} - } - + @if (item.sanitized_download_url) { + + {{ item.student_name }} + + + + + } @else { + {{ item.student_name }} + } + {{ item.student_name }} + @if (item.sanitized_download_url) { + + {{ item.id_code }} + + + + + } @else { + {{ item.id_code }} + } + diff --git a/frontend/src/app/components/simpleproof-widget/simpleproof-cubo-widget.component.ts b/frontend/src/app/components/simpleproof-widget/simpleproof-cubo-widget.component.ts index afb6386b4..87d8836a2 100644 --- a/frontend/src/app/components/simpleproof-widget/simpleproof-cubo-widget.component.ts +++ b/frontend/src/app/components/simpleproof-widget/simpleproof-cubo-widget.component.ts @@ -13,6 +13,9 @@ export interface SimpleProofCubo { parsed?: { type: string; year: number; studentNumber: number }; } +export type SortField = 'student_name' | 'id_code' | null; +export type SortDirection = 'asc' | 'desc'; + @Component({ selector: 'app-simpleproof-cubo-widget', templateUrl: './simpleproof-cubo-widget.component.html', @@ -35,6 +38,8 @@ export class SimpleProofCuboWidgetComponent implements OnChanges { lastPage = 1; itemsPerPage = 15; paginationMaxSize = window.innerWidth <= 767.98 ? 3 : 5; + sortField: SortField = null; + sortDirection: SortDirection = 'asc'; constructor( private servicesApiService: ServicesApiServices, @@ -122,6 +127,11 @@ export class SimpleProofCuboWidgetComponent implements OnChanges { } else { this.filteredVerified = this.verified; } + + if (this.sortField) { + this.applySort(); + } + this.page = 1; this.updatePage(); } @@ -134,4 +144,56 @@ export class SimpleProofCuboWidgetComponent implements OnChanges { this.page = page; this.updatePage(); } + + sortBy(field: SortField, direction?: SortDirection): boolean { + if (field && direction) { + this.sortField = field; + this.sortDirection = direction; + } else { + if (this.sortField === field) { + if (this.sortDirection === 'asc') { + this.sortDirection = 'desc'; + } else { + this.sortField = null; + } + } else { + this.sortField = field; + this.sortDirection = 'asc'; + } + } + + this.applySort(); + this.page = 1; + this.updatePage(); + return false; + } + + applySort(): void { + // default to ascending sort by id + const sortByField = this.sortField || 'id_code'; + const sortDirection = this.sortField ? this.sortDirection : 'asc'; + + const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); + + this.filteredVerified.sort((a, b) => { + let comparison = 0; + if (sortByField === 'student_name') { + comparison = collator.compare(a.student_name, b.student_name); + } else if (sortByField === 'id_code') { + // For ID sorting, try to use the parsed Cubo key logic first + if (a.parsed && b.parsed) { + if (a.parsed.year !== b.parsed.year) { + comparison = a.parsed.year - b.parsed.year; + } else if (a.parsed.type !== b.parsed.type) { + comparison = a.parsed.type.localeCompare(b.parsed.type); + } else { + comparison = a.parsed.studentNumber - b.parsed.studentNumber; + } + } else { + comparison = collator.compare(a.id_code, b.id_code); + } + } + return sortDirection === 'asc' ? comparison : -comparison; + }); + } } diff --git a/frontend/src/app/components/simpleproof-widget/simpleproof-widget.component.scss b/frontend/src/app/components/simpleproof-widget/simpleproof-widget.component.scss index ad0bf96dd..e52b383a1 100644 --- a/frontend/src/app/components/simpleproof-widget/simpleproof-widget.component.scss +++ b/frontend/src/app/components/simpleproof-widget/simpleproof-widget.component.scss @@ -60,6 +60,14 @@ tr, td, th { white-space: nowrap; } +.student { + width: 50%; + max-width: 300px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + .hash { width: 20%; max-width: 700px; @@ -70,9 +78,7 @@ tr, td, th { td.hash { font-family: monospace; } -.widget .hash { - display: none; -} + @media (max-width: 1200px) { .hash { display: none; @@ -93,10 +99,52 @@ td.verified { } .proof { - width: 25%; + width: 120px; padding-left: 0; } +.widget { + &.id, &.hash { + display: none; + } + &.student { + width: 100%; + } + &.proof { + width: 120px; + } +} + +.sortable { + user-select: none; + transition: background-color 0.2s ease; + + &:hover { + background-color: rgba(0, 0, 0, 0.05); + } +} + +.sort-icons { + display: inline-flex; + line-height: 1; + flex-direction: column; + width: 1em; + height: 100%; + align-items: center; + justify-content: center; + vertical-align: middle; + + fa-icon { + transition: color 0.2s ease; + margin: -0.25em 0; + pointer-events: all; + color: var(--secondary); + &.active { + color: var(--info); + } + } +} + .badge-verify { font-size: 1.05em; font-weight: normal;