ciyidogan commited on
Commit
5a72500
·
verified ·
1 Parent(s): b74fc10

Update flare-ui/src/app/dialogs/project-edit-dialog/project-edit-dialog.component.ts

Browse files
flare-ui/src/app/dialogs/project-edit-dialog/project-edit-dialog.component.ts CHANGED
@@ -1,4 +1,4 @@
1
- // project-edit-dialog.component.ts (TÜMÜ) - Template inline olarak
2
  import { Component, Inject, OnInit } from '@angular/core';
3
  import { CommonModule } from '@angular/common';
4
  import { FormBuilder, FormGroup, Validators, ReactiveFormsModule, FormArray } from '@angular/forms';
@@ -12,7 +12,9 @@ import { MatIconModule } from '@angular/material/icon';
12
  import { MatChipsModule } from '@angular/material/chips';
13
  import { MatDividerModule } from '@angular/material/divider';
14
  import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
 
15
  import { ApiService } from '../../services/api.service';
 
16
 
17
  export interface ProjectDialogData {
18
  mode: 'create' | 'edit';
@@ -34,7 +36,8 @@ export interface ProjectDialogData {
34
  MatIconModule,
35
  MatChipsModule,
36
  MatDividerModule,
37
- MatSnackBarModule
 
38
  ],
39
  template: `
40
  <h2 mat-dialog-title>{{ data.mode === 'create' ? 'Create New Project' : 'Edit Project' }}</h2>
@@ -75,22 +78,54 @@ export interface ProjectDialogData {
75
  <textarea matInput formControlName="description" rows="3"></textarea>
76
  </mat-form-field>
77
 
 
78
  <mat-form-field appearance="outline" class="full-width">
79
  <mat-label>Default Language</mat-label>
80
- <mat-select formControlName="defaultLanguage">
81
- @for (lang of languages; track lang.code) {
82
- <mat-option [value]="lang.code">{{ lang.name }}</mat-option>
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
  </mat-select>
 
 
85
  </mat-form-field>
86
 
 
87
  <mat-form-field appearance="outline" class="full-width">
88
  <mat-label>Supported Languages</mat-label>
89
- <mat-select formControlName="supportedLanguages" multiple>
90
- @for (lang of languages; track lang.code) {
91
- <mat-option [value]="lang.code">{{ lang.name }}</mat-option>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
93
  </mat-select>
 
 
94
  </mat-form-field>
95
 
96
  <mat-form-field appearance="outline" class="full-width">
@@ -123,14 +158,11 @@ export interface ProjectDialogData {
123
  export default class ProjectEditDialogComponent implements OnInit {
124
  form!: FormGroup;
125
  saving = false;
 
 
 
126
  projectIcons = ['folder', 'work', 'shopping_cart', 'school', 'local_hospital', 'restaurant', 'home', 'business'];
127
- languages = [
128
- { code: 'tr', name: 'Turkish' },
129
- { code: 'en', name: 'English' },
130
- { code: 'de', name: 'German' },
131
- { code: 'fr', name: 'French' },
132
- { code: 'es', name: 'Spanish' }
133
- ];
134
  timezones = [
135
  'Europe/Istanbul',
136
  'Europe/London',
@@ -143,6 +175,7 @@ export default class ProjectEditDialogComponent implements OnInit {
143
  constructor(
144
  private fb: FormBuilder,
145
  private apiService: ApiService,
 
146
  private snackBar: MatSnackBar,
147
  public dialogRef: MatDialogRef<ProjectEditDialogComponent>,
148
  @Inject(MAT_DIALOG_DATA) public data: ProjectDialogData
@@ -150,40 +183,119 @@ export default class ProjectEditDialogComponent implements OnInit {
150
 
151
  ngOnInit() {
152
  this.initializeForm();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
- if (this.data.mode === 'edit' && this.data.project) {
 
155
  this.form.patchValue({
156
- name: this.data.project.name,
157
- caption: this.data.project.caption || '',
158
- icon: this.data.project.icon || 'folder',
159
- description: this.data.project.description || '',
160
- defaultLanguage: this.data.project.default_language || 'tr',
161
- supportedLanguages: this.data.project.supported_languages || ['tr'],
162
- timezone: this.data.project.timezone || 'Europe/Istanbul',
163
- region: this.data.project.region || 'tr-TR'
164
  });
165
-
166
- // Rebuild test users form array
167
- const testUsersArray = this.form.get('testUsers') as FormArray;
168
- testUsersArray.clear();
169
- (this.data.project.test_users || []).forEach((phoneNumber: string) => {
170
- testUsersArray.push(this.fb.control(phoneNumber, Validators.required));
 
 
 
 
 
171
  });
172
  }
173
  }
174
 
175
- initializeForm() {
176
- this.form = this.fb.group({
177
- name: ['', [Validators.required, Validators.pattern(/^[a-z0-9_]+$/)]],
178
- caption: ['', Validators.required],
179
- icon: ['folder'],
180
- description: [''],
181
- defaultLanguage: ['tr'],
182
- supportedLanguages: [['tr']],
183
- timezone: ['Europe/Istanbul'],
184
- region: ['tr-TR']
185
- // testUsers kaldırıldı
186
- });
187
  }
188
 
189
  async save() {
@@ -194,10 +306,10 @@ export default class ProjectEditDialogComponent implements OnInit {
194
 
195
  this.saving = true;
196
  try {
197
- const formValue = this.form.value;
198
 
199
- // Base project data
200
- const baseProjectData = {
201
  name: formValue.name,
202
  caption: formValue.caption,
203
  icon: formValue.icon,
@@ -210,40 +322,36 @@ export default class ProjectEditDialogComponent implements OnInit {
210
 
211
  let result;
212
  if (this.data.mode === 'create') {
213
- result = await this.apiService.createProject(baseProjectData).toPromise();
214
- this.showMessage('Project created successfully!', false);
215
  } else {
216
- // Edit mode için ek alanlarla birlikte gönder
217
- const updateProjectData = {
218
- ...baseProjectData,
219
- id: this.data.project.id,
220
- last_update_date: this.data.project.last_update_date
221
  };
222
-
223
- result = await this.apiService.updateProject(this.data.project.id, updateProjectData).toPromise();
224
- this.showMessage('Project updated successfully!', false);
225
  }
226
-
227
  this.dialogRef.close(result);
228
  } catch (error: any) {
229
- if (error.status === 409) {
230
- this.showMessage('This record was modified by another user. Please reload and try again.', true);
231
- } else {
232
- this.showMessage(error.error?.detail || 'Operation failed', true);
233
- }
234
  } finally {
235
  this.saving = false;
236
  }
237
  }
238
-
239
- private showMessage(message: string, isError: boolean) {
240
- this.snackBar.open(message, 'Close', {
241
- duration: isError ? 5000 : 3000,
242
- panelClass: isError ? 'error-snackbar' : 'success-snackbar'
243
- });
244
- }
245
 
246
  close() {
247
  this.dialogRef.close();
248
  }
 
 
 
 
 
 
 
 
 
249
  }
 
1
+ // project-edit-dialog.component.ts
2
  import { Component, Inject, OnInit } from '@angular/core';
3
  import { CommonModule } from '@angular/common';
4
  import { FormBuilder, FormGroup, Validators, ReactiveFormsModule, FormArray } from '@angular/forms';
 
12
  import { MatChipsModule } from '@angular/material/chips';
13
  import { MatDividerModule } from '@angular/material/divider';
14
  import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
15
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
16
  import { ApiService } from '../../services/api.service';
17
+ import { LocaleManagerService, Locale } from '../../services/locale-manager.service';
18
 
19
  export interface ProjectDialogData {
20
  mode: 'create' | 'edit';
 
36
  MatIconModule,
37
  MatChipsModule,
38
  MatDividerModule,
39
+ MatSnackBarModule,
40
+ MatProgressSpinnerModule
41
  ],
42
  template: `
43
  <h2 mat-dialog-title>{{ data.mode === 'create' ? 'Create New Project' : 'Edit Project' }}</h2>
 
78
  <textarea matInput formControlName="description" rows="3"></textarea>
79
  </mat-form-field>
80
 
81
+ <!-- Default Language -->
82
  <mat-form-field appearance="outline" class="full-width">
83
  <mat-label>Default Language</mat-label>
84
+ <mat-select
85
+ formControlName="defaultLanguage"
86
+ (selectionChange)="onDefaultLanguageChange()"
87
+ [disabled]="loadingLocales">
88
+ @if (loadingLocales) {
89
+ <mat-option disabled>
90
+ <mat-spinner diameter="20"></mat-spinner>
91
+ Loading languages...
92
+ </mat-option>
93
+ }
94
+ @for (locale of availableLocales; track locale.code) {
95
+ <mat-option [value]="locale.code">
96
+ {{ locale.name }}
97
+ <span class="locale-code">{{ locale.code }}</span>
98
+ </mat-option>
99
  }
100
  </mat-select>
101
+ <mat-icon matPrefix>translate</mat-icon>
102
+ <mat-hint>Primary language for this project</mat-hint>
103
  </mat-form-field>
104
 
105
+ <!-- Supported Languages -->
106
  <mat-form-field appearance="outline" class="full-width">
107
  <mat-label>Supported Languages</mat-label>
108
+ <mat-select
109
+ formControlName="supportedLanguages"
110
+ (selectionChange)="onSupportedLanguagesChange()"
111
+ [disabled]="loadingLocales"
112
+ multiple>
113
+ <mat-select-trigger>
114
+ <div class="selected-languages">
115
+ @for (lang of form.get('supportedLanguages')?.value || []; track lang; let last = $last) {
116
+ <span>{{ getLocaleName(lang) }}@if (!last) {, }</span>
117
+ }
118
+ </div>
119
+ </mat-select-trigger>
120
+ @for (locale of availableLocales; track locale.code) {
121
+ <mat-option [value]="locale.code">
122
+ {{ locale.name }}
123
+ <span class="locale-code">{{ locale.code }}</span>
124
+ </mat-option>
125
  }
126
  </mat-select>
127
+ <mat-icon matPrefix>language</mat-icon>
128
+ <mat-hint>Languages available in this project</mat-hint>
129
  </mat-form-field>
130
 
131
  <mat-form-field appearance="outline" class="full-width">
 
158
  export default class ProjectEditDialogComponent implements OnInit {
159
  form!: FormGroup;
160
  saving = false;
161
+ loadingLocales = true;
162
+ availableLocales: Locale[] = [];
163
+
164
  projectIcons = ['folder', 'work', 'shopping_cart', 'school', 'local_hospital', 'restaurant', 'home', 'business'];
165
+
 
 
 
 
 
 
166
  timezones = [
167
  'Europe/Istanbul',
168
  'Europe/London',
 
175
  constructor(
176
  private fb: FormBuilder,
177
  private apiService: ApiService,
178
+ private localeManager: LocaleManagerService,
179
  private snackBar: MatSnackBar,
180
  public dialogRef: MatDialogRef<ProjectEditDialogComponent>,
181
  @Inject(MAT_DIALOG_DATA) public data: ProjectDialogData
 
183
 
184
  ngOnInit() {
185
  this.initializeForm();
186
+ this.loadAvailableLocales();
187
+ }
188
+
189
+ initializeForm() {
190
+ const defaultValues = this.data.mode === 'edit' && this.data.project ? {
191
+ name: this.data.project.name,
192
+ caption: this.data.project.caption || '',
193
+ icon: this.data.project.icon || 'folder',
194
+ description: this.data.project.description || '',
195
+ defaultLanguage: this.data.project.default_language || 'tr-TR',
196
+ supportedLanguages: this.data.project.supported_languages || ['tr-TR'],
197
+ timezone: this.data.project.timezone || 'Europe/Istanbul',
198
+ region: this.data.project.region || 'tr-TR'
199
+ } : {
200
+ name: '',
201
+ caption: '',
202
+ icon: 'folder',
203
+ description: '',
204
+ defaultLanguage: 'tr-TR',
205
+ supportedLanguages: ['tr-TR'],
206
+ timezone: 'Europe/Istanbul',
207
+ region: 'tr-TR'
208
+ };
209
+
210
+ this.form = this.fb.group({
211
+ name: [defaultValues.name, [Validators.required, Validators.pattern(/^[a-z0-9_]+$/)]],
212
+ caption: [defaultValues.caption, Validators.required],
213
+ icon: [defaultValues.icon],
214
+ description: [defaultValues.description],
215
+ defaultLanguage: [defaultValues.defaultLanguage],
216
+ supportedLanguages: [defaultValues.supportedLanguages],
217
+ timezone: [defaultValues.timezone],
218
+ region: [defaultValues.region]
219
+ });
220
+
221
+ // Disable name field in edit mode
222
+ if (this.data.mode === 'edit') {
223
+ this.form.get('name')?.disable();
224
+ }
225
+ }
226
+
227
+ loadAvailableLocales() {
228
+ this.loadingLocales = true;
229
+ this.localeManager.getAvailableLocales().subscribe({
230
+ next: (locales) => {
231
+ this.availableLocales = locales;
232
+ this.loadingLocales = false;
233
+ this.validateSelectedLanguages();
234
+ },
235
+ error: (err) => {
236
+ this.showMessage('Failed to load available languages', 'error');
237
+ this.loadingLocales = false;
238
+ // Use fallback locales
239
+ this.availableLocales = [
240
+ { code: 'tr-TR', name: 'Türkçe', english_name: 'Turkish' },
241
+ { code: 'en-US', name: 'English', english_name: 'English (US)' }
242
+ ];
243
+ }
244
+ });
245
+ }
246
+
247
+ validateSelectedLanguages() {
248
+ const availableCodes = this.availableLocales.map(l => l.code);
249
+ const currentSupported = this.form.get('supportedLanguages')?.value || [];
250
+ const currentDefault = this.form.get('defaultLanguage')?.value;
251
+
252
+ // Filter out any unsupported languages
253
+ const validSupported = currentSupported.filter((lang: string) =>
254
+ availableCodes.includes(lang)
255
+ );
256
+
257
+ // Update form if any languages were removed
258
+ if (validSupported.length !== currentSupported.length) {
259
+ this.form.patchValue({ supportedLanguages: validSupported });
260
+ }
261
+
262
+ // Ensure default language is valid
263
+ if (!availableCodes.includes(currentDefault)) {
264
+ const newDefault = availableCodes[0] || 'tr-TR';
265
+ this.form.patchValue({
266
+ defaultLanguage: newDefault,
267
+ supportedLanguages: [...validSupported, newDefault]
268
+ });
269
+ }
270
+ }
271
+
272
+ onDefaultLanguageChange() {
273
+ const defaultLang = this.form.get('defaultLanguage')?.value;
274
+ const supportedLangs = this.form.get('supportedLanguages')?.value || [];
275
 
276
+ // Ensure default language is in supported languages
277
+ if (defaultLang && !supportedLangs.includes(defaultLang)) {
278
  this.form.patchValue({
279
+ supportedLanguages: [...supportedLangs, defaultLang]
 
 
 
 
 
 
 
280
  });
281
+ }
282
+ }
283
+
284
+ onSupportedLanguagesChange() {
285
+ const defaultLang = this.form.get('defaultLanguage')?.value;
286
+ const supportedLangs = this.form.get('supportedLanguages')?.value || [];
287
+
288
+ // If default language was removed, change default to first supported
289
+ if (defaultLang && !supportedLangs.includes(defaultLang)) {
290
+ this.form.patchValue({
291
+ defaultLanguage: supportedLangs[0] || 'tr-TR'
292
  });
293
  }
294
  }
295
 
296
+ getLocaleName(code: string): string {
297
+ const locale = this.availableLocales.find(l => l.code === code);
298
+ return locale ? locale.name : code;
 
 
 
 
 
 
 
 
 
299
  }
300
 
301
  async save() {
 
306
 
307
  this.saving = true;
308
  try {
309
+ const formValue = this.form.getRawValue(); // getRawValue to include disabled fields
310
 
311
+ // Project data format matching backend expectations
312
+ const projectData = {
313
  name: formValue.name,
314
  caption: formValue.caption,
315
  icon: formValue.icon,
 
322
 
323
  let result;
324
  if (this.data.mode === 'create') {
325
+ result = await this.apiService.createProject(projectData).toPromise();
326
+ this.showMessage('Project created successfully!');
327
  } else {
328
+ // Add last_update_date for edit mode
329
+ const updateData = {
330
+ ...projectData,
331
+ last_update_date: this.data.project.last_update_date || ''
 
332
  };
333
+ result = await this.apiService.updateProject(this.data.project.id, updateData).toPromise();
334
+ this.showMessage('Project updated successfully!');
 
335
  }
336
+
337
  this.dialogRef.close(result);
338
  } catch (error: any) {
339
+ this.showMessage(error.error?.detail || 'Operation failed', 'error');
 
 
 
 
340
  } finally {
341
  this.saving = false;
342
  }
343
  }
 
 
 
 
 
 
 
344
 
345
  close() {
346
  this.dialogRef.close();
347
  }
348
+
349
+ private showMessage(message: string, type: 'success' | 'error' = 'success') {
350
+ this.snackBar.open(message, 'Close', {
351
+ duration: 5000,
352
+ panelClass: type === 'error' ? 'error-snackbar' : 'success-snackbar',
353
+ horizontalPosition: 'right',
354
+ verticalPosition: 'top'
355
+ });
356
+ }
357
  }