mirror of
https://github.com/FJurmanovic/wallet-web.git
synced 2026-02-06 06:08:10 +00:00
added transaction date to transaction form
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@github/catalyst": "^1.1.3",
|
"@github/catalyst": "^1.1.3",
|
||||||
|
"dayjs": "^1.10.5",
|
||||||
"lit-html": "^1.4.1",
|
"lit-html": "^1.4.1",
|
||||||
"validator": "^13.6.0"
|
"validator": "^13.6.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ class BaseElement extends HTMLElement {
|
|||||||
|
|
||||||
update = (): void => {
|
update = (): void => {
|
||||||
render(this.render(), this);
|
render(this.render(), this);
|
||||||
|
if (this.shadowRoot) {
|
||||||
|
const renderSlot = () => html`<slot><slot></slot></slot>`;
|
||||||
|
render(renderSlot(), this.shadowRoot);
|
||||||
|
}
|
||||||
this.bindEvents('data-action');
|
this.bindEvents('data-action');
|
||||||
this.bindEvents('app-action');
|
this.bindEvents('app-action');
|
||||||
this.updateCallback();
|
this.updateCallback();
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class Validator {
|
|||||||
.reverse()
|
.reverse()
|
||||||
.map((rule) => {
|
.map((rule) => {
|
||||||
let args = [];
|
let args = [];
|
||||||
|
let inps = [];
|
||||||
if (rule.includes('[') && rule.includes(']')) {
|
if (rule.includes('[') && rule.includes(']')) {
|
||||||
const begSep = rule.lastIndexOf('[');
|
const begSep = rule.lastIndexOf('[');
|
||||||
const endSep = rule.lastIndexOf(']');
|
const endSep = rule.lastIndexOf(']');
|
||||||
@@ -51,7 +52,7 @@ class Validator {
|
|||||||
const begBr = arg.lastIndexOf('(');
|
const begBr = arg.lastIndexOf('(');
|
||||||
const endBr = arg.lastIndexOf(')');
|
const endBr = arg.lastIndexOf(')');
|
||||||
const field = arg.slice(begBr + 1, endBr);
|
const field = arg.slice(begBr + 1, endBr);
|
||||||
|
inps = [...inps, this.form.getInput(field)];
|
||||||
return this.form?.values[field];
|
return this.form?.values[field];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -69,10 +70,19 @@ class Validator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
const error = ruleArray
|
let error = ruleArray
|
||||||
? validRule?.[1]?.replaceAll('{- name}', firstUpper(this.name?.toString()))
|
? validRule?.[1]?.replaceAll('{- name}', firstUpper(this.name?.toString()))
|
||||||
: validatorErrors[rule]?.replaceAll('{- name}', firstUpper(this.name?.toString()));
|
: validatorErrors[rule]?.replaceAll('{- name}', firstUpper(this.name?.toString()));
|
||||||
if (error) {
|
if (error) {
|
||||||
|
if (inps?.length > 1) {
|
||||||
|
inps.forEach((arg) => {
|
||||||
|
if (arg) {
|
||||||
|
error.replaceAll(`{- ${arg?.type}}`, firstUpper(arg?.name?.toString()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (inps?.length == 1) {
|
||||||
|
error = error.replaceAll('{- field}', firstUpper(inps[0]?.name?.toString()));
|
||||||
|
}
|
||||||
this.error = error;
|
this.error = error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class AppDropdownElement extends BaseComponentElement {
|
|||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
validate = (): boolean => {
|
validate = (change = false): boolean => {
|
||||||
return this.validator.validate();
|
return this.validator.validate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class AppFormElement extends BaseComponentElement {
|
|||||||
@querys inputField: NodeListOf<InputFieldElement>;
|
@querys inputField: NodeListOf<InputFieldElement>;
|
||||||
@querys appDropdown: NodeListOf<AppDropdownElement>;
|
@querys appDropdown: NodeListOf<AppDropdownElement>;
|
||||||
@attr custom: string;
|
@attr custom: string;
|
||||||
|
@attr renderInput: string;
|
||||||
@attr hasCancel: string;
|
@attr hasCancel: string;
|
||||||
slotted: any;
|
slotted: any;
|
||||||
isValid: boolean = false;
|
isValid: boolean = false;
|
||||||
@@ -24,6 +25,10 @@ class AppFormElement extends BaseComponentElement {
|
|||||||
return findMethod(this.custom, this.appMain);
|
return findMethod(this.custom, this.appMain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get customRender() {
|
||||||
|
return findMethod(this.renderInput, this.appMain);
|
||||||
|
}
|
||||||
|
|
||||||
public inputChange = (e) => {
|
public inputChange = (e) => {
|
||||||
this.validate();
|
this.validate();
|
||||||
this.update();
|
this.update();
|
||||||
@@ -103,13 +108,15 @@ class AppFormElement extends BaseComponentElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
elementConnected = (): void => {
|
elementConnected = (): void => {
|
||||||
const _template = document.createElement('template');
|
if (this.renderInput) {
|
||||||
const _slot = this.innerHTML;
|
this.update();
|
||||||
_template.innerHTML = _slot;
|
} else {
|
||||||
this.innerHTML = null;
|
const _template = document.createElement('template');
|
||||||
this.update();
|
const _slot = this.innerHTML;
|
||||||
|
_template.innerHTML = _slot;
|
||||||
this.formElement.replaceChild(_template.content, this.innerSlot);
|
this.update();
|
||||||
|
this.formElement?.replaceChild(_template.content, this.innerSlot);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render = (): TemplateResult => {
|
render = (): TemplateResult => {
|
||||||
@@ -139,7 +146,7 @@ class AppFormElement extends BaseComponentElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="app-form">
|
<div class="app-form">
|
||||||
<form app-action="submit:app-form#onSubmit" data-target="app-form.formElement">
|
<form app-action="submit:app-form#onSubmit" data-target="app-form.formElement">
|
||||||
<slot data-target="app-form.innerSlot"></slot>
|
${this.renderInput ? this.customRender() : html`<slot data-target="app-form.innerSlot"></slot>`}
|
||||||
${renderError(this.error)}
|
${renderError(this.error)}
|
||||||
<div class="form-buttons">
|
<div class="form-buttons">
|
||||||
<div class="button-content">${renderSubmit(this.isValid)}${renderCancel(isTrue(this.hasCancel))}</div>
|
<div class="button-content">${renderSubmit(this.isValid)}${renderCancel(isTrue(this.hasCancel))}</div>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class AppMainElement extends HTMLElement {
|
|||||||
public authStore: AuthStore;
|
public authStore: AuthStore;
|
||||||
private httpClient: HttpClient;
|
private httpClient: HttpClient;
|
||||||
public appService: AppService;
|
public appService: AppService;
|
||||||
public shadow: any;
|
//public shadow: any;
|
||||||
@target appModal: AppModalElement;
|
@target appModal: AppModalElement;
|
||||||
@target mainRoot: AppRootElement;
|
@target mainRoot: AppRootElement;
|
||||||
@target appLoader: AppLoaderElement;
|
@target appLoader: AppLoaderElement;
|
||||||
|
|||||||
@@ -13,12 +13,14 @@ class InputFieldElement extends BaseComponentElement {
|
|||||||
@attr type: string;
|
@attr type: string;
|
||||||
@attr label: string;
|
@attr label: string;
|
||||||
@attr rules: string;
|
@attr rules: string;
|
||||||
|
@attr customAction: string;
|
||||||
@target main: HTMLElement;
|
@target main: HTMLElement;
|
||||||
@target inp: HTMLElement;
|
@target inp: HTMLElement;
|
||||||
@closest appForm: AppFormElement;
|
@closest appForm: AppFormElement;
|
||||||
valid: boolean;
|
valid: boolean;
|
||||||
displayError: boolean;
|
displayError: boolean;
|
||||||
randId: string;
|
randId: string;
|
||||||
|
changed: boolean = false;
|
||||||
|
|
||||||
validator: Validator;
|
validator: Validator;
|
||||||
|
|
||||||
@@ -54,7 +56,15 @@ class InputFieldElement extends BaseComponentElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate = (): boolean => {
|
validate = (): boolean => {
|
||||||
return this.validator.validate();
|
const valid = this.validator.validate();
|
||||||
|
if (valid && this.displayError) {
|
||||||
|
this.displayError = false;
|
||||||
|
this.update();
|
||||||
|
} else if (this.changed && !valid) {
|
||||||
|
this.displayError = true;
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
validateDisplay = () => {
|
validateDisplay = () => {
|
||||||
@@ -69,6 +79,9 @@ class InputFieldElement extends BaseComponentElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inputChange = (e) => {
|
inputChange = (e) => {
|
||||||
|
if (!this.changed && e?.target?.value) {
|
||||||
|
this.changed = true;
|
||||||
|
}
|
||||||
this.validate();
|
this.validate();
|
||||||
this.appForm?.inputChange(e);
|
this.appForm?.inputChange(e);
|
||||||
};
|
};
|
||||||
@@ -96,6 +109,7 @@ class InputFieldElement extends BaseComponentElement {
|
|||||||
app-action="
|
app-action="
|
||||||
input:input-field#inputChange
|
input:input-field#inputChange
|
||||||
blur:input-field#validateDisplay
|
blur:input-field#validateDisplay
|
||||||
|
${this.customAction ? this.customAction : ''}
|
||||||
"
|
"
|
||||||
/>`;
|
/>`;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import isEmail from 'validator/lib/isEmail';
|
import isEmail from 'validator/lib/isEmail';
|
||||||
import isDate from 'validator/lib/isDate';
|
import isDate from 'validator/lib/isDate';
|
||||||
import isNumeric from 'validator/lib/isNumeric';
|
import isNumeric from 'validator/lib/isNumeric';
|
||||||
|
import isAfter from 'validator/lib/isAfter';
|
||||||
import matches from 'validator/lib/matches';
|
import matches from 'validator/lib/matches';
|
||||||
|
|
||||||
const validator = {
|
const validator = {
|
||||||
@@ -10,6 +11,7 @@ const validator = {
|
|||||||
matches: matches,
|
matches: matches,
|
||||||
is_same: [isSame, '{- name} needs to be same to {- field}.'],
|
is_same: [isSame, '{- name} needs to be same to {- field}.'],
|
||||||
required: [required, '{- name} is required.'],
|
required: [required, '{- name} is required.'],
|
||||||
|
is_after: [isAfter, '{- name} needs to be after {- field}.'],
|
||||||
};
|
};
|
||||||
|
|
||||||
function required(str: string): boolean {
|
function required(str: string): boolean {
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ class SubscriptionCreateElement extends BasePageElement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
get hasEndCheck(): InputFieldElement | AppDropdownElement {
|
||||||
|
for (const i in this.inputs) {
|
||||||
|
if (this.inputs[i]?.name == 'hasEnd') {
|
||||||
|
return this.inputs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get nameInput(): InputFieldElement | AppDropdownElement {
|
get nameInput(): InputFieldElement | AppDropdownElement {
|
||||||
for (const i in this.inputs) {
|
for (const i in this.inputs) {
|
||||||
if (this.inputs[i]?.name == 'name') {
|
if (this.inputs[i]?.name == 'name') {
|
||||||
@@ -148,10 +156,16 @@ class SubscriptionCreateElement extends BasePageElement {
|
|||||||
return _return;
|
return _return;
|
||||||
}
|
}
|
||||||
|
|
||||||
render = (): TemplateResult => {
|
onCheck = () => {
|
||||||
const renderInput = (type, name, label, rules, hide?) => {
|
this.appForm.update();
|
||||||
|
this.appForm.validate();
|
||||||
|
this.appForm.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
renderForms = () => {
|
||||||
|
const renderInput = (type, name, label, rules, hide?, customAction?) => {
|
||||||
if (hide) {
|
if (hide) {
|
||||||
return html``;
|
return null;
|
||||||
}
|
}
|
||||||
return html`<input-field
|
return html`<input-field
|
||||||
data-type="${type}"
|
data-type="${type}"
|
||||||
@@ -159,6 +173,7 @@ class SubscriptionCreateElement extends BasePageElement {
|
|||||||
data-label="${label}"
|
data-label="${label}"
|
||||||
data-targets="subscription-create.inputs"
|
data-targets="subscription-create.inputs"
|
||||||
data-rules="${rules}"
|
data-rules="${rules}"
|
||||||
|
data-custom-action="${customAction || ''}"
|
||||||
></input-field>`;
|
></input-field>`;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -174,26 +189,41 @@ class SubscriptionCreateElement extends BasePageElement {
|
|||||||
data-fetch="${fetch}"
|
data-fetch="${fetch}"
|
||||||
></app-dropdown>`;
|
></app-dropdown>`;
|
||||||
};
|
};
|
||||||
|
return html`
|
||||||
|
<div slot="inputs">
|
||||||
|
${renderInput('number', 'amount', 'Amount', 'required')}
|
||||||
|
${renderInput('text', 'description', 'Description', 'required')}
|
||||||
|
${renderInput('date', 'startDate', 'Start date', 'required')}
|
||||||
|
${renderInput('checkbox', 'hasEnd', 'Existing End Date', '', false, 'change:subscription-create#onCheck')}
|
||||||
|
${renderInput(
|
||||||
|
'date',
|
||||||
|
'endDate',
|
||||||
|
'End date',
|
||||||
|
'required|is_after[field(startDate)]',
|
||||||
|
!(this.hasEndCheck?.inp as HTMLInputElement)?.checked
|
||||||
|
)}
|
||||||
|
${renderDropdown(
|
||||||
|
'subscription-create#getWallets',
|
||||||
|
'wallet',
|
||||||
|
'Wallet',
|
||||||
|
'required',
|
||||||
|
this.walletData && this.walletData.walletId
|
||||||
|
)}
|
||||||
|
${renderDropdown('subscription-create#getTypes', 'transactionType', 'Transaction Type', 'required')}
|
||||||
|
${renderInput('number', 'customRange', 'Every', 'required')}
|
||||||
|
${renderDropdown('subscription-create#getSubs', 'subscriptionType', 'Subscription Type', 'required')}
|
||||||
|
${this.errorMessage ? html`<div>${this.errorMessage}</div>` : html``}</template
|
||||||
|
>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
render = (): TemplateResult => {
|
||||||
return html`
|
return html`
|
||||||
<app-form
|
<app-form
|
||||||
data-custom="subscription-create#onSubmit"
|
data-custom="subscription-create#onSubmit"
|
||||||
data-has-cancel="true"
|
data-has-cancel="true"
|
||||||
data-target="subscription-create.appForm"
|
data-target="subscription-create.appForm"
|
||||||
|
data-render-input="subscription-create#renderForms"
|
||||||
>
|
>
|
||||||
${renderInput('number', 'amount', 'Amount', 'required')}
|
|
||||||
${renderInput('text', 'description', 'Description', 'required')}
|
|
||||||
${renderDropdown(
|
|
||||||
'subscription-create#getWallets',
|
|
||||||
'wallet',
|
|
||||||
'Wallet',
|
|
||||||
'required',
|
|
||||||
this.walletData && this.walletData.walletId
|
|
||||||
)}
|
|
||||||
${renderDropdown('subscription-create#getTypes', 'transactionType', 'Transaction Type', 'required')}
|
|
||||||
${renderInput('number', 'customRange', 'Every', 'required')}
|
|
||||||
${renderDropdown('subscription-create#getSubs', 'subscriptionType', 'Subscription Type', 'required')}
|
|
||||||
${this.errorMessage ? html`<div>${this.errorMessage}</div>` : html``}
|
|
||||||
</app-form>
|
</app-form>
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { AppFormElement, InputFieldElement } from 'components/';
|
|||||||
import { RouterService } from 'core/services';
|
import { RouterService } from 'core/services';
|
||||||
import { BasePageElement } from 'common/';
|
import { BasePageElement } from 'common/';
|
||||||
import { AppDropdownElement } from 'components/app-dropdown/AppDropdownElement';
|
import { AppDropdownElement } from 'components/app-dropdown/AppDropdownElement';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
@controller
|
@controller
|
||||||
class TransactionCreateElement extends BasePageElement {
|
class TransactionCreateElement extends BasePageElement {
|
||||||
@@ -84,7 +85,15 @@ class TransactionCreateElement extends BasePageElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { description: description, wallet: walletId, amount, transactionType: transactionTypeId } = values;
|
const {
|
||||||
|
description: description,
|
||||||
|
wallet: walletId,
|
||||||
|
amount,
|
||||||
|
transactionType: transactionTypeId,
|
||||||
|
transactionDate,
|
||||||
|
} = values;
|
||||||
|
|
||||||
|
const formattedDate = dayjs(transactionDate).format();
|
||||||
|
|
||||||
const walletData = this.walletData;
|
const walletData = this.walletData;
|
||||||
|
|
||||||
@@ -92,9 +101,11 @@ class TransactionCreateElement extends BasePageElement {
|
|||||||
description,
|
description,
|
||||||
amount,
|
amount,
|
||||||
walletId: walletData && walletData.walletId ? walletData.walletId : walletId,
|
walletId: walletData && walletData.walletId ? walletData.walletId : walletId,
|
||||||
|
transactionDate: formattedDate,
|
||||||
transactionTypeId:
|
transactionTypeId:
|
||||||
walletData && walletData.transactionTypeId ? walletData.transactionTypeId : transactionTypeId,
|
walletData && walletData.transactionTypeId ? walletData.transactionTypeId : transactionTypeId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await this.transactionService.post(formData);
|
const response = await this.transactionService.post(formData);
|
||||||
|
|
||||||
if (response?.id) {
|
if (response?.id) {
|
||||||
@@ -125,7 +136,7 @@ class TransactionCreateElement extends BasePageElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render = (): TemplateResult => {
|
render = (): TemplateResult => {
|
||||||
const renderInput = (type, name, label, rules, hide?) => {
|
const renderInput = (type, name, label, rules, hide?, customAction?) => {
|
||||||
if (hide) {
|
if (hide) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
@@ -135,6 +146,7 @@ class TransactionCreateElement extends BasePageElement {
|
|||||||
data-label="${label}"
|
data-label="${label}"
|
||||||
data-targets="transaction-create.inputs"
|
data-targets="transaction-create.inputs"
|
||||||
data-rules="${rules}"
|
data-rules="${rules}"
|
||||||
|
custom-action="${customAction}"
|
||||||
></input-field>`;
|
></input-field>`;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -159,6 +171,7 @@ class TransactionCreateElement extends BasePageElement {
|
|||||||
>
|
>
|
||||||
${renderInput('number', 'amount', 'Amount', 'required')}
|
${renderInput('number', 'amount', 'Amount', 'required')}
|
||||||
${renderInput('text', 'description', 'Description', 'required')}
|
${renderInput('text', 'description', 'Description', 'required')}
|
||||||
|
${renderInput('date', 'transactionDate', 'Transaction date', 'required')}
|
||||||
${renderDropdown(
|
${renderDropdown(
|
||||||
'transaction-create#getWallets',
|
'transaction-create#getWallets',
|
||||||
'wallet',
|
'wallet',
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ app-modal {
|
|||||||
width: 960px;
|
width: 960px;
|
||||||
min-height: 160px;
|
min-height: 160px;
|
||||||
max-height: 560px;
|
max-height: 560px;
|
||||||
|
overflow-y: auto;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -41,7 +42,7 @@ app-modal {
|
|||||||
.button-content {
|
.button-content {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 4px;
|
left: 4px;
|
||||||
bottom: 4px;
|
margin-top: 20pxf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2179,6 +2179,11 @@ dashdash@^1.12.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
assert-plus "^1.0.0"
|
assert-plus "^1.0.0"
|
||||||
|
|
||||||
|
dayjs@^1.10.5:
|
||||||
|
version "1.10.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.5.tgz#5600df4548fc2453b3f163ebb2abbe965ccfb986"
|
||||||
|
integrity sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g==
|
||||||
|
|
||||||
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
|
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
|
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user