Files
canti/src/app/services/comunita.service.ts
T
David Frassi 8c9f9df11c fix: correzione filtro comunità al riavvio e priorità deduplicazione invertita
- Il background refresh al riavvio ora non riattiva il filtro comunità se comunitaEnabled è false nelle impostazioni, evitando di restringere silenziosamente il bacino dei canti.
- Invertita la logica di deduplicazione: in caso di canto duplicato (validato + non validato), ora vince la versione validata (ufficiale del catalogo).
2026-05-20 16:09:30 +02:00

233 lines
8.5 KiB
TypeScript

import { Injectable, signal, inject, effect } from '@angular/core';
import { HttpClient, HttpRequest, HttpEventType, HttpResponse } from '@angular/common/http';
import { SettingsService } from './settings.service';
import { Canto } from './canti.service';
export interface ParrocchiaItem {
id_parrocchia: number;
nome: string;
codice: string;
mail: string;
guid_parrocchia: string;
}
export interface ParrocchiaCantiItem {
id_parrocchia: number;
id_canti: number;
num_canto: number;
}
export interface CantiSettingsItem {
id_canti: number;
speed: number;
tonalita: number;
}
export interface GetAllAppTablesResponse {
parrocchia?: { data: ParrocchiaItem[] };
parrocchia_canti?: { data: ParrocchiaCantiItem[] };
canti_settings?: { data: CantiSettingsItem[] };
}
@Injectable({
providedIn: 'root'
})
export class ComunitaService {
private http = inject(HttpClient);
private settingsService = inject(SettingsService);
public comunitaCode = signal<string>('');
public comunitaNome = signal<string>('');
public comunitaMail = signal<string>('');
public comunitaCantiIds = signal<(number | string)[]>([]);
public comunitaCantiInfo = signal<ParrocchiaCantiItem[]>([]);
public comunitaCantiSettings = signal<CantiSettingsItem[]>([]);
public comunitaCantiPersonali = signal<Canto[]>([]);
public isFilterActive = signal<boolean>(false);
public loading = signal<boolean>(false);
public loadingProgress = signal<number>(0);
constructor() {
const savedCode = localStorage.getItem('comunita-code');
const savedNome = localStorage.getItem('comunita-nome');
const savedMail = localStorage.getItem('comunita-mail');
const savedCanti = localStorage.getItem('comunita-canti-ids');
const savedInfo = localStorage.getItem('comunita-canti-info');
const savedSettings = localStorage.getItem('comunita-canti-settings');
const savedCantiPersonali = localStorage.getItem('comunita-canti-personali');
const savedFilterActive = localStorage.getItem('comunita-filter-active') === 'true';
if (savedCode) {
this.comunitaCode.set(savedCode);
// Run background refresh 1 second after startup to fetch any new custom canti or updates
// but only if the community feature is enabled in settings
setTimeout(() => {
if (!this.settingsService.comunitaEnabled()) {
// Community is disabled: skip refresh to avoid re-enabling the filter
return;
}
this.setComunitaCode(savedCode).catch(err => {
console.warn('Failed background community refresh at startup:', err);
});
}, 1000);
}
if (savedNome) this.comunitaNome.set(savedNome);
if (savedMail) this.comunitaMail.set(savedMail);
if (savedCanti) {
try { this.comunitaCantiIds.set(JSON.parse(savedCanti)); } catch (e) {}
}
if (savedInfo) {
try { this.comunitaCantiInfo.set(JSON.parse(savedInfo)); } catch (e) {}
}
if (savedSettings) {
try { this.comunitaCantiSettings.set(JSON.parse(savedSettings)); } catch (e) {}
}
if (savedCantiPersonali) {
try { this.comunitaCantiPersonali.set(JSON.parse(savedCantiPersonali)); } catch (e) {}
}
this.isFilterActive.set(savedFilterActive);
effect(() => {
localStorage.setItem('comunita-code', this.comunitaCode());
localStorage.setItem('comunita-nome', this.comunitaNome());
localStorage.setItem('comunita-mail', this.comunitaMail());
localStorage.setItem('comunita-canti-ids', JSON.stringify(this.comunitaCantiIds()));
localStorage.setItem('comunita-canti-info', JSON.stringify(this.comunitaCantiInfo()));
localStorage.setItem('comunita-canti-settings', JSON.stringify(this.comunitaCantiSettings()));
localStorage.setItem('comunita-canti-personali', JSON.stringify(this.comunitaCantiPersonali()));
localStorage.setItem('comunita-filter-active', this.isFilterActive().toString());
});
effect(() => {
if (!this.settingsService.comunitaEnabled()) {
this.isFilterActive.set(false);
}
});
}
private fetchWithProgress<T>(url: string): Promise<T> {
return new Promise<T>((resolve, reject) => {
const req = new HttpRequest('GET', url, {
reportProgress: true,
responseType: 'json'
});
this.http.request<T>(req).subscribe({
next: (event) => {
if (event.type === HttpEventType.DownloadProgress) {
if (event.total && event.total > 0) {
const pct = Math.round((event.loaded / event.total) * 100);
this.loadingProgress.set(pct);
} else {
// No Content-Length header — simulate gradual progress up to 85%
const simulated = Math.min(85, this.loadingProgress() + 12);
this.loadingProgress.set(simulated);
}
} else if (event instanceof HttpResponse) {
this.loadingProgress.set(100);
resolve(event.body as T);
}
},
error: (err) => reject(err)
});
});
}
async setComunitaCode(code: string): Promise<boolean> {
const trimmedCode = code.trim();
if (!trimmedCode) {
this.comunitaCode.set('');
this.comunitaNome.set('');
this.comunitaMail.set('');
this.comunitaCantiIds.set([]);
this.comunitaCantiInfo.set([]);
this.comunitaCantiSettings.set([]);
this.comunitaCantiPersonali.set([]);
this.isFilterActive.set(false);
return true;
}
this.loading.set(true);
this.loadingProgress.set(0);
// 1. Try to fetch from the actual production API
try {
const url = `https://libretto.mmcinet.eu/canti/api/v3/get_all_app_tables?uuid=pwa-cc-uuid&email=&platform=browser&version=1.0&gruppo=${trimmedCode}&all_song=false&t=${Date.now()}`;
const data = await this.fetchWithProgress<GetAllAppTablesResponse>(url);
if (data && data.parrocchia?.data && data.parrocchia.data.length > 0) {
const parrocchia = data.parrocchia.data[0];
const cantiList = data.parrocchia_canti?.data || [];
const settingsList = data.canti_settings?.data || [];
// Parse canti_personali (custom unvalidated community canti)
const cantiPersonaliList = (data as any).canti_personali?.data || [];
const mappedCantiPersonali = cantiPersonaliList.map((cp: any) => ({
id: cp.id_canti.toString(),
id_canti: cp.id_canti,
titolo: cp.titolo,
testo: cp.accordi || '',
accordi: cp.accordi || '',
autore: cp.autore || '',
link_youtube: cp.link_youtube || '',
id_momenti: [],
data_update: cp.data_update || '',
nonValidato: true
}));
this.comunitaCode.set(trimmedCode);
this.comunitaNome.set(parrocchia.nome || `Comunità ${trimmedCode}`);
this.comunitaMail.set(parrocchia.mail || '');
this.comunitaCantiInfo.set(cantiList);
this.comunitaCantiIds.set(cantiList.map(c => c.id_canti));
this.comunitaCantiSettings.set(settingsList);
this.comunitaCantiPersonali.set(mappedCantiPersonali);
this.isFilterActive.set(true);
this.loading.set(false);
return true;
}
} catch (err) {
console.warn('Failed to fetch from production API, trying fallback...', err);
this.loadingProgress.set(0);
}
// 2. Fallback to static community JSON
try {
const isProduction = window.location.hostname.includes('canticristiani.it');
const origin = isProduction ? window.location.origin : 'https://www.canticristiani.it';
const fallbackUrl = `${origin}/api/comunita_${trimmedCode}.json?t=${Date.now()}`;
interface StaticComunitaData {
id_comunita: string;
nome_comunita: string;
canti: (number | string)[];
}
const staticData = await this.fetchWithProgress<StaticComunitaData>(fallbackUrl);
if (staticData && staticData.canti) {
this.comunitaCode.set(trimmedCode);
this.comunitaNome.set(staticData.nome_comunita || `Comunità ${trimmedCode}`);
this.comunitaCantiIds.set(staticData.canti);
const mockInfo = staticData.canti.map((id, index) => ({
id_parrocchia: 1,
id_canti: Number(id),
num_canto: index + 1
}));
this.comunitaCantiInfo.set(mockInfo);
this.comunitaCantiSettings.set([]);
this.comunitaCantiPersonali.set([]);
this.isFilterActive.set(true);
this.loading.set(false);
return true;
}
} catch (err) {
console.error('All community fetch strategies failed:', err);
}
this.loading.set(false);
return false;
}
}