Repository navigation
Added classes #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added classes #113
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,146 @@ | ||
| <app-page-header>Курсы валюты</app-page-header> | ||
|
|
||
| <div class="container my-5"> | ||
| <div class="container my-5" *ngIf="currencies; else dataLoading"> | ||
| <div class="card"> | ||
| <div class="card-body"> | ||
| <div> | ||
| <table class="table table-sm table-hover"> | ||
| <div class="card-body p-4"> | ||
| <div class="mb-3"> | ||
| <button class="btn btn-sm btn-primary" (click)="create()"> | ||
| Создать запись | ||
| </button> | ||
| </div> | ||
|
|
||
| <div | ||
| class="table-responsive mb-3" | ||
| *ngIf="currencies.length > 0; else nothingToShow" | ||
| > | ||
| <table class="table table-hover table-sm"> | ||
| <thead> | ||
| <tr> | ||
| <th>Валюта</th> | ||
| <th>Курс</th> | ||
| <th>Дата</th> | ||
| <tr class="small"> | ||
| <th>Дата публикации</th> | ||
| <th>Валюты (JSON)</th> | ||
| <th>Создано</th> | ||
| <th>Обновлено</th> | ||
| <th>Действия</th> | ||
| </tr> | ||
| </thead> | ||
| <tbody> | ||
| <tr *ngFor="let item of currencies" class="small"> | ||
| <td>{{ item.currencyString }}</td> | ||
| <td>{{ item.value }} kzt</td> | ||
| <td>{{ item.pubDate | date: "yyyy-MM-dd" }}</td> | ||
| <td>{{ item.currencyDate | date: "yyyy-MM-dd" }}</td> | ||
| <td> | ||
| <button | ||
| type="button" | ||
| class="btn-link-sm text-start" | ||
| (click)="showCurrenciesDetails(item)" | ||
| title="Нажмите для просмотра деталей" | ||
| > | ||
| <code>{{ item.currenciesShort }}</code> | ||
| </button> | ||
| </td> | ||
| <td>{{ item.createdAt | date: "yyyy-MM-dd HH:mm" }}</td> | ||
| <td>{{ item.updatedAt | date: "yyyy-MM-dd HH:mm" }}</td> | ||
| <td> | ||
| <button | ||
| type="button" | ||
| class="btn-link-sm btn-link-danger" | ||
| (click)="openDeleteDialog(item)" | ||
| > | ||
| Удалить | ||
| </button> | ||
| </td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| </div> | ||
|
|
||
| <div class="mt-4" *ngIf="source && source.results.length > 0"> | ||
| <app-pagination-buttons | ||
| [source]="source" | ||
| (pageChange)="loadData($event)" | ||
| ></app-pagination-buttons> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <app-confirm-dialog | ||
| *ngIf="confirmDeletionMessage" | ||
| [message]="confirmDeletionMessage" | ||
| ></app-confirm-dialog> | ||
|
|
||
| <app-dialog | ||
| [show]="!!editForm" | ||
| (closed)="onEditModalDlgClose()" | ||
| [header]="'Создать запись курса валюты'" | ||
| > | ||
| <form | ||
| class="mb-3" | ||
| *ngIf="!!editForm" | ||
| [formGroup]="editForm" | ||
| (ngSubmit)="onEditFormSubmit()" | ||
| > | ||
| <div class="mb-3"> | ||
| <label class="form-label">Валюта</label> | ||
| <select class="form-select" formControlName="currency"> | ||
| <option *ngFor="let option of currencyOptions" [ngValue]="option.value"> | ||
| {{ option.label }} | ||
| </option> | ||
| </select> | ||
| <app-field-error [field]="editForm.get('currency')"></app-field-error> | ||
| </div> | ||
|
|
||
| <div class="mb-3"> | ||
| <label class="form-label">Курс (в KZT)</label> | ||
| <input | ||
| type="number" | ||
| step="0.0001" | ||
| class="form-control" | ||
| formControlName="value" | ||
| placeholder="Например: 450.5" | ||
| /> | ||
| <app-field-error [field]="editForm.get('value')"></app-field-error> | ||
| </div> | ||
|
|
||
| <div class="mb-3"> | ||
| <label class="form-label">Дата публикации</label> | ||
| <input type="date" class="form-control" formControlName="pubDate" /> | ||
| <app-field-error [field]="editForm.get('pubDate')"></app-field-error> | ||
| </div> | ||
|
|
||
| <div class="mb-3"> | ||
| <button class="btn btn-primary" type="submit">Сохранить</button> | ||
| </div> | ||
| </form> | ||
| </app-dialog> | ||
|
|
||
| <!-- Modal for viewing currencies JSON --> | ||
| <app-dialog | ||
| [show]="!!selectedCurrencyItem" | ||
| (closed)="closeCurrenciesDetails()" | ||
| [header]="'Данные о курсах валют'" | ||
| additionalCss="modal-lg" | ||
| > | ||
| <div *ngIf="selectedCurrencyItem"> | ||
| <div class="mb-3"> | ||
| <strong>Дата:</strong> | ||
| {{ selectedCurrencyItem.currencyDate | date: "yyyy-MM-dd" }} | ||
| </div> | ||
| <div class="mb-3"> | ||
| <strong>Данные валют (JSON):</strong> | ||
| <pre class="bg-light p-3 rounded mt-2 currencies-json">{{ | ||
| selectedCurrencyItem.currencies | json | ||
| }}</pre> | ||
| </div> | ||
| </div> | ||
| </app-dialog> | ||
|
|
||
| <ng-template #dataLoading> | ||
| <div class="container py-5"> | ||
| <app-data-loader></app-data-loader> | ||
| </div> | ||
| </ng-template> | ||
|
|
||
| <ng-template #nothingToShow> | ||
| <div class="text-center p-3 text-muted"> | ||
| Нет записей о курсах валют. Создайте первую запись! | ||
| </div> | ||
| </ng-template> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| .currencies-json { | ||
| max-height: 400px; | ||
| overflow-y: auto; | ||
| font-size: 0.85rem; | ||
| white-space: pre-wrap; | ||
| word-break: break-all; | ||
| } | ||
|
|
||
| code { | ||
| font-size: 0.8rem; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,38 +1,133 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { Component, OnDestroy, OnInit } from "@angular/core"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { TitleService } from "@services/title.service"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { HealthCheckItem } from "../health-check-table/health-check-item"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { AdminToolsService } from "@services/admin-tools.service"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { untilDestroyed } from "@shared/subscriptions/until-destroyed"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { CurrencyItem } from "./currency-item"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { defaultPageParams } from "@models/page-params"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { PaginatedList } from "@models/paginated-list"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||
| CurrenciesCollectionService, | ||||||||||||||||||||||||||||||||||||||||||||||||
| CurrencyRecord, | ||||||||||||||||||||||||||||||||||||||||||||||||
| } from "@services/currencies-collection.service"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { DialogMessage } from "@shared/components/dialogs/models/dialog-message"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { ConfirmMsg } from "@shared/components/dialogs/models/confirm-msg"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { AlertService } from "@shared/components/alert/services/alert.service"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { CurrencyRecordEditForm } from "./currency-record-edit-form"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { CurrencyType } from "@services/admin-tools.service"; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| @Component({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| templateUrl: "./currencies-page.component.html", | ||||||||||||||||||||||||||||||||||||||||||||||||
| styleUrls: ["./currencies-page.component.scss"], | ||||||||||||||||||||||||||||||||||||||||||||||||
| standalone: false, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
| export class CurrenciesPageComponent implements OnInit, OnDestroy { | ||||||||||||||||||||||||||||||||||||||||||||||||
| authorizationToken: string | null = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| configs: string | null = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| healthCheckItems: Array<HealthCheckItem> = []; | ||||||||||||||||||||||||||||||||||||||||||||||||
| currencies: Array<CurrencyItem> = []; | ||||||||||||||||||||||||||||||||||||||||||||||||
| currencies: Array<CurrencyItem> | null = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| source: PaginatedList<CurrencyRecord> | null = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| currentPage: number = 1; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| confirmDeletionMessage: DialogMessage<ConfirmMsg> | null = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| editForm: CurrencyRecordEditForm | null = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // For viewing currencies JSON | ||||||||||||||||||||||||||||||||||||||||||||||||
| selectedCurrencyItem: CurrencyItem | null = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Currency options for select box | ||||||||||||||||||||||||||||||||||||||||||||||||
| readonly currencyOptions = [ | ||||||||||||||||||||||||||||||||||||||||||||||||
| { value: CurrencyType.USD, label: "USD" }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { value: CurrencyType.EUR, label: "EUR" }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { value: CurrencyType.RUB, label: "RUB" }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { value: CurrencyType.KGS, label: "KGS" }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { value: CurrencyType.SAR, label: "SAR" }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { value: CurrencyType.AED, label: "AED" }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { value: CurrencyType.CAD, label: "CAD" }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| constructor( | ||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly titleService: TitleService, | ||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly adminToolsService: AdminToolsService, | ||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly currenciesService: CurrenciesCollectionService, | ||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly alert: AlertService, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.titleService.setTitle("Курсы валют"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ngOnInit(): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.adminToolsService | ||||||||||||||||||||||||||||||||||||||||||||||||
| .getCurrencies() | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.currencies = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.source = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.loadData(this.currentPage); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| loadData(pageToRequest: number): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.currencies = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.source = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.currentPage = pageToRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| this.currenciesService | ||||||||||||||||||||||||||||||||||||||||||||||||
| .getAll({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| page: this.currentPage, | ||||||||||||||||||||||||||||||||||||||||||||||||
| pageSize: defaultPageParams.pageSize, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .pipe(untilDestroyed(this)) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .subscribe((currencies) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.currencies = currencies.map((x) => new CurrencyItem(x)); | ||||||||||||||||||||||||||||||||||||||||||||||||
| .subscribe((response) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.currencies = response.results.map((x) => new CurrencyItem(x)); | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.source = response; | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ngOnDestroy(): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.titleService.resetTitle(); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| create(): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.editForm = new CurrencyRecordEditForm(); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| onEditFormSubmit(): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (this.editForm == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const createRequest = this.editForm.createRequestOrNull(); | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (createRequest == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| this.currenciesService | ||||||||||||||||||||||||||||||||||||||||||||||||
| .create(createRequest) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .pipe(untilDestroyed(this)) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .subscribe(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.alert.success("Запись о курсе валюты была создана"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.editForm = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.loadData(this.currentPage); | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+93
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling to the create subscription. The create subscription lacks an error handler. If the API call fails, the user receives no feedback and the form remains open with no indication of the failure. 🔎 Suggested fix this.currenciesService
.create(createRequest)
.pipe(untilDestroyed(this))
- .subscribe(() => {
- this.alert.success("Запись о курсе валюты была создана");
- this.editForm = null;
- this.loadData(this.currentPage);
+ .subscribe({
+ next: () => {
+ this.alert.success("Запись о курсе валюты была создана");
+ this.editForm = null;
+ this.loadData(this.currentPage);
+ },
+ error: (err) => {
+ this.alert.error("Не удалось создать запись. Попробуйте позже.");
+ console.error("Failed to create currency record:", err);
+ }
});As per coding guidelines for Angular components and proper error handling. 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| onEditModalDlgClose(): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.editForm = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| openDeleteDialog(item: CurrencyItem): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.confirmDeletionMessage = new DialogMessage( | ||||||||||||||||||||||||||||||||||||||||||||||||
| new ConfirmMsg( | ||||||||||||||||||||||||||||||||||||||||||||||||
| "Удалить запись", | ||||||||||||||||||||||||||||||||||||||||||||||||
| `Вы уверены, что хотите удалить запись от ${new Date(item.currencyDate).toLocaleDateString()}?`, | ||||||||||||||||||||||||||||||||||||||||||||||||
| () => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.currenciesService | ||||||||||||||||||||||||||||||||||||||||||||||||
| .delete(item.id) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .pipe(untilDestroyed(this)) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .subscribe(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.alert.success("Запись была удалена"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.confirmDeletionMessage = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.loadData(this.currentPage); | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+113
to
+120
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling to the delete subscription. The delete subscription lacks an error handler. If the API call fails, the user receives no feedback and the confirmation dialog may remain open. 🔎 Suggested fix this.currenciesService
.delete(item.id)
.pipe(untilDestroyed(this))
- .subscribe(() => {
- this.alert.success("Запись была удалена");
- this.confirmDeletionMessage = null;
- this.loadData(this.currentPage);
+ .subscribe({
+ next: () => {
+ this.alert.success("Запись была удалена");
+ this.confirmDeletionMessage = null;
+ this.loadData(this.currentPage);
+ },
+ error: (err) => {
+ this.alert.error("Не удалось удалить запись. Попробуйте позже.");
+ this.confirmDeletionMessage = null;
+ console.error("Failed to delete currency record:", err);
+ }
});As per coding guidelines for Angular components and proper error handling. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| showCurrenciesDetails(item: CurrencyItem): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.selectedCurrencyItem = item; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| closeCurrenciesDetails(): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.selectedCurrencyItem = null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling to the subscription.
The
loadDatasubscription lacks an error handler. If the API call fails, the user receives no feedback and the loading state may persist indefinitely.🔎 Suggested fix
this.currenciesService .getAll({ page: this.currentPage, pageSize: defaultPageParams.pageSize, }) .pipe(untilDestroyed(this)) - .subscribe((response) => { - this.currencies = response.results.map((x) => new CurrencyItem(x)); - this.source = response; + .subscribe({ + next: (response) => { + this.currencies = response.results.map((x) => new CurrencyItem(x)); + this.source = response; + }, + error: (err) => { + this.alert.error("Не удалось загрузить данные. Попробуйте позже."); + this.currencies = []; + console.error("Failed to load currencies:", err); + } });As per coding guidelines for Angular components and proper error handling.
🤖 Prompt for AI Agents