Spaces:
Building
Building
import { Component, Inject, OnInit } from '@angular/core'; | |
import { CommonModule } from '@angular/common'; | |
import { FormBuilder, FormGroup, FormArray, Validators, ReactiveFormsModule } from '@angular/forms'; | |
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; | |
import { MatFormFieldModule } from '@angular/material/form-field'; | |
import { MatInputModule } from '@angular/material/input'; | |
import { MatButtonModule } from '@angular/material/button'; | |
import { MatIconModule } from '@angular/material/icon'; | |
import { MatListModule } from '@angular/material/list'; | |
import { MatChipsModule } from '@angular/material/chips'; | |
interface LocalizedCaption { | |
locale_code: string; | |
caption: string; | |
} | |
({ | |
selector: 'app-caption-dialog', | |
standalone: true, | |
imports: [ | |
CommonModule, | |
ReactiveFormsModule, | |
MatDialogModule, | |
MatFormFieldModule, | |
MatInputModule, | |
MatButtonModule, | |
MatIconModule, | |
MatListModule, | |
MatChipsModule | |
], | |
template: ` | |
<h2 mat-dialog-title>Manage Captions</h2> | |
<mat-dialog-content> | |
<p class="hint">Add captions for different languages. The default locale ({{ getLocaleName(data.defaultLocale) }}) is required.</p> | |
<form [formGroup]="form"> | |
<div formArrayName="captions" class="captions-list"> | |
<div *ngFor="let caption of captions.controls; let i = index" | |
[formGroupName]="i" | |
class="caption-row"> | |
<mat-chip-listbox class="locale-chip" [disabled]="true"> | |
<mat-chip-option [selected]="true"> | |
{{ getLocaleName(caption.get('locale_code')?.value) }} | |
</mat-chip-option> | |
</mat-chip-listbox> | |
<mat-form-field appearance="outline" class="caption-field"> | |
<mat-label>Caption</mat-label> | |
<input matInput formControlName="caption" | |
[placeholder]="'Caption in ' + getLocaleName(caption.get('locale_code')?.value)"> | |
<mat-error *ngIf="caption.get('caption')?.hasError('required')"> | |
Caption is required | |
</mat-error> | |
</mat-form-field> | |
<button mat-icon-button color="warn" | |
(click)="removeCaption(i)" | |
[disabled]="caption.get('locale_code')?.value === data.defaultLocale && captions.length === 1" | |
class="remove-button"> | |
<mat-icon>delete</mat-icon> | |
</button> | |
</div> | |
</div> | |
<div class="add-section" *ngIf="availableLocales.length > 0"> | |
<button mat-stroked-button (click)="addCaption()"> | |
<mat-icon>add</mat-icon> | |
Add Caption for Another Language | |
</button> | |
<mat-chip-listbox class="available-locales"> | |
<mat-chip-option *ngFor="let locale of availableLocales" | |
[value]="locale" | |
(click)="addCaptionForLocale(locale)"> | |
{{ getLocaleName(locale) }} | |
</mat-chip-option> | |
</mat-chip-listbox> | |
</div> | |
</form> | |
</mat-dialog-content> | |
<mat-dialog-actions align="end"> | |
<button mat-button (click)="cancel()">Cancel</button> | |
<button mat-raised-button color="primary" | |
(click)="save()" | |
[disabled]="!form.valid"> | |
Save | |
</button> | |
</mat-dialog-actions> | |
`, | |
styles: [` | |
mat-dialog-content { | |
min-width: 500px; | |
max-width: 600px; | |
} | |
.hint { | |
color: rgba(0, 0, 0, 0.6); | |
font-size: 14px; | |
margin-bottom: 16px; | |
} | |
.captions-list { | |
margin-bottom: 24px; | |
} | |
.caption-row { | |
display: flex; | |
align-items: flex-start; | |
gap: 16px; | |
margin-bottom: 16px; | |
} | |
.locale-chip { | |
flex: 0 0 120px; | |
margin-top: 8px; | |
} | |
.caption-field { | |
flex: 1; | |
} | |
.remove-button { | |
margin-top: 8px; | |
} | |
.add-section { | |
border-top: 1px solid #e0e0e0; | |
padding-top: 16px; | |
} | |
.available-locales { | |
margin-top: 16px; | |
} | |
`] | |
}) | |
export default class CaptionDialogComponent implements OnInit { | |
form!: FormGroup; | |
availableLocales: string[] = []; | |
constructor( | |
private fb: FormBuilder, | |
public dialogRef: MatDialogRef<CaptionDialogComponent>, | |
public data: { (MAT_DIALOG_DATA) | |
captions: LocalizedCaption[]; | |
supportedLocales: string[]; | |
defaultLocale: string; | |
} | |
) {} | |
ngOnInit() { | |
this.initializeForm(); | |
this.updateAvailableLocales(); | |
} | |
initializeForm() { | |
this.form = this.fb.group({ | |
captions: this.fb.array([]) | |
}); | |
// Add existing captions | |
if (this.data.captions && this.data.captions.length > 0) { | |
this.data.captions.forEach(caption => { | |
this.addCaptionFormGroup(caption); | |
}); | |
} else { | |
// Add default locale caption if no captions exist | |
this.addCaptionFormGroup({ | |
locale_code: this.data.defaultLocale, | |
caption: '' | |
}); | |
} | |
} | |
get captions() { | |
return this.form.get('captions') as FormArray; | |
} | |
addCaptionFormGroup(caption: LocalizedCaption) { | |
const group = this.fb.group({ | |
locale_code: [caption.locale_code, Validators.required], | |
caption: [caption.caption, Validators.required] | |
}); | |
this.captions.push(group); | |
} | |
addCaption() { | |
if (this.availableLocales.length > 0) { | |
this.addCaptionForLocale(this.availableLocales[0]); | |
} | |
} | |
addCaptionForLocale(locale: string) { | |
this.addCaptionFormGroup({ | |
locale_code: locale, | |
caption: '' | |
}); | |
this.updateAvailableLocales(); | |
} | |
removeCaption(index: number) { | |
this.captions.removeAt(index); | |
this.updateAvailableLocales(); | |
} | |
updateAvailableLocales() { | |
const usedLocales = this.captions.controls.map(c => c.get('locale_code')?.value); | |
this.availableLocales = this.data.supportedLocales.filter( | |
locale => !usedLocales.includes(locale) | |
); | |
} | |
getLocaleName(localeCode: string): string { | |
const localeNames: { [key: string]: string } = { | |
'tr': 'Türkçe', | |
'en': 'English', | |
'de': 'Deutsch', | |
'fr': 'Français', | |
'es': 'Español', | |
'ar': 'العربية', | |
'ru': 'Русский', | |
'zh': '中文', | |
'ja': '日本語', | |
'ko': '한국어' | |
}; | |
return localeNames[localeCode] || localeCode; | |
} | |
save() { | |
if (this.form.valid) { | |
this.dialogRef.close(this.form.value.captions); | |
} | |
} | |
cancel() { | |
this.dialogRef.close(); | |
} | |
} |