ciyidogan commited on
Commit
94f7a1e
·
verified ·
1 Parent(s): 4e8cf3c

Update flare-ui/src/app/services/locale-manager.service.ts

Browse files
flare-ui/src/app/services/locale-manager.service.ts CHANGED
@@ -1,7 +1,10 @@
 
 
 
1
  import { Injectable } from '@angular/core';
2
- import { HttpClient, HttpHeaders } from '@angular/common/http';
3
- import { Observable, of } from 'rxjs';
4
- import { map, catchError } from 'rxjs/operators';
5
  import { AuthService } from './auth.service';
6
 
7
  export interface Locale {
@@ -33,6 +36,9 @@ export interface LocaleDetails extends Locale {
33
  export class LocaleManagerService {
34
  private apiUrl = '/api';
35
  private localesCache?: Locale[];
 
 
 
36
 
37
  constructor(
38
  private http: HttpClient,
@@ -41,6 +47,10 @@ export class LocaleManagerService {
41
 
42
  private getAuthHeaders(): HttpHeaders {
43
  const token = this.authService.getToken();
 
 
 
 
44
  return new HttpHeaders({
45
  'Authorization': `Bearer ${token}`,
46
  'Content-Type': 'application/json'
@@ -48,49 +58,154 @@ export class LocaleManagerService {
48
  }
49
 
50
  getAvailableLocales(): Observable<Locale[]> {
51
- if (this.localesCache) {
52
- return of(this.localesCache);
53
- }
 
 
 
 
 
54
 
55
- return this.http.get<{ locales: Locale[], default: string }>(
56
- `${this.apiUrl}/locales`,
57
- { headers: this.getAuthHeaders() }
58
- ).pipe(
59
- map(response => {
60
- this.localesCache = response.locales;
61
- return response.locales;
62
- }),
63
- catchError(() => {
64
- // Fallback locales if API fails
65
- const fallback = [
66
- { code: 'tr-TR', name: 'Türkçe', english_name: 'Turkish' },
67
- { code: 'en-US', name: 'English', english_name: 'English (US)' }
68
- ];
69
- this.localesCache = fallback;
70
- return of(fallback);
71
- })
72
- );
73
  }
74
 
75
  getLocaleDetails(code: string): Observable<LocaleDetails | null> {
76
- return this.http.get<LocaleDetails>(
77
- `${this.apiUrl}/locales/${code}`,
78
- { headers: this.getAuthHeaders() }
79
- ).pipe(
80
- catchError(() => of(null))
81
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  }
83
 
84
  validateLanguages(languages: string[]): Observable<string[]> {
85
- return this.getAvailableLocales().pipe(
86
- map(locales => {
87
- const availableCodes = locales.map(l => l.code);
88
- return languages.filter(lang => !availableCodes.includes(lang));
89
- })
90
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
92
 
93
  clearCache(): void {
94
  this.localesCache = undefined;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  }
96
  }
 
1
+ // locale-manager.service.ts
2
+ // Path: /flare-ui/src/app/services/locale-manager.service.ts
3
+
4
  import { Injectable } from '@angular/core';
5
+ import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
6
+ import { Observable, of, throwError } from 'rxjs';
7
+ import { map, catchError, retry, timeout } from 'rxjs/operators';
8
  import { AuthService } from './auth.service';
9
 
10
  export interface Locale {
 
36
  export class LocaleManagerService {
37
  private apiUrl = '/api';
38
  private localesCache?: Locale[];
39
+ private cacheTimestamp?: number;
40
+ private readonly CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
41
+ private readonly REQUEST_TIMEOUT = 10000; // 10 seconds
42
 
43
  constructor(
44
  private http: HttpClient,
 
47
 
48
  private getAuthHeaders(): HttpHeaders {
49
  const token = this.authService.getToken();
50
+ if (!token) {
51
+ throw new Error('No authentication token available');
52
+ }
53
+
54
  return new HttpHeaders({
55
  'Authorization': `Bearer ${token}`,
56
  'Content-Type': 'application/json'
 
58
  }
59
 
60
  getAvailableLocales(): Observable<Locale[]> {
61
+ try {
62
+ // Check cache validity
63
+ if (this.localesCache && this.cacheTimestamp) {
64
+ const now = Date.now();
65
+ if (now - this.cacheTimestamp < this.CACHE_DURATION) {
66
+ return of(this.localesCache);
67
+ }
68
+ }
69
 
70
+ return this.http.get<{ locales: Locale[], default: string }>(
71
+ `${this.apiUrl}/locales`,
72
+ { headers: this.getAuthHeaders() }
73
+ ).pipe(
74
+ timeout(this.REQUEST_TIMEOUT),
75
+ retry({ count: 2, delay: 1000 }),
76
+ map(response => {
77
+ this.localesCache = response.locales;
78
+ this.cacheTimestamp = Date.now();
79
+ return response.locales;
80
+ }),
81
+ catchError(error => this.handleError(error, 'getAvailableLocales'))
82
+ );
83
+ } catch (error) {
84
+ return this.handleError(error, 'getAvailableLocales');
85
+ }
 
 
86
  }
87
 
88
  getLocaleDetails(code: string): Observable<LocaleDetails | null> {
89
+ if (!code) {
90
+ return throwError(() => new Error('Locale code is required'));
91
+ }
92
+
93
+ try {
94
+ return this.http.get<LocaleDetails>(
95
+ `${this.apiUrl}/locales/${encodeURIComponent(code)}`,
96
+ { headers: this.getAuthHeaders() }
97
+ ).pipe(
98
+ timeout(this.REQUEST_TIMEOUT),
99
+ retry({ count: 2, delay: 1000 }),
100
+ catchError(error => {
101
+ // For 404, return null instead of throwing
102
+ if (error.status === 404) {
103
+ console.warn(`Locale '${code}' not found`);
104
+ return of(null);
105
+ }
106
+ return this.handleError(error, 'getLocaleDetails');
107
+ })
108
+ );
109
+ } catch (error) {
110
+ return this.handleError(error, 'getLocaleDetails');
111
+ }
112
  }
113
 
114
  validateLanguages(languages: string[]): Observable<string[]> {
115
+ if (!languages || languages.length === 0) {
116
+ return of([]);
117
+ }
118
+
119
+ try {
120
+ return this.getAvailableLocales().pipe(
121
+ map(locales => {
122
+ const availableCodes = locales.map(l => l.code);
123
+ const invalidLanguages = languages.filter(lang => !availableCodes.includes(lang));
124
+
125
+ if (invalidLanguages.length > 0) {
126
+ console.warn('Invalid languages detected:', invalidLanguages);
127
+ }
128
+
129
+ return invalidLanguages;
130
+ }),
131
+ catchError(error => {
132
+ console.error('Error validating languages:', error);
133
+ // Return all languages as invalid if validation fails
134
+ return of(languages);
135
+ })
136
+ );
137
+ } catch (error) {
138
+ return this.handleError(error, 'validateLanguages');
139
+ }
140
  }
141
 
142
  clearCache(): void {
143
  this.localesCache = undefined;
144
+ this.cacheTimestamp = undefined;
145
+ }
146
+
147
+ private handleError(error: any, operation: string): Observable<any> {
148
+ console.error(`LocaleManagerService.${operation} error:`, error);
149
+
150
+ // Handle authentication errors
151
+ if (error?.status === 401) {
152
+ this.authService.logout();
153
+ return throwError(() => ({
154
+ ...error,
155
+ message: 'Authentication required'
156
+ }));
157
+ }
158
+
159
+ // Handle race condition errors
160
+ if (error?.status === 409) {
161
+ return throwError(() => ({
162
+ ...error,
163
+ message: error.error?.message || 'Resource was modified by another user',
164
+ isRaceCondition: true
165
+ }));
166
+ }
167
+
168
+ // Handle network errors
169
+ if (error?.status === 0 || error?.name === 'TimeoutError') {
170
+ return throwError(() => ({
171
+ ...error,
172
+ message: 'Network connection error',
173
+ isNetworkError: true
174
+ }));
175
+ }
176
+
177
+ // For specific operations, provide fallback data
178
+ if (operation === 'getAvailableLocales' && !error?.status) {
179
+ // Fallback locales if API fails
180
+ const fallback = [
181
+ { code: 'tr-TR', name: 'Türkçe', english_name: 'Turkish' },
182
+ { code: 'en-US', name: 'English', english_name: 'English (US)' }
183
+ ];
184
+ this.localesCache = fallback;
185
+ this.cacheTimestamp = Date.now();
186
+ console.warn('Using fallback locales due to error');
187
+ return of(fallback);
188
+ }
189
+
190
+ // Default error handling
191
+ const errorMessage = error?.error?.message || error?.message || 'Unknown error occurred';
192
+ return throwError(() => ({
193
+ ...error,
194
+ message: errorMessage,
195
+ operation: operation,
196
+ timestamp: new Date().toISOString()
197
+ }));
198
+ }
199
+
200
+ // Helper method to check if cache is stale
201
+ isCacheStale(): boolean {
202
+ if (!this.cacheTimestamp) return true;
203
+ return Date.now() - this.cacheTimestamp > this.CACHE_DURATION;
204
+ }
205
+
206
+ // Force refresh locales
207
+ refreshLocales(): Observable<Locale[]> {
208
+ this.clearCache();
209
+ return this.getAvailableLocales();
210
  }
211
  }