- {{ item.student_name }} |
-
- @if (item.sanitized_download_url) {
-
- {{ item.id_code }}
-
-
-
-
- } @else {
- {{ item.id_code }}
- }
- |
+ @if (widget) {
+
+ @if (item.sanitized_download_url) {
+
+ {{ item.student_name }}
+
+
+
+
+ } @else {
+ {{ item.student_name }}
+ }
+ |
+ } @else {
+ {{ 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;
|