nise/nise-frontend/src/app/search/search.component.ts

263 lines
6.7 KiB
TypeScript
Raw Normal View History

import {Component, OnInit} from '@angular/core';
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {DecimalPipe, JsonPipe, NgForOf, NgIf} from "@angular/common";
import {HttpClient} from "@angular/common/http";
import {environment} from "../../environments/environment";
import {countryCodeToFlag} from "../format";
import {OsuGradeComponent} from "../../corelib/components/osu-grade/osu-grade.component";
import {Field, Query, QueryBuilderComponent} from "../../corelib/components/query-builder/query-builder.component";
2024-02-24 13:59:17 +00:00
import {RouterLink} from "@angular/router";
import {CalculatePageRangePipe} from "../../corelib/calculate-page-range.pipe";
import {DownloadFilesService} from "../../corelib/service/download-files.service";
import {LocalCacheService} from "../../corelib/service/local-cache.service";
interface SchemaField {
name: string;
short_name: string;
category: 'user' | 'score' | 'beatmap';
type: 'number' | 'string' | 'flag' | 'grade' | 'boolean';
active: boolean;
description: string;
}
interface SchemaResponse {
fields: SchemaField[];
}
interface SearchResponse {
scores: SearchResponseEntry[];
2024-02-24 13:59:17 +00:00
pagination: SearchPagination;
}
interface SearchPagination {
currentPage: number;
pageSize: number;
totalResults: number;
totalPages: number;
}
interface Sorting {
field: string;
order: 'ASC' | 'DESC';
}
interface SearchResponseEntry {
// User fields
user_id?: number;
user_username?: string;
user_join_date?: string;
user_country?: string;
user_country_rank?: number;
user_rank?: number;
user_pp_raw?: number;
user_accuracy?: number;
user_playcount?: number;
user_total_score?: number;
user_ranked_score?: number;
user_seconds_played?: number;
user_count_300?: number;
user_count_100?: number;
user_count_50?: number;
user_count_miss?: number;
// Score fields
replay_id?: number;
date?: string;
beatmap_id?: number;
pp?: number;
frametime?: number;
ur?: number;
// Beatmap fields
beatmap_artist?: string;
beatmap_beatmapset_id?: number;
beatmap_creator?: string;
beatmap_source?: string;
beatmap_star_rating?: number;
beatmap_title?: string;
beatmap_version?: string;
}
@Component({
selector: 'app-search',
standalone: true,
imports: [
ReactiveFormsModule,
NgForOf,
FormsModule,
JsonPipe,
NgIf,
DecimalPipe,
OsuGradeComponent,
2024-02-24 13:59:17 +00:00
QueryBuilderComponent,
RouterLink,
CalculatePageRangePipe
],
templateUrl: './search.component.html',
styleUrl: './search.component.css'
})
export class SearchComponent implements OnInit {
constructor(private httpClient: HttpClient,
private localCacheService: LocalCacheService,
public downloadFilesService: DownloadFilesService) { }
isError = false;
2024-02-24 13:59:17 +00:00
isLoading = false;
response: SearchResponse | null = null;
fields: SchemaField[] = [];
sortingOrder: Sorting | null = null;
queries: Query[] | null = null;
ngOnInit(): void {
this.localCacheService.fetchData<SchemaResponse>(
"search-schema",
`${environment.apiUrl}/search`,
60
).subscribe({
next: (response) => {
this.fields = response.fields;
this.loadPreviousFromLocalStorage();
},
error: () => {
alert('Error fetching schema');
}
});
}
private loadPreviousFromLocalStorage() {
const storedQueries = localStorage.getItem('search_queries');
if (storedQueries) {
this.queries = JSON.parse(storedQueries);
} else {
this.queries = [];
}
// Load active/inactive status from localStorage
const storedStatus = localStorage.getItem('columns_status');
if (storedStatus) {
const statusMap = JSON.parse(storedStatus);
this.fields.forEach(field => {
if (statusMap.hasOwnProperty(field.name)) {
field.active = statusMap[field.name];
}
});
}
this.sortingOrder = {
field: 'user_id',
order: 'ASC'
};
}
deselectEntireFieldCategory(categoryName: string): void {
this.fields.forEach(field => {
if (field.category === categoryName) {
field.active = false;
}
});
this.saveColumnsStatusToLocalStorage();
}
selectEntireFieldCategory(categoryName: string): void {
this.fields.forEach(field => {
if (field.category === categoryName) {
field.active = true;
}
});
this.saveColumnsStatusToLocalStorage();
}
mapSchemaFieldsToFields(): Field[] {
return this.fields.map(field => {
return {
name: field.name,
type: field.type,
};
});
}
2024-02-24 13:59:17 +00:00
updateLocalStorage(): void {
console.warn('Updating local storage');
localStorage.setItem('search_queries', JSON.stringify(this.queries));
}
exportSettings(): void {
const settings = {
queries: this.queries,
sorting: this.sortingOrder
} as any;
this.downloadFilesService.downloadJSON(settings);
}
importSettings(event: any): void {
const file = event.target.files[0];
if (file) {
const fileReader = new FileReader();
fileReader.onload = (e) => {
try {
const json = JSON.parse(fileReader.result as string);
if (this.verifySchema(json)) {
this.queries = json.queries;
this.sortingOrder = json.sorting;
} else {
console.error('Invalid file schema');
}
} catch (error) {
console.error('Error parsing JSON', error);
}
};
fileReader.readAsText(file);
}
}
verifySchema(json: any): boolean {
// TODO: Implement schema verification logic here
return 'queries' in json && 'sorting' in json;
}
saveColumnsStatusToLocalStorage(): void {
const statusMap = this.fields.reduce<{ [key: string]: boolean }>((acc, field) => {
acc[field.name] = field.active;
return acc;
}, {});
localStorage.setItem('columns_status', JSON.stringify(statusMap));
}
2024-02-24 13:59:17 +00:00
search(pageNumber: number = 1): void {
this.isLoading = true;
this.isError = false;
this.response = null;
const body = {
queries: this.queries,
2024-02-24 13:59:17 +00:00
sorting: this.sortingOrder,
page: pageNumber
}
this.httpClient.post<SearchResponse>(`${environment.apiUrl}/search`, body)
.subscribe({
next: (response) => {
this.response = response;
this.isLoading = false;
},
error: (error) => {
this.isError = true;
this.isLoading = false;
}
});
2024-02-24 13:59:17 +00:00
this.updateLocalStorage();
}
// Add this method to the SearchComponent class
getValue(entry: SearchResponseEntry, columnName: string): any {
return entry[columnName as keyof SearchResponseEntry];
}
protected readonly countryCodeToFlag = countryCodeToFlag;
2024-02-24 13:59:17 +00:00
protected readonly Math = Math;
}