This commit is contained in:
2023-06-17 14:16:09 +03:00
parent 62178f1f32
commit 7ae5d3bc81
180 changed files with 12932 additions and 192 deletions
@@ -0,0 +1,30 @@
<section class="content">
<div class="content-block">
<div class="block-header">
<!-- breadcrumb -->
<app-breadcrumb [title]="'Blank'" [items]="['Home','Settings']" [active_item]="'Accounts'">
</app-breadcrumb>
</div>
<div class="row clearfix">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<mat-accordion class="main-headers-align" multi>
<mat-expansion-panel *ngFor="let account of accounts; let i = index" [expanded]="i === 0" >
<mat-expansion-panel-header>
<mat-panel-description>
<div>{{account.account.name}}</div>
<div>
{{account.rest}}
({{account.account.currencyId}})
</div>
</mat-panel-description>
</mat-expansion-panel-header>
<account-motion [motion]="newMotion">
</account-motion>
<account-motion *ngFor="let motion of motions" [motion]="motion">
</account-motion>
</mat-expansion-panel>
</mat-accordion>
</div>
</div>
</div>
</section>
@@ -0,0 +1,91 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
// libs
import Swal from 'sweetalert2';
import { MatDialog } from '@angular/material/dialog';
// app
import { AccountCategoryService } from '../../services/account.category.service';
import { ApiRoutes } from '../../api-routes';
import { AccountCategoryModel } from '../../model/account.category.model';
import { SettingsAccountAddComponent } from '../settings/account/add.account.component';
import { SettingsAccountEditComponent } from '../settings/account/edit.account.component';
import { AccountModel } from '../../model/account.model';
import { AccountDetailedModel } from '../../model/account.detailed.model';
import { AccountMotionModel } from '../../model/account.motion';
@Component({
templateUrl: './account.component.html',
styleUrls: ['./account.component.scss'],
})
export class AccountComponent {
public accounts?: AccountDetailedModel[];
public motions?: AccountMotionModel[];
public newMotion: AccountMotionModel;
constructor(
private httpClient: HttpClient,
private dialogModel: MatDialog,
private activatedRoute: ActivatedRoute
) {
this.newMotion = {
date: new Date(),
};
}
ngOnInit(): void {
this.activatedRoute.params.subscribe(params => {
this.httpClient
.get<AccountDetailedModel[]>(ApiRoutes.Accounts + "?category=" + params['id'])
.subscribe(data => {
this.accounts = data;
});
});
}
/*private loadAccounts() {
}*/
/*private loadCategories() {
this.accountCategoryService
.getCategories()
.subscribe(x => {
this.accountCategories = x;
this.loadAccounts();
});
}*/
/*public accountInCategory(category?: AccountCategoryModel) {
if (this.accounts) {
return this.accounts.filter(acc => (!category && (!acc.categories || acc.categories.length === 0)) || (category && acc.categories && acc.categories.filter(cat => cat.id === category.id).length > 0));
}
return null;
}*/
/*public add() {
this.dialogModel.open(SettingsAccountAddComponent, {
width: '640px',
disableClose: true,
data: this.accounts,
}).afterClosed().subscribe(x => {
if (x && x.refresh) {
this.loadAccounts();
}
});
}*/
/*public edit(account: AccountModel) {
this.dialogModel.open(SettingsAccountEditComponent, {
width: '640px',
disableClose: true,
data: account,
}).afterClosed().subscribe(x => {
if (x && x.refresh) {
this.loadAccounts();
}
});
}*/
}
@@ -0,0 +1,55 @@
<form [formGroup]="form!" (ngSubmit)="onSubmitClick()">
<div class="row">
<div class="col-md-4">
<div style="display: flex; align-items: center;">
<a href="javascript:void(0)" matSuffix (click)="addDay(-1)">
<i class="material-icons font-40">arrow_back</i>
</a>
<mat-form-field class="example-full-width" appearance="fill">
<input matInput [matDatepicker]="picker3" (focus)="picker3.open()" value={{motion.date}} formControlName="date" required>
<mat-hint>YYYY/MM/DD</mat-hint>
<mat-datepicker-toggle tabindex="-1" matSuffix [for]="picker3"></mat-datepicker-toggle>
<mat-datepicker #picker3></mat-datepicker>
<mat-error *ngIf="form.controls?.['date']?.hasError('required')">
Please enter rate date
</mat-error>
</mat-form-field>
<a href="javascript:void(0)" matSuffix (click)="addDay(1)">
<i class="material-icons font-40">arrow_forward</i>
</a>
</div>
</div>
<div class="col-md-4">
<mat-form-field class="example-full-width" appearance="fill">
<input matInput formControlName="motion">
</mat-form-field>
<mat-form-field class="example-full-width" appearance="fill">
<input matInput formControlName="description">
</mat-form-field>
</div>
<div class="col-md-2">
<mat-form-field class="example-full-width" appearance="fill">
<input matInput [value]="motion.plus | number:'0.2-2'" formControlName="plus" currencyMask [options]="{ prefix: '', precision: 4, inputMode: 1 }">
</mat-form-field>
<mat-form-field class="example-full-width" appearance="fill">
<input matInput [value]="motion.minus | number:'0.2-2'" formControlName="minus" currencyMask [options]="{ prefix: '', precision: 4, inputMode: 1 }">
</mat-form-field>
</div>
<div class="col-md-2 mb-2">
<a *ngIf="!motion.id" href="javascript:void(0)" (click)="onSubmitClick()">
<i class="material-icons font-40">add</i>
</a>
<a *ngIf="!motion.id" href="javascript:void(0)" (click)="onSubmitClick()">
<i class="material-icons font-40">import_export</i>
</a>
<a *ngIf="motion.id" href="javascript:void(0)" (click)="onSubmitClick()">
<i class="material-icons font-40">save</i>
</a>
<a *ngIf="motion.id" href="javascript:void(0)" (click)="onSubmitClick()">
<i class="material-icons font-40">delete</i>
</a>
</div>
</div>
</form>
@@ -0,0 +1,90 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { UntypedFormBuilder } from '@angular/forms';
import { Validators } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { Input } from '@angular/core';
import { Output } from '@angular/core';
import { EventEmitter } from '@angular/core';
// libs
import Swal from 'sweetalert2';
import { MatDialog } from '@angular/material/dialog';
import * as moment from 'moment';
// app
import { AccountCategoryService } from '../../services/account.category.service';
import { ApiRoutes } from '../../api-routes';
import { AccountCategoryModel } from '../../model/account.category.model';
import { SettingsAccountAddComponent } from '../settings/account/add.account.component';
import { SettingsAccountEditComponent } from '../settings/account/edit.account.component';
import { AccountModel } from '../../model/account.model';
import { AccountDetailedModel } from '../../model/account.detailed.model';
import { AccountMotionModel } from '../../model/account.motion';
import { atLeastOne } from '../../core/validators/atleastone.validator';
import { atLeastOneNumber } from '../../core/validators/atleastonenumber.validator';
@Component({
selector: 'account-motion',
templateUrl: './motion.component.html',
styleUrls: ['./motion.component.scss'],
})
export class MotionComponent {
public form!: UntypedFormGroup;
public errorMessage?: string;
@Input() motion!: AccountMotionModel;
constructor(
private fb: UntypedFormBuilder,
private httpClient: HttpClient,
private dialogModel: MatDialog,
private activatedRoute: ActivatedRoute
) {
}
ngOnInit(): void {
this.form = this.fb.group({
id: [
this.motion.id,
],
date: [
this.motion.date,
[Validators.required],
],
motion: [
this.motion.motion,
[Validators.required],
],
description: [
this.motion.description,
],
plus: [
this.motion.plus,
],
minus: [
this.motion.minus,
],
}, { validator: atLeastOneNumber(Validators.required, ['plus', 'minus']) });
}
onSubmitClick() {
if (this.form.valid) {
this.httpClient
.post<AccountMotionModel[]>(ApiRoutes.SettingsCurrencies, this.form.value)
.subscribe(response => {
}, error => {
this.errorMessage = error.detail;
});
}
}
addDay(days: number) {
var date = moment(this.form!.get('date')!.value).add(days, 'days').toDate();
this.form.patchValue({
date: date,
});
}
}
@@ -1,6 +1,12 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { UserProfileComponent } from './user-profile/user-profile.component';
import { SettingsCurrencyComponent } from './settings/currency/currency.component';
import { SettingsAccountCategoryComponent } from './settings/account/account.category.component';
import { SettingsAccountComponent } from './settings/account/account.component';
import { SettingsMotionCategoryComponent } from './settings/motion/motion.category.component';
import { SettingsMotionComponent } from './settings/motion/motion.component';
import { AccountComponent } from './accounts/account.component';
const routes: Routes = [
{
@@ -12,6 +18,30 @@ const routes: Routes = [
path: 'user/profile',
component: UserProfileComponent,
},
{
path: 'settings/currencies',
component: SettingsCurrencyComponent,
},
{
path: 'settings/account-categories',
component: SettingsAccountCategoryComponent,
},
{
path: 'settings/accounts',
component: SettingsAccountComponent,
},
{
path: 'settings/motion-categories',
component: SettingsMotionCategoryComponent,
},
{
path: 'settings/motions',
component: SettingsMotionComponent,
},
{
path: 'account-category/:id',
component: AccountComponent,
},
];
@NgModule({
+61 -2
View File
@@ -1,18 +1,63 @@
// angular
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { PagesRoutingModule } from './pages-routing.module';
import { UserProfileComponent } from './user-profile/user-profile.component';
import { ReactiveFormsModule } from '@angular/forms';
import { MAT_DATE_LOCALE } from '@angular/material/core';
// libs
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatTabsModule } from '@angular/material/tabs';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatCardModule } from '@angular/material/card';
import { NgxMaskModule } from 'ngx-mask';
import { NgxCurrencyModule } from "ngx-currency";
import { MatExpansionModule } from '@angular/material/expansion';
// app
import { PagesRoutingModule } from './pages-routing.module';
import { ComponentsModule } from '../shared/components/components.module';
import { SettingsCurrencyComponent } from './settings/currency/currency.component';
import { SettingsConnectCurrencyComponent } from './settings/currency/connect.currency.component';
import { UserProfileComponent } from './user-profile/user-profile.component';
import { SettingsRateCurrencyComponent } from './settings/currency/rate.currency.component';
import { SettingsAccountCategoryComponent } from './settings/account/account.category.component';
import { SettingsAccountComponent } from './settings/account/account.component';
import { SettingsAccountAddComponent } from './settings/account/add.account.component';
import { SettingsAccountEditComponent } from './settings/account/edit.account.component';
import { CurrencyService } from '../services/currency.service';
import { MotionService } from '../services/motion.service';
import { SettingsMotionCategoryComponent } from './settings/motion/motion.category.component';
import { SettingsMotionComponent } from './settings/motion/motion.component';
import { SettingsMotionEditComponent } from './settings/motion/edit.motion.component';
import { AccountComponent } from './accounts/account.component';
import { MotionComponent } from './accounts/motion.component';
@NgModule({
declarations: [
UserProfileComponent,
SettingsCurrencyComponent,
SettingsConnectCurrencyComponent,
SettingsRateCurrencyComponent,
SettingsAccountCategoryComponent,
SettingsAccountComponent,
SettingsAccountAddComponent,
SettingsAccountEditComponent,
SettingsMotionCategoryComponent,
SettingsMotionComponent,
SettingsMotionEditComponent,
AccountComponent,
MotionComponent,
],
imports: [
CommonModule,
@@ -21,9 +66,23 @@ import { ComponentsModule } from '../shared/components/components.module';
ReactiveFormsModule,
PagesRoutingModule,
MatFormFieldModule,
MatSelectModule,
MatInputModule,
MatIconModule,
MatButtonModule,
MatTabsModule,
MatDialogModule,
MatDatepickerModule,
MatGridListModule,
MatCardModule,
MatExpansionModule,
NgxMaskModule,
NgxCurrencyModule,
],
providers: [
{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
CurrencyService,
MotionService,
],
})
export class PagesModule {
@@ -0,0 +1,47 @@
<section class="content">
<div class="content-block">
<div class="block-header">
<!-- breadcrumb -->
<app-breadcrumb [title]="'Blank'" [items]="['Home','Settings']" [active_item]="'Account categories'">
</app-breadcrumb>
</div>
<div class="row clearfix">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<mat-card class="card">
<mat-card-header>
<mat-card-title-group>
<mat-card-title>
Account categories
</mat-card-title>
<mat-card-subtitle>
</mat-card-subtitle>
</mat-card-title-group>
<div fxFlex></div>
<button class="btn-space " (click)="add()" mat-raised-button color="primary">
Add
</button>
</mat-card-header>
<mat-card-content>
<div class="body table-responsive">
<table class="table">
<tbody>
<tr *ngFor="let item of categories">
<td>{{item.name}}</td>
<td>
<button class="btn-space" (click)="edit(item)" mat-raised-button color="primary">
Edit
</button>
<button class="btn-space" *ngIf="item.allowDelete" (click)="remove(item)" mat-raised-button color="primary">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
</section>
@@ -0,0 +1,122 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// libs
import Swal from 'sweetalert2';
// app
import { ApiRoutes } from '../../../api-routes';
import { AccountCategoryModel } from '../../../model/account.category.model';
@Component({
templateUrl: './account.category.component.html',
styleUrls: ['./account.category.component.scss'],
})
export class SettingsAccountCategoryComponent {
public categories?: AccountCategoryModel[];
constructor(
private httpClient: HttpClient,
) {
}
ngOnInit(): void {
this.load();
}
private load() {
this.httpClient
.get<AccountCategoryModel[]>(ApiRoutes.SettingsAccountCategories)
.subscribe(data => {
this.categories = data;
});
}
public add() {
Swal.fire({
title: 'Account category name',
input: 'text',
inputAttributes: {
autocapitalize: 'off',
},
showCancelButton: true,
confirmButtonText: 'Add',
showLoaderOnConfirm: true,
preConfirm: (name) => {
return new Promise((resolve, reject) => {
this.httpClient.post(ApiRoutes.SettingsAccountCategories, { name: name })
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error.detail);
reject();
});
}).catch(x => {
return false;
});
},
allowOutsideClick: () => !Swal.isLoading(),
}).then((result) => {
this.load();
});
}
public edit(category: AccountCategoryModel) {
Swal.fire({
title: 'Account category name',
input: 'text',
inputValue: category.name,
inputAttributes: {
autocapitalize: 'off',
},
showCancelButton: true,
confirmButtonText: 'Update',
showLoaderOnConfirm: true,
preConfirm: (name) => {
return new Promise((resolve, reject) => {
this.httpClient.put(ApiRoutes.SettingsAccountCategory.replace(':id', category.id!), { name: name })
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error.detail);
reject();
});
}).catch(x => {
return false;
});
},
allowOutsideClick: () => !Swal.isLoading(),
}).then((result) => {
this.load();
});
}
public remove(category: AccountCategoryModel) {
Swal.fire({
title: 'Remove account category ' + category.name,
showCancelButton: true,
confirmButtonText: 'Delete',
showLoaderOnConfirm: true,
preConfirm: (name) => {
return new Promise((resolve, reject) => {
this.httpClient.delete(ApiRoutes.SettingsAccountCategory.replace(':id', category.id!))
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error.detail);
reject();
});
}).catch(x => {
return false;
});
},
allowOutsideClick: () => !Swal.isLoading(),
}).then((result) => {
this.load();
});
}
}
@@ -0,0 +1,88 @@
<section class="content">
<div class="content-block">
<div class="block-header">
<!-- breadcrumb -->
<app-breadcrumb [title]="'Blank'" [items]="['Home','Settings']" [active_item]="'Accounts'">
</app-breadcrumb>
</div>
<div class="row clearfix">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<mat-card class="card">
<mat-card-header>
<mat-card-title-group>
<mat-card-title>
Accounts
</mat-card-title>
<mat-card-subtitle>
</mat-card-subtitle>
</mat-card-title-group>
<div fxFlex></div>
<button class="btn-space " (click)="add()" mat-raised-button color="primary">
Add
</button>
</mat-card-header>
<mat-card-content>
<div class="body table-responsive">
<mat-tab-group mat-stretch-tabs="false" mat-align-tabs="start">
<mat-tab *ngFor="let category of accountCategories" label="{{category.name}}">
<table class="table">
<tbody>
<tr *ngFor="let account of accountInCategory(category)">
<td>{{account.name}}</td>
<td>{{account.currencyId}}</td>
<td>
<button class="btn-space " (click)="edit(account)" mat-raised-button color="primary">
Edit
</button>
<button class="btn-space " (click)="remove(account)" mat-raised-button color="primary">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</mat-tab>
<mat-tab *ngIf="accountCategories && accounts" label="Without category">
<table class="table">
<tbody>
<tr *ngFor="let account of accountInCategory()">
<td>{{account.name}}</td>
<td>{{account.currencyId}}</td>
<td>
<button class="btn-space " (click)="edit(account)" mat-raised-button color="primary">
Edit
</button>
<button class="btn-space " (click)="remove(account)" mat-raised-button color="primary">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</mat-tab>
<mat-tab *ngIf="accountCategories && accounts" label="All">
<table class="table">
<tbody>
<tr *ngFor="let account of accounts">
<td>{{account.name}}</td>
<td>{{account.currencyId}}</td>
<td>
<button class="btn-space " (click)="edit(account)" mat-raised-button color="primary">
Edit
</button>
<button class="btn-space " (click)="remove(account)" mat-raised-button color="primary">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</mat-tab>
</mat-tab-group>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
</section>
@@ -0,0 +1,109 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// libs
import Swal from 'sweetalert2';
import { MatDialog } from '@angular/material/dialog';
// app
import { ApiRoutes } from '../../../api-routes';
import { AccountModel } from '../../../model/account.model';
import { AccountCategoryModel } from '../../../model/account.category.model';
import { SettingsAccountAddComponent } from './add.account.component';
import { SettingsAccountEditComponent } from './edit.account.component';
import { AccountCategoryService } from '../../../services/account.category.service';
@Component({
templateUrl: './account.component.html',
styleUrls: ['./account.component.scss'],
})
export class SettingsAccountComponent {
public accountCategories?: AccountCategoryModel[];
public accounts?: AccountModel[];
constructor(
private httpClient: HttpClient,
private dialogModel: MatDialog,
private accountCategoryService: AccountCategoryService,
) {
}
ngOnInit(): void {
this.loadCategories();
}
private loadAccounts() {
this.httpClient
.get<AccountModel[]>(ApiRoutes.SettingsAccounts)
.subscribe(data => {
this.accounts = data;
});
}
private loadCategories() {
this.accountCategoryService
.getCategories()
.subscribe(x => {
this.accountCategories = x;
this.loadAccounts();
});
}
public accountInCategory(category?: AccountCategoryModel) {
if (this.accounts) {
return this.accounts.filter(acc => (!category && (!acc.categories || acc.categories.length === 0)) || (category && acc.categories && acc.categories.filter(cat => cat.id === category.id).length > 0));
}
return null;
}
public add() {
this.dialogModel.open(SettingsAccountAddComponent, {
width: '640px',
disableClose: true,
data: this.accounts,
}).afterClosed().subscribe(x => {
if (x && x.refresh) {
this.loadAccounts();
}
});
}
public edit(account: AccountModel) {
this.dialogModel.open(SettingsAccountEditComponent, {
width: '640px',
disableClose: true,
data: account,
}).afterClosed().subscribe(x => {
if (x && x.refresh) {
this.loadAccounts();
}
});
}
public remove(category: AccountModel) {
/*Swal.fire({
title: 'Remove account category ' + category.name,
showCancelButton: true,
confirmButtonText: 'Add',
showLoaderOnConfirm: true,
preConfirm: (name) => {
return new Promise((resolve, reject) => {
this.httpClient.delete(ApiRoutes.SettingsAccountCategory.replace(':id', category.id!))
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error.detail);
reject();
});
}).catch(x => {
return false;
});
},
allowOutsideClick: () => !Swal.isLoading(),
}).then((result) => {
this.load();
});*/
}
}
@@ -0,0 +1,67 @@
<div>
<h2 mat-dialog-title>
Add account
</h2>
<div mat-dialog-content>
<form [formGroup]="editForm!" (ngSubmit)="onSubmitClick()">
<div class="row">
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Name</mat-label>
<input matInput value={{account.name}} formControlName="name">
</mat-form-field>
</div>
</div>
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Currency</mat-label>
<mat-select formControlName="currencyId">
<mat-option *ngFor="let currency of currencies" [value]="currency.code">
{{currency.code}} ({{currency.name}})
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Category</mat-label>
<mat-select formControlName="categoryId">
<mat-option *ngFor="let category of categories" [value]="category.id">
{{category.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>User</mat-label>
<input matInput value={{username}} readonly>
</mat-form-field>
</div>
</div>
</div>
<mat-dialog-actions class="mat-dialog-actions">
<div class="mat-dialog-left">
<div class="alert alert-danger mat-dialog-error" *ngIf="errorMessage">
{{errorMessage}}
</div>
</div>
<div class="mat-dialog-right">
<div class="button-bottom">
<button type="button" mat-button (click)="closeDialog()">Cancel</button>
<button class="btn-space" mat-raised-button color="primary">Save</button>
</div>
</div>
</mat-dialog-actions>
</form>
</div>
</div>
@@ -0,0 +1,90 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Inject } from '@angular/core';
import { UntypedFormBuilder } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { Validators } from '@angular/forms';
// libs
import Swal from 'sweetalert2';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
// app
import { ApiRoutes } from '../../../api-routes';
import { AccountModel } from '../../../model/account.model';
import { MatDialogRef } from '@angular/material/dialog';
import { CurrencyService } from '../../../services/currency.service';
import { CurrencyModel } from '../../../model/currency.model';
import { AccountCategoryService } from '../../../services/account.category.service';
import { AccountCategoryModel } from '../../../model/account.category.model';
import { AuthService } from '../../../core/service/auth.service';
@Component({
templateUrl: './add.account.component.html',
styleUrls: ['./add.account.component.scss'],
})
export class SettingsAccountAddComponent {
public editForm!: UntypedFormGroup;
public errorMessage?: string;
public currencies?: CurrencyModel[];
public categories?: AccountCategoryModel[];
public username: string;
constructor(
private fb: UntypedFormBuilder,
private httpClient: HttpClient,
private dialogRef: MatDialogRef<SettingsAccountAddComponent>,
private currencyService: CurrencyService,
private accountCategoryService: AccountCategoryService,
private authService: AuthService,
@Inject(MAT_DIALOG_DATA) public account: AccountModel
) {
this.username = authService.currentUserValue.userName;
}
ngOnInit(): void {
this.editForm = this.fb.group({
id: [
this.account.id,
],
name: [
this.account.name,
[Validators.required],
],
currencyId: [
this.account.currencyId,
[Validators.required],
],
categoryId: [
'',
[Validators.required],
],
});
this.currencyService
.getCurrencies()
.subscribe(x => this.currencies = x);
this.accountCategoryService
.getCategories()
.subscribe(x => this.categories = x);
}
closeDialog(): void {
this.dialogRef.close();
}
onSubmitClick() {
if (this.editForm.valid) {
this.errorMessage = undefined;
this.httpClient
.post<AccountModel>(ApiRoutes.SettingsAccounts, this.editForm.value)
.subscribe(response => {
this.dialogRef.close({ refresh: true });
}, error => {
this.errorMessage = error.detail;
});
}
}
}
@@ -0,0 +1,103 @@
<div>
<h2 mat-dialog-title>
Edit account
</h2>
<div mat-dialog-content>
<form [formGroup]="editForm!" (ngSubmit)="onSubmitClick()">
<div class="row">
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Name</mat-label>
<input matInput value={{account.name}} formControlName="name">
</mat-form-field>
</div>
</div>
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Currency</mat-label>
<mat-select formControlName="currencyId">
<mat-option *ngFor="let currency of currencies" [value]="currency.code">
{{currency.code}} ({{currency.name}})
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label>Categories</label>
<div class="col-md-12">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Category</mat-label>
<mat-select formControlName="categoryId">
<mat-option *ngFor="let category of categories" [value]="category.id">
{{category.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="col-md-12">
<table class="table">
<tbody>
<tr *ngFor="let category of account.categories">
<td>{{category.name}}</td>
<td>
<button class="btn-space" (click)="removeCategory(category)" mat-raised-button color="primary">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-6">
<label>Users</label>
<div class="col-md-12">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Category</mat-label>
<mat-select formControlName="categoryId">
<mat-option *ngFor="let category of categories" [value]="category.id">
{{category.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<table class="table">
<tbody>
<tr *ngFor="let accessRight of account.accessRights">
<td>{{accessRight.user.email}}</td>
<td>
<button class="btn-space" [disabled]="account.accessRights!.length <= 1" click="removeAccessRight(accessRight)" mat-raised-button color="primary">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<mat-dialog-actions class="mat-dialog-actions">
<div class="mat-dialog-left">
<div class="alert alert-danger mat-dialog-error" *ngIf="errorMessage">
{{errorMessage}}
</div>
</div>
<div class="mat-dialog-right">
<div class="button-bottom">
<button type="button" mat-button (click)="closeDialog()">Cancel</button>
<button class="btn-space" mat-raised-button color="primary">Save</button>
</div>
</div>
</mat-dialog-actions>
</form>
</div>
</div>
@@ -0,0 +1,104 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Inject } from '@angular/core';
import { UntypedFormBuilder } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { Validators } from '@angular/forms';
// libs
import Swal from 'sweetalert2';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
// app
import { ApiRoutes } from '../../../api-routes';
import { AccountModel } from '../../../model/account.model';
import { MatDialogRef } from '@angular/material/dialog';
import { CurrencyService } from '../../../services/currency.service';
import { CurrencyModel } from '../../../model/currency.model';
import { AccountCategoryService } from '../../../services/account.category.service';
import { AccountCategoryModel } from '../../../model/account.category.model';
import { AccountAccessRightModel } from '../../../model/account.accessRight.model';
@Component({
templateUrl: './edit.account.component.html',
styleUrls: ['./edit.account.component.scss'],
})
export class SettingsAccountEditComponent {
public editForm!: UntypedFormGroup;
public errorMessage?: string;
public currencies?: CurrencyModel[];
public categories?: AccountCategoryModel[];
constructor(
private fb: UntypedFormBuilder,
private httpClient: HttpClient,
private dialogRef: MatDialogRef<SettingsAccountEditComponent>,
private currencyService: CurrencyService,
private accountCategoryService: AccountCategoryService,
@Inject(MAT_DIALOG_DATA) public account: AccountModel
) {
}
ngOnInit(): void {
this.editForm = this.fb.group({
id: [
this.account.id,
],
name: [
this.account.name,
[Validators.required],
],
currencyId: [
this.account.currencyId,
[Validators.required],
],
categoryId: [
'',
],
});
this.currencyService
.getCurrencies()
.subscribe(x => this.currencies = x);
this.accountCategoryService
.getCategories()
.subscribe(x => this.categories = x);
}
removeCategory(category: AccountCategoryModel) {
var url = ApiRoutes.SettingsAccountAccountCategory
.replace(':id', this.account.id!)
.replace(':categoryId', category.id!);
this.httpClient
.delete(url)
.subscribe(response => {
this.dialogRef.close({ refresh: true });
}, error => {
this.errorMessage = error.detail;
});
}
removeAccessRight(accessRight: AccountAccessRightModel) {
}
closeDialog(): void {
this.dialogRef.close();
}
onSubmitClick() {
if (this.editForm.valid) {
this.errorMessage = undefined;
this.httpClient
.put<AccountModel>(ApiRoutes.SettingsAccount.replace(':id', this.account.id!), this.editForm.value)
.subscribe(response => {
this.dialogRef.close({ refresh: true });
}, error => {
this.errorMessage = error.detail;
});
}
}
}
@@ -0,0 +1,94 @@
<div>
<h2 mat-dialog-title>Add currency</h2>
<div mat-dialog-content>
<form [formGroup]="addForm!" (ngSubmit)="onSubmitClick()">
<div class="row">
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Symbol</mat-label>
<input matInput value={{currency.symbol}} formControlName="symbol" readonly="">
</mat-form-field>
</div>
</div>
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Code</mat-label>
<input matInput value={{currency.id}} formControlName="id" readonly="">
</mat-form-field>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Name</mat-label>
<input matInput value={{currency.name}} formControlName="name">
</mat-form-field>
</div>
</div>
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Short Name</mat-label>
<input matInput value={{currency.shortName}} formControlName="shortName">
</mat-form-field>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="text-inside">
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Rate</mat-label>
<input matInput [value]="currency.rate | number:'0.2-2'" formControlName="rate" currencyMask [options]="{ prefix: currency.symbol, precision: 4 }" required>
<mat-error *ngIf="addForm.controls?.['rate']?.hasError('required')">
Please enter rate
</mat-error>
</mat-form-field>
</div>
</div>
<div class="col-md-4">
<div class="text-inside">
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Quantity</mat-label>
<input matInput [value]="currency.rate | number:'0.0-0'" formControlName="quantity" currencyMask [options]="{ prefix: '', precision: 0 }" required>
<mat-error *ngIf="addForm.controls?.['rate']?.hasError('required')">
Please enter rate
</mat-error>
</mat-form-field>
</div>
</div>
<div class="col-md-4">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Rate Date</mat-label>
<input matInput [matDatepicker]="picker3" (focus)="picker3.open()" value={{currency.rateDate}} formControlName="rateDate" required>
<mat-hint>YYYY/MM/DD</mat-hint>
<mat-datepicker-toggle matSuffix [for]="picker3"></mat-datepicker-toggle>
<mat-datepicker #picker3></mat-datepicker>
<mat-error *ngIf="addForm.controls?.['rateDate']?.hasError('required')">
Please enter rate date
</mat-error>
</mat-form-field>
</div>
</div>
</div>
<mat-dialog-actions class="mat-dialog-actions">
<div class="mat-dialog-left">
<div class="alert alert-danger mat-dialog-error" *ngIf="errorMessage">
{{errorMessage}}
</div>
</div>
<div class="mat-dialog-right">
<div class="button-bottom">
<button type="button" mat-button (click)="closeDialog()">Cancel</button>
<button class="btn-space" mat-raised-button color="primary">Save</button>
</div>
</div>
</mat-dialog-actions>
</form>
</div>
</div>
@@ -0,0 +1,78 @@
// angular
import { Component } from '@angular/core';
import { Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { UntypedFormBuilder } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { Validators } from '@angular/forms';
// libs
import { MatDialogRef } from '@angular/material/dialog';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
// app
import { ApiRoutes } from '../../../api-routes';
import { CurrencyModel } from '../../../model/currency.model';
@Component({
templateUrl: './connect.currency.component.html',
styleUrls: ['./connect.currency.component.scss'],
})
export class SettingsConnectCurrencyComponent {
public addForm!: UntypedFormGroup;
public errorMessage?: string;
constructor(
private fb: UntypedFormBuilder,
private httpClient: HttpClient,
private dialogRef: MatDialogRef<SettingsConnectCurrencyComponent>,
@Inject(MAT_DIALOG_DATA) public currency: CurrencyModel
) {
}
public ngOnInit(): void {
this.addForm = this.fb.group({
id: [
this.currency.id,
],
symbol: [
this.currency.symbol,
],
name: [
this.currency.name,
],
shortName: [
this.currency.id,
],
quantity: [
this.currency.quantity || 1,
[Validators.required],
],
rate: [
this.currency.rate || 1,
[Validators.required],
],
rateDate: [
this.currency.rateDate,
[Validators.required],
],
});
}
closeDialog(): void {
this.dialogRef.close();
}
onSubmitClick() {
if (this.addForm.valid) {
this.errorMessage = undefined;
this.httpClient
.post<CurrencyModel[]>(ApiRoutes.SettingsCurrencies, this.addForm.value)
.subscribe(response => {
this.dialogRef.close({ refresh: true });
}, error => {
this.errorMessage = error.detail;
});
}
}
}
@@ -0,0 +1,73 @@
<section class="content">
<div class="content-block">
<div class="block-header">
<!-- breadcrumb -->
<app-breadcrumb [title]="'Blank'" [items]="['Home','Settings']" [active_item]="'Currency'">
</app-breadcrumb>
</div>
<div class="row clearfix">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="card">
<div class="header">
<h2><strong>My currencies</strong></h2>
</div>
<div class="body">
<mat-tab-group [(selectedIndex)]="tabIndex">
<mat-tab label="My currencies">
<div class="body table-responsive">
<table class="table">
<tbody>
<tr *ngFor="let item of myCurrencies">
<td>{{item.code}}</td>
<td>{{item.name}}</td>
<td style="text-align: end">
{{item.quantity}}
</td>
<td style="text-align: end">
{{item.rate | number: '1.2-6'}}
{{item.symbol}}
</td>
<td>{{item.rateDate | date:'yyyy-MM-dd'}}</td>
<td>
<button class="btn-space" (click)="setRate(item)" mat-raised-button color="primary">
Rate
</button>
</td>
</tr>
</tbody>
</table>
</div>
</mat-tab>
<mat-tab label="All currencies">
<div class="body table-responsive">
<table class="table">
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of currencies">
<td>{{item.symbol}}</td>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>
<button class="btn-space" (click)="connect(item)" [disabled]="item.isConnected" mat-raised-button color="primary">
Add
</button>
</td>
</tr>
</tbody>
</table>
</div>
</mat-tab>
</mat-tab-group>
</div>
</div>
</div>
</div>
</div>
</section>
@@ -0,0 +1,90 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// libs
import { MatDialog } from '@angular/material/dialog';
// app
import { ApiRoutes } from '../../../api-routes';
import { SettingsConnectCurrencyComponent } from './connect.currency.component';
import { CurrencyModel } from '../../../model/currency.model';
import { SettingsRateCurrencyComponent } from './rate.currency.component';
@Component({
templateUrl: './currency.component.html',
styleUrls: ['./currency.component.scss'],
})
export class SettingsCurrencyComponent {
public tabIndex = 0;
public currencies?: CurrencyModel[];
public myCurrencies?: CurrencyModel[];
constructor(
private httpClient: HttpClient,
private dialogModel: MatDialog
) {
}
ngOnInit(): void {
this.load();
}
connect(currency: CurrencyModel) {
this.dialogModel.open(SettingsConnectCurrencyComponent, {
width: '640px',
disableClose: true,
data: currency,
}).afterClosed().subscribe(x => {
if (x && x.refresh) {
this.tabIndex = 0;
this.loadMyCurrency();
}
});
}
disconnect(currency: CurrencyModel) {
}
setRate(currency: CurrencyModel) {
this.dialogModel.open(SettingsRateCurrencyComponent, {
width: '640px',
disableClose: true,
data: currency,
}).afterClosed().subscribe(x => {
if (x && x.refresh) {
this.loadMyCurrency();
}
});
}
private load() {
this.httpClient
.get<CurrencyModel[]>(ApiRoutes.GeneralCurrencies)
.subscribe(data => {
this.currencies = data;
this.loadMyCurrency();
});
}
private loadMyCurrency() {
this.httpClient
.get<CurrencyModel[]>(ApiRoutes.SettingsCurrencies)
.subscribe(data => {
this.myCurrencies = data.map(myCurrency => {
var globalCurrency = this.currencies?.find(x => x.id === myCurrency.code);
return ({
id: myCurrency.id,
code: myCurrency.code,
name: myCurrency.name,
quantity: myCurrency.quantity,
rate: myCurrency.rate,
rateDate: myCurrency.rateDate,
shortName: globalCurrency?.name,
symbol: globalCurrency?.symbol,
});
});
});
}
}
@@ -0,0 +1,84 @@
<div>
<h2 mat-dialog-title>Add currency</h2>
<div mat-dialog-content>
<form [formGroup]="addForm!" (ngSubmit)="onSubmitClick()">
<div class="row">
<div class="col-md-4">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Symbol</mat-label>
<input matInput value={{currency.symbol}} formControlName="symbol" readonly="">
</mat-form-field>
</div>
</div>
<div class="col-md-4">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Code</mat-label>
<input matInput value={{currency.code}} formControlName="code" readonly="">
</mat-form-field>
</div>
</div>
<div class="col-md-4">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Name</mat-label>
<input matInput value={{currency.name}} formControlName="name" readonly="">
</mat-form-field>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="text-inside">
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Rate</mat-label>
<input matInput [value]="currency.rate | number:'0.2-2'" formControlName="rate" currencyMask [options]="{ prefix: '', precision: 4, inputMode: 1 }" required>
<mat-error *ngIf="addForm.controls?.['rate']?.hasError('required')">
Please enter rate
</mat-error>
</mat-form-field>
</div>
</div>
<div class="col-md-4">
<div class="text-inside">
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Quantity</mat-label>
<input matInput [value]="currency.rate | number:'0.0-0'" formControlName="quantity" currencyMask [options]="{ prefix: '', precision: 0 }" required>
<mat-error *ngIf="addForm.controls?.['rate']?.hasError('required')">
Please enter rate
</mat-error>
</mat-form-field>
</div>
</div>
<div class="col-md-4">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Rate Date</mat-label>
<input matInput [matDatepicker]="picker3" (focus)="picker3.open()" value={{currency.rateDate}} formControlName="rateDate" required>
<mat-hint>YYYY/MM/DD</mat-hint>
<mat-datepicker-toggle matSuffix [for]="picker3"></mat-datepicker-toggle>
<mat-datepicker #picker3></mat-datepicker>
<mat-error *ngIf="addForm.controls?.['rateDate']?.hasError('required')">
Please enter rate date
</mat-error>
</mat-form-field>
</div>
</div>
</div>
<mat-dialog-actions class="mat-dialog-actions">
<div class="mat-dialog-left">
<div class="alert alert-danger mat-dialog-error" *ngIf="errorMessage">
{{errorMessage}}
</div>
</div>
<div class="mat-dialog-right">
<div class="button-bottom">
<button type="button" mat-button (click)="closeDialog()">Cancel</button>
<button class="btn-space" mat-raised-button color="primary">Save</button>
</div>
</div>
</mat-dialog-actions>
</form>
</div>
</div>
@@ -0,0 +1,79 @@
// angular
import { Component } from '@angular/core';
import { Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { UntypedFormBuilder } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { Validators } from '@angular/forms';
// libs
import { MatDialogRef } from '@angular/material/dialog';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { CurrencyMaskInputMode, NgxCurrencyModule } from "ngx-currency";
// app
import { ApiRoutes } from '../../../api-routes';
import { CurrencyModel } from '../../../model/currency.model';
@Component({
templateUrl: './rate.currency.component.html',
styleUrls: ['./rate.currency.component.scss'],
})
export class SettingsRateCurrencyComponent {
public addForm!: UntypedFormGroup;
public errorMessage?: string;
constructor(
private fb: UntypedFormBuilder,
private httpClient: HttpClient,
private dialogRef: MatDialogRef<SettingsRateCurrencyComponent>,
@Inject(MAT_DIALOG_DATA) public currency: CurrencyModel
) {
}
public ngOnInit(): void {
this.addForm = this.fb.group({
id: [
this.currency.id,
],
code: [
this.currency.code,
],
symbol: [
this.currency.symbol,
],
name: [
this.currency.name,
],
quantity: [
this.currency.quantity || 1,
[Validators.required],
],
rate: [
this.currency.rate || 1,
[Validators.required],
],
rateDate: [
this.currency.rateDate,
[Validators.required],
],
});
}
closeDialog(): void {
this.dialogRef.close();
}
onSubmitClick() {
if (this.addForm.valid) {
this.errorMessage = undefined;
this.httpClient
.post<CurrencyModel[]>(ApiRoutes.SettingsCurrenciesRate.replace(':id', this.addForm.value.id), this.addForm.value)
.subscribe(response => {
this.dialogRef.close({ refresh: true });
}, error => {
this.errorMessage = error.detail;
});
}
}
}
@@ -0,0 +1,45 @@
<div>
<h2 mat-dialog-title>
Edit motion
</h2>
<div mat-dialog-content>
<form [formGroup]="editForm!" (ngSubmit)="onSubmitClick()">
<div class="row">
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Name</mat-label>
<input matInput value={{motion.name}} formControlName="name" readonly>
</mat-form-field>
</div>
</div>
<div class="col-md-6">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Category</mat-label>
<mat-select formControlName="category">
<mat-option *ngFor="let category of categories" [value]="category.id">
{{category.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
<mat-dialog-actions class="mat-dialog-actions">
<div class="mat-dialog-left">
<div class="alert alert-danger mat-dialog-error" *ngIf="errorMessage">
{{errorMessage}}
</div>
</div>
<div class="mat-dialog-right">
<div class="button-bottom">
<button type="button" mat-button (click)="closeDialog()">Cancel</button>
<button class="btn-space" mat-raised-button color="primary">Save</button>
</div>
</div>
</mat-dialog-actions>
</form>
</div>
</div>
@@ -0,0 +1,74 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Inject } from '@angular/core';
import { UntypedFormBuilder } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { Validators } from '@angular/forms';
// libs
import Swal from 'sweetalert2';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
// app
import { ApiRoutes } from '../../../api-routes';
import { MatDialogRef } from '@angular/material/dialog';
import { AccountCategoryModel } from '../../../model/account.category.model';
import { MotionModel } from '../../../model/motion.model';
import { MotionService } from '../../../services/motion.service';
@Component({
templateUrl: './edit.motion.component.html',
styleUrls: ['./edit.motion.component.scss'],
})
export class SettingsMotionEditComponent {
public editForm!: UntypedFormGroup;
public errorMessage?: string;
public categories?: AccountCategoryModel[];
constructor(
private fb: UntypedFormBuilder,
private httpClient: HttpClient,
private dialogRef: MatDialogRef<SettingsMotionEditComponent>,
private motionService: MotionService,
@Inject(MAT_DIALOG_DATA) public motion: MotionModel
) {
}
ngOnInit(): void {
this.editForm = this.fb.group({
id: [
this.motion.id,
],
name: [
this.motion.name,
[Validators.required],
],
category: [
this.motion.categoryId,
[Validators.required],
],
});
this.motionService
.getCategories()
.subscribe(x => this.categories = x);
}
closeDialog(): void {
this.dialogRef.close();
}
onSubmitClick() {
if (this.editForm.valid) {
this.errorMessage = undefined;
this.httpClient
.put<MotionModel>(ApiRoutes.SettingsMotion.replace(':id', this.motion.id!), this.editForm.value)
.subscribe(response => {
this.dialogRef.close({ motion: response, refresh: true });
}, error => {
this.errorMessage = error.detail;
});
}
}
}
@@ -0,0 +1,47 @@
<section class="content">
<div class="content-block">
<div class="block-header">
<!-- breadcrumb -->
<app-breadcrumb [title]="'Blank'" [items]="['Home','Settings']" [active_item]="'Motion categories'">
</app-breadcrumb>
</div>
<div class="row clearfix">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<mat-card class="card">
<mat-card-header>
<mat-card-title-group>
<mat-card-title>
Motion categories
</mat-card-title>
<mat-card-subtitle>
</mat-card-subtitle>
</mat-card-title-group>
<div fxFlex></div>
<button class="btn-space " (click)="add()" mat-raised-button color="primary">
Add
</button>
</mat-card-header>
<mat-card-content>
<div class="body table-responsive">
<table class="table">
<tbody>
<tr *ngFor="let item of categories">
<td>{{item.name}}</td>
<td>
<button class="btn-space" (click)="edit(item)" mat-raised-button color="primary">
Edit
</button>
<button class="btn-space" *ngIf="item.allowDelete" (click)="remove(item)" mat-raised-button color="primary">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
</section>
@@ -0,0 +1,122 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// libs
import Swal from 'sweetalert2';
// app
import { ApiRoutes } from '../../../api-routes';
import { MotionCategoryModel } from '../../../model/motion.category.model';
@Component({
templateUrl: './motion.category.component.html',
styleUrls: ['./motion.category.component.scss'],
})
export class SettingsMotionCategoryComponent {
public categories?: MotionCategoryModel[];
constructor(
private httpClient: HttpClient,
) {
}
ngOnInit(): void {
this.load();
}
private load() {
this.httpClient
.get<MotionCategoryModel[]>(ApiRoutes.SettingsMotionCategories)
.subscribe(data => {
this.categories = data;
});
}
public add() {
Swal.fire({
title: 'Motion category name',
input: 'text',
inputAttributes: {
autocapitalize: 'off',
},
showCancelButton: true,
confirmButtonText: 'Add',
showLoaderOnConfirm: true,
preConfirm: (name) => {
return new Promise((resolve, reject) => {
this.httpClient.post(ApiRoutes.SettingsMotionCategories, { name: name })
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error.detail);
reject();
});
}).catch(x => {
return false;
});
},
allowOutsideClick: () => !Swal.isLoading(),
}).then((result) => {
this.load();
});
}
public edit(category: MotionCategoryModel) {
Swal.fire({
title: 'Motion category name',
input: 'text',
inputValue: category.name,
inputAttributes: {
autocapitalize: 'off',
},
showCancelButton: true,
confirmButtonText: 'Update',
showLoaderOnConfirm: true,
preConfirm: (name) => {
return new Promise((resolve, reject) => {
this.httpClient.put(ApiRoutes.SettingsMotionCategory.replace(':id', category.id!), { name: name })
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error.detail);
reject();
});
}).catch(x => {
return false;
});
},
allowOutsideClick: () => !Swal.isLoading(),
}).then((result) => {
this.load();
});
}
public remove(category: MotionCategoryModel) {
Swal.fire({
title: 'Remove motion category ' + category.name,
showCancelButton: true,
confirmButtonText: 'Delete',
showLoaderOnConfirm: true,
preConfirm: (name) => {
return new Promise((resolve, reject) => {
this.httpClient.delete(ApiRoutes.SettingsMotionCategory.replace(':id', category.id!))
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error.detail);
reject();
});
}).catch(x => {
return false;
});
},
allowOutsideClick: () => !Swal.isLoading(),
}).then((result) => {
this.load();
});
}
}
@@ -0,0 +1,54 @@
<section class="content">
<div class="content-block">
<div class="block-header">
<!-- breadcrumb -->
<app-breadcrumb [title]="'Blank'" [items]="['Home','Settings']" [active_item]="'Motions'">
</app-breadcrumb>
</div>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-3 col-lg-3">
<div class="card">
<div class="body">
<div id="mail-nav">
<ul class="" id="mail-folders">
<li *ngFor="let category of categories" [class.active]="selectedCategory && selectedCategory.id == category.id">
<a href="javascript:;" (click)="selectCategory(category)" title="{{category.name}}">{{category.name}}</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-9 col-lg-9">
<mat-card class="card">
<mat-card-header>
<mat-card-title-group>
<mat-card-title>
Motions
</mat-card-title>
<mat-card-subtitle>
</mat-card-subtitle>
</mat-card-title-group>
<div fxFlex></div>
</mat-card-header>
<mat-card-content>
<div class="body table-responsive">
<table class="table">
<tbody>
<tr *ngFor="let item of motions">
<td>{{item.name}}</td>
<td>
<button class="btn-space" (click)="edit(item)" mat-raised-button color="primary">
Edit
</button>
</td>
</tr>
</tbody>
</table>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
</section>
@@ -0,0 +1,98 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// libs
import Swal from 'sweetalert2';
import { MatDialog } from '@angular/material/dialog';
// app
import { ApiRoutes } from '../../../api-routes';
import { SettingsMotionEditComponent } from './edit.motion.component';
import { MotionService } from '../../../services/motion.service';
import { MotionModel } from '../../../model/motion.model';
import { MotionCategoryModel } from '../../../model/motion.category.model';
@Component({
templateUrl: './motion.component.html',
styleUrls: ['./motion.component.scss'],
})
export class SettingsMotionComponent {
public motions?: MotionModel[];
public categories?: MotionCategoryModel[];
public selectedCategory?: MotionCategoryModel;
constructor(
private dialogModel: MatDialog,
private httpClient: HttpClient,
private motionService: MotionService,
) {
}
ngOnInit(): void {
this.load();
}
private load(categoryId?: string) {
this.motionService.getCategories()
.subscribe(data => {
this.categories = data;
var selected = data[0];
if (categoryId) {
var categories = this.categories.filter(x => x.id === categoryId);
selected = categories.length === 0
? selected
: categories[0];
}
this.selectCategory(selected);
});
}
public selectCategory(category: MotionCategoryModel) {
this.selectedCategory = category;
this.motionService.getMotions(category.id)
.subscribe(data => {
this.motions = data;
});
}
public edit(motion: MotionModel) {
this.dialogModel.open(SettingsMotionEditComponent, {
width: '640px',
disableClose: true,
data: motion,
}).afterClosed().subscribe(x => {
if (x && x.refresh) {
console.log(x.motion.categoryId);
this.load(x.motion.categoryId);
}
});
}
public remove(category: MotionModel) {
Swal.fire({
title: 'Remove motion ' + category.name,
showCancelButton: true,
confirmButtonText: 'Delete',
showLoaderOnConfirm: true,
preConfirm: (name) => {
return new Promise((resolve, reject) => {
this.httpClient.delete(ApiRoutes.SettingsMotionCategory.replace(':id', category.id!))
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error.detail);
reject();
});
}).catch(x => {
return false;
});
},
allowOutsideClick: () => !Swal.isLoading(),
}).then((result) => {
this.load();
});
}
}
@@ -56,6 +56,19 @@
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 mb-2">
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Currency</mat-label>
<mat-select formControlName="currency">
<mat-option *ngFor="let item of currencies" [value]="item.id">
({{item.symbol}}) {{item.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 mb-2">
<button class="btn-space" [disabled]="!form.valid" mat-raised-button color="primary">
@@ -88,21 +101,21 @@
<div class="col-md-2">
<span class="fl-r" *ngIf="!provider.isConnected">
<button color="accent" class="btn-block mw-100-imp"
mat-raised-button
(click)="connect(provider)"
[disabled]="provider.isLoading"
[class.spinner]="provider.isLoading"
type="button">
mat-raised-button
(click)="connect(provider)"
[disabled]="provider.isLoading"
[class.spinner]="provider.isLoading"
type="button">
Connect
</button>
</span>
<span class="fl-r" *ngIf="provider.isConnected">
<button color="warn" class="btn-block mw-100-imp"
mat-raised-button
(click)="disconnect(provider.provider)"
[disabled]="provider.isLoading"
[class.spinner]="provider.isLoading"
type="button">
mat-raised-button
(click)="disconnect(provider.provider)"
[disabled]="provider.isLoading"
[class.spinner]="provider.isLoading"
type="button">
Disconect
</button>
</span>
@@ -22,6 +22,8 @@ import { AuthService } from '../../core/service/auth.service';
export class UserProfileComponent {
form: UntypedFormGroup;
providers?: ProviderModel[];
profile?: ProfileModel;
currencies?: CurrencyModel[];
constructor(
private fb: UntypedFormBuilder,
@@ -33,6 +35,7 @@ export class UserProfileComponent {
lastName: ['', [Validators.pattern('[a-zA-Z0-9]+')]],
fullName: ['', [Validators.pattern('[a-zA-Z0-9 ]+')]],
email: [{ value: '', disabled: true }, []],
currency: [{ value: '' }, []],
});
this.providers = ExternalLoginConfig
@@ -54,19 +57,36 @@ export class UserProfileComponent {
}
private load() {
this.httpClient.get<ProfileModel>(ApiRoutes.UserProfile).subscribe(data => {
this.updateForm(data);
this.loadProfile();
}
this.providers?.map((provider) => {
var attached = data.providers?.find(x => x.provider === provider.provider);
provider.isConnected = false;
provider.isEmailConfirmed = false;
if (attached) {
provider.isConnected = true;
provider.isEmailConfirmed = attached.isEmailConfirmed;
}
private loadProfile() {
this.httpClient
.get<ProfileModel>(ApiRoutes.UserProfile)
.subscribe(data => {
this.profile = data;
this.loadCurrencies();
this.updateForm(data);
this.providers?.map((provider) => {
var attached = data.providers?.find(x => x.provider === provider.provider);
provider.isConnected = false;
provider.isEmailConfirmed = false;
if (attached) {
provider.isConnected = true;
provider.isEmailConfirmed = attached.isEmailConfirmed;
}
});
});
}
private loadCurrencies() {
this.httpClient
.get<CurrencyModel[]>(ApiRoutes.GeneralCurrencies)
.subscribe(data => {
this.currencies = data;
});
});
}
onSubmit() {
@@ -134,6 +154,15 @@ interface ProfileModel {
firstName?: string,
lastName?: string,
fullName?: string,
currency?: string,
isEmailConfirmed?: boolean,
providers?: ProviderModel[],
}
interface CurrencyModel {
id?: string,
name?: string,
symbol?: string,
rate?: number,
rateDate?: string,
}