Consolidated commit message to v22 signals
This commit is contained in:
@@ -1,135 +1,421 @@
|
||||
<h2>Recipe Detail</h2>
|
||||
<h2>Recipe Editor</h2>
|
||||
|
||||
<form [formGroup]="form" class="flex-col wrapped">
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Date</mat-label>
|
||||
<input matInput [matDatepicker]="date" formControlName="date" autocomplete="off" #dateElement />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Source</mat-label>
|
||||
<input type="text" matInput formControlName="source" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
@if (itemResource.isLoading()) {
|
||||
<app-skeleton-loader type="card" [count]="1" />
|
||||
<app-skeleton-loader type="line" [count]="10" />
|
||||
} @else if (itemResource.error()) {
|
||||
<app-error-state [message]="'Failed to load recipe detail.'" (retryAction)="itemResource.reload()" />
|
||||
} @else {
|
||||
<div class="section-nav row-container wrapped">
|
||||
<button mat-stroked-button (click)="go('basics')" [class.active]="selectedSection === 'basics'">Basics</button>
|
||||
<button mat-stroked-button (click)="go('ingredients')" [class.active]="selectedSection === 'ingredients'">
|
||||
Ingredients
|
||||
</button>
|
||||
<button mat-stroked-button (click)="go('steps')" [class.active]="selectedSection === 'steps'">Steps</button>
|
||||
<button mat-stroked-button (click)="go('photos')" [class.active]="selectedSection === 'photos'">Photos</button>
|
||||
<button mat-stroked-button (click)="go('notes')" [class.active]="selectedSection === 'notes'">Notes</button>
|
||||
<button mat-raised-button color="primary" (click)="go('preview')" [class.active]="selectedSection === 'preview'">
|
||||
Preview
|
||||
</button>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto basis-4-5">
|
||||
<mat-label>Product</mat-label>
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
#productElement
|
||||
[matAutocomplete]="autoP"
|
||||
formControlName="product"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-autocomplete
|
||||
#autoP="matAutocomplete"
|
||||
autoActiveFirstOption
|
||||
[displayWith]="displayProduct"
|
||||
(optionSelected)="productSelected($event)"
|
||||
>
|
||||
@for (product of products | async; track product) {
|
||||
<mat-option [value]="product">{{ product.name }}</mat-option>
|
||||
|
||||
<form class="flex-col wrapped" [formRoot]="form">
|
||||
@if (selectedSection === 'basics') {
|
||||
<div class="flex-col wrapped">
|
||||
<h3>Basics</h3>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Date</mat-label>
|
||||
<input matInput [matDatepicker]="date" [formField]="form.basics.date" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Source</mat-label>
|
||||
<input type="text" matInput [formField]="form.basics.source" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto basis-4-5">
|
||||
<mat-label>Dish / Product</mat-label>
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
#productElement
|
||||
[matAutocomplete]="autoP"
|
||||
[formField]="form.basics.product"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-autocomplete
|
||||
#autoP="matAutocomplete"
|
||||
autoActiveFirstOption
|
||||
[displayWith]="displayProduct"
|
||||
(optionSelected)="productSelected($event)"
|
||||
>
|
||||
@for (product of products(); track product) {
|
||||
<mat-option [value]="product">{{ product.name }}</mat-option>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="flex-auto basis-1-5">
|
||||
<mat-label>Yield</mat-label>
|
||||
<input type="text" matInput [formField]="form.basics.recipeYield" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (selectedSection === 'ingredients') {
|
||||
<div class="flex-col wrapped">
|
||||
<h3>Ingredients</h3>
|
||||
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto basis-2-5">
|
||||
<mat-label>Ingredient</mat-label>
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
#ingredientElement
|
||||
[matAutocomplete]="autoI"
|
||||
[formField]="form.addRow.ingredient"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-autocomplete #autoI="matAutocomplete" autoActiveFirstOption [displayWith]="displayIngredient">
|
||||
@for (product of ingredients(); track product) {
|
||||
<mat-option [value]="product">{{ product.name }} ({{ product.fractionUnits }})</mat-option>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="flex-auto basis-1-5">
|
||||
<mat-label>Quantity</mat-label>
|
||||
<input type="text" matInput [formField]="form.addRow.quantity" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="flex-auto basis-30">
|
||||
<mat-label>Description</mat-label>
|
||||
<input type="text" matInput [formField]="form.addRow.description" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
|
||||
<button mat-raised-button color="primary" type="button" (click)="addRow()" class="flex-auto basis-10">
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-table
|
||||
#table
|
||||
[dataSource]="form.ingredients().value() ?? []"
|
||||
matSort
|
||||
(matSortChange)="sortData($event)"
|
||||
aria-label="Ingredients"
|
||||
>
|
||||
<ng-container matColumnDef="product">
|
||||
<mat-header-cell *matHeaderCellDef>Product</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.product.name }} {{ row.description }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="quantity">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Quantity</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{ row.quantity | number: '1.2-2' }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="units">
|
||||
<mat-header-cell *matHeaderCellDef>Units</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.product.fractionUnits }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="center">
|
||||
<button mat-icon-button tabindex="-1" color="warn" type="button" (click)="deleteRow(row)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||
</mat-table>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (selectedSection === 'steps') {
|
||||
<div class="flex-col wrapped">
|
||||
<h3>Steps</h3>
|
||||
<p class="hint">Add steps and reorder them using ↑ / ↓. Keep titles short and chef-friendly.</p>
|
||||
|
||||
<div class="row-container">
|
||||
<button mat-raised-button color="primary" type="button" (click)="addStep()">
|
||||
<mat-icon>add</mat-icon>
|
||||
Add Step
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@for (step of form.steps; track step; let i = $index) {
|
||||
<div class="step-card">
|
||||
<div class="row-container space-between aligned">
|
||||
<div class="row-container aligned">
|
||||
<span class="step-number">Step {{ i + 1 }}</span>
|
||||
</div>
|
||||
<div class="row-container aligned">
|
||||
<button mat-icon-button type="button" (click)="moveStepUp(i)" [disabled]="i === 0">
|
||||
<mat-icon>arrow_upward</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
type="button"
|
||||
(click)="moveStepDown(i)"
|
||||
[disabled]="i === form.steps.length - 1"
|
||||
>
|
||||
<mat-icon>arrow_downward</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button type="button" color="warn" (click)="removeStep(i)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto basis-1-5">
|
||||
<mat-label>Phase</mat-label>
|
||||
<select matNativeControl [formField]="step.phase">
|
||||
@for (p of phases; track p) {
|
||||
<option [value]="p">{{ p }}</option>
|
||||
}
|
||||
</select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="flex-auto basis-3-5">
|
||||
<mat-label>Title</mat-label>
|
||||
<input matInput [formField]="step.title" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="flex-auto basis-1-5">
|
||||
<mat-label>Duration (min)</mat-label>
|
||||
<input matInput type="number" [formField]="step.durationMinutes" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Step Text</mat-label>
|
||||
<textarea matInput matAutosizeMinRows="3" [formField]="step.text"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Notes (optional)</mat-label>
|
||||
<textarea matInput matAutosizeMinRows="2" [formField]="step.notes"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-1-5">
|
||||
<mat-label>Yield</mat-label>
|
||||
<input type="text" matInput formControlName="recipeYield" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div formGroupName="addRow" class="row-container">
|
||||
<mat-form-field class="flex-auto basis-2-5">
|
||||
<mat-label>Ingredient</mat-label>
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
#ingredientElement
|
||||
[matAutocomplete]="autoI"
|
||||
formControlName="ingredient"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-autocomplete
|
||||
#autoI="matAutocomplete"
|
||||
autoActiveFirstOption
|
||||
[displayWith]="displayIngredient"
|
||||
(optionSelected)="ingredientSelected($event)"
|
||||
>
|
||||
@for (product of ingredients | async; track product) {
|
||||
<mat-option [value]="product">{{ product.name }} ({{ product.fractionUnits }})</mat-option>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (selectedSection === 'photos') {
|
||||
<div class="flex-col wrapped">
|
||||
<h3>Photos</h3>
|
||||
<div class="row-container aligned wrapped">
|
||||
<label class="file-btn">
|
||||
<input type="file" accept="image/*" multiple (change)="onPhotosSelected($event)" />
|
||||
<span>
|
||||
<mat-icon>upload</mat-icon>
|
||||
Add Photos
|
||||
</span>
|
||||
</label>
|
||||
<span class="hint">Captions are optional. Reorder with ↑ / ↓.</span>
|
||||
</div>
|
||||
|
||||
@if (form.photos.length === 0) {
|
||||
<p class="hint">No photos yet.</p>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-1-5">
|
||||
<mat-label>Quantity</mat-label>
|
||||
<input type="text" matInput formControlName="quantity" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-30">
|
||||
<mat-label>Description</mat-label>
|
||||
<input type="text" matInput formControlName="description" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
|
||||
<button mat-raised-button color="primary" (click)="addRow()" class="flex-auto basis-10">Add</button>
|
||||
</div>
|
||||
<mat-table #table [dataSource]="dataSource" matSort aria-label="Elements">
|
||||
<!-- Ingredient Column -->
|
||||
<ng-container matColumnDef="product">
|
||||
<mat-header-cell *matHeaderCellDef>Product</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.product.name }} {{ row.description }}</mat-cell>
|
||||
</ng-container>
|
||||
@for (p of form.photos; track p; let i = $index) {
|
||||
<div class="photo-card">
|
||||
<div class="row-container space-between aligned">
|
||||
<div class="row-container aligned">
|
||||
<img class="thumb" [src]="photoThumbSrc(formModel().photos[i])" alt="Recipe photo" />
|
||||
</div>
|
||||
<div class="row-container aligned">
|
||||
<button mat-icon-button type="button" (click)="movePhotoUp(i)" [disabled]="i === 0">
|
||||
<mat-icon>arrow_upward</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
type="button"
|
||||
(click)="movePhotoDown(i)"
|
||||
[disabled]="i === form.photos.length - 1"
|
||||
>
|
||||
<mat-icon>arrow_downward</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="warn" type="button" (click)="removePhoto(i)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Caption</mat-label>
|
||||
<input matInput [formField]="p.caption" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Quantity Column -->
|
||||
<ng-container matColumnDef="quantity">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Quantity</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{ row.quantity | number: '1.2-2' }}</mat-cell>
|
||||
</ng-container>
|
||||
@if (selectedSection === 'notes') {
|
||||
<div class="flex-col wrapped">
|
||||
<h3>Notes</h3>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Garnishing</mat-label>
|
||||
<textarea matInput matAutosizeMinRows="3" [formField]="form.notes.garnishing"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Plating</mat-label>
|
||||
<textarea matInput matAutosizeMinRows="3" [formField]="form.notes.plating"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Additional Notes</mat-label>
|
||||
<textarea matInput matAutosizeMinRows="4" [formField]="form.notes.notes"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Units Column -->
|
||||
<ng-container matColumnDef="units">
|
||||
<mat-header-cell *matHeaderCellDef>Units</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.product.fractionUnits }}</mat-cell>
|
||||
</ng-container>
|
||||
@if (selectedSection === 'preview') {
|
||||
<div class="flex-col wrapped">
|
||||
<div class="row-container space-between aligned">
|
||||
<h3>Preview</h3>
|
||||
<div class="row-container aligned">
|
||||
<button mat-stroked-button type="button" (click)="exportPdf()">
|
||||
<mat-icon>picture_as_pdf</mat-icon>
|
||||
Export PDF
|
||||
</button>
|
||||
<button mat-stroked-button type="button" (click)="print()">
|
||||
<mat-icon>print</mat-icon>
|
||||
Print
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Column -->
|
||||
<ng-container matColumnDef="action">
|
||||
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="center">
|
||||
<button mat-icon-button tabindex="-1" color="warn" (click)="deleteRow(row)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
<div class="recipe-print" #previewElement>
|
||||
<div class="recipe-print__header">
|
||||
<h1 class="recipe-print__title">{{ dishName }}</h1>
|
||||
<div class="recipe-print__meta">
|
||||
<span><strong>Date:</strong> {{ formModel().basics.date.format('DD-MMM-YYYY') }}</span>
|
||||
<span><strong>Source:</strong> {{ formModel().basics.source }}</span>
|
||||
<span>
|
||||
<strong>Yield:</strong>
|
||||
{{ yieldText }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||
</mat-table>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Instructions</mat-label>
|
||||
<textarea matInput matAutosizeMinRows="5" formControlName="instructions"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Garnishing</mat-label>
|
||||
<textarea matInput matAutosizeMinRows="5" formControlName="garnishing"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Plating</mat-label>
|
||||
<textarea matInput matAutosizeMinRows="5" formControlName="plating"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
<hr class="recipe-print__hr" />
|
||||
|
||||
<div class="row-container">
|
||||
<button mat-raised-button (click)="save()" color="primary" class="">
|
||||
{{ item.id ? 'Update' : 'Save' }}
|
||||
<section class="recipe-print__section">
|
||||
<h2>Ingredients</h2>
|
||||
<ul class="recipe-print__ingredients">
|
||||
@for (ing of formModel().ingredients; track ing) {
|
||||
<li>
|
||||
<div>
|
||||
<span class="name">{{ ing.product.name }}</span>
|
||||
@if (ing.description) {
|
||||
<span class="desc">— {{ ing.description }}</span>
|
||||
}
|
||||
</div>
|
||||
<span class="qty">{{ ing.quantity | number: '1.2-2' }} {{ ing.product.fractionUnits }}</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@if (formModel().steps.length > 0) {
|
||||
<section class="recipe-print__section">
|
||||
<h2>Steps</h2>
|
||||
<ol class="recipe-print__steps">
|
||||
@for (step of formModel().steps; track step; let i = $index) {
|
||||
<li class="recipe-print__step-item">
|
||||
<div class="recipe-print__step-header">
|
||||
Step {{ i + 1 }} - {{ step.phase }}: {{ step.title }}
|
||||
@if (step.durationMinutes) {
|
||||
({{ step.durationMinutes }} min)
|
||||
}
|
||||
</div>
|
||||
<p class="recipe-print__step-text">{{ step.text }}</p>
|
||||
@if (step.notes) {
|
||||
<p class="recipe-print__step-notes">Note: {{ step.notes }}</p>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ol>
|
||||
</section>
|
||||
}
|
||||
|
||||
@if (formModel().photos.length > 0) {
|
||||
<section class="recipe-print__section">
|
||||
<h2>Photos</h2>
|
||||
<div class="recipe-print__photos">
|
||||
@for (p of formModel().photos; track p; let i = $index) {
|
||||
<div class="recipe-print__photo-item">
|
||||
<img
|
||||
class="recipe-print__photo-img"
|
||||
[src]="photoThumbSrc(formModel().photos[i])"
|
||||
alt="Recipe photo"
|
||||
/>
|
||||
@if (p.caption) {
|
||||
<div class="recipe-print__photo-caption">{{ p.caption }}</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
@if (formModel().notes.garnishing || formModel().notes.plating || formModel().notes.notes) {
|
||||
<section class="recipe-print__section">
|
||||
<h2>Notes</h2>
|
||||
@if (formModel().notes.garnishing) {
|
||||
<div class="recipe-print__notes-block">
|
||||
<div class="recipe-print__notes-title">Garnishing</div>
|
||||
<p class="recipe-print__notes-text">{{ formModel().notes.garnishing }}</p>
|
||||
</div>
|
||||
}
|
||||
@if (formModel().notes.plating) {
|
||||
<div class="recipe-print__notes-block">
|
||||
<div class="recipe-print__notes-title">Plating</div>
|
||||
<p class="recipe-print__notes-text">{{ formModel().notes.plating }}</p>
|
||||
</div>
|
||||
}
|
||||
@if (formModel().notes.notes) {
|
||||
<div class="recipe-print__notes-block">
|
||||
<div class="recipe-print__notes-title">Additional Notes</div>
|
||||
<p class="recipe-print__notes-text">{{ formModel().notes.notes }}</p>
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</form>
|
||||
}
|
||||
|
||||
<div class="row-container aligned wrapped">
|
||||
<button mat-raised-button color="primary" (click)="save()">
|
||||
{{ id() ? 'Update' : 'Save' }}
|
||||
</button>
|
||||
@if (item.id) {
|
||||
<button mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
|
||||
@if (id()) {
|
||||
<button mat-raised-button type="button" color="warn" (click)="confirmDelete()">Delete</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user