From 6fa3c9266c4392a65ed076e9d4e1368b3a65713c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=20Jurmanovi=C4=87?= Date: Sat, 19 Jun 2021 14:14:12 +0200 Subject: [PATCH] added transaction date to transaction form --- package.json | 1 + src/common/core/BaseElement/BaseElement.ts | 4 ++ src/common/core/Validator/Validator.ts | 14 ++++- .../app-dropdown/AppDropdownElement.ts | 2 +- src/components/app-form/AppFormElement.ts | 23 ++++--- src/components/app-main/AppMainElement.ts | 2 +- .../input-field/InputFieldElement.ts | 16 ++++- src/core/utils/validator.ts | 2 + .../SubscriptionCreateElement.ts | 62 ++++++++++++++----- .../TransactionCreateElement.ts | 17 ++++- src/styles/modal/modal.scss | 3 +- yarn.lock | 5 ++ 12 files changed, 119 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 8980f88..1d3e8ec 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@github/catalyst": "^1.1.3", + "dayjs": "^1.10.5", "lit-html": "^1.4.1", "validator": "^13.6.0" }, diff --git a/src/common/core/BaseElement/BaseElement.ts b/src/common/core/BaseElement/BaseElement.ts index af302fa..163694b 100644 --- a/src/common/core/BaseElement/BaseElement.ts +++ b/src/common/core/BaseElement/BaseElement.ts @@ -79,6 +79,10 @@ class BaseElement extends HTMLElement { update = (): void => { render(this.render(), this); + if (this.shadowRoot) { + const renderSlot = () => html``; + render(renderSlot(), this.shadowRoot); + } this.bindEvents('data-action'); this.bindEvents('app-action'); this.updateCallback(); diff --git a/src/common/core/Validator/Validator.ts b/src/common/core/Validator/Validator.ts index 381f503..d794d4d 100644 --- a/src/common/core/Validator/Validator.ts +++ b/src/common/core/Validator/Validator.ts @@ -39,6 +39,7 @@ class Validator { .reverse() .map((rule) => { let args = []; + let inps = []; if (rule.includes('[') && rule.includes(']')) { const begSep = rule.lastIndexOf('['); const endSep = rule.lastIndexOf(']'); @@ -51,7 +52,7 @@ class Validator { const begBr = arg.lastIndexOf('('); const endBr = arg.lastIndexOf(')'); const field = arg.slice(begBr + 1, endBr); - + inps = [...inps, this.form.getInput(field)]; return this.form?.values[field]; } }); @@ -69,10 +70,19 @@ class Validator { } } if (!valid) { - const error = ruleArray + let error = ruleArray ? validRule?.[1]?.replaceAll('{- name}', firstUpper(this.name?.toString())) : validatorErrors[rule]?.replaceAll('{- name}', firstUpper(this.name?.toString())); 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; } } diff --git a/src/components/app-dropdown/AppDropdownElement.ts b/src/components/app-dropdown/AppDropdownElement.ts index 421fdee..8b62bc9 100644 --- a/src/components/app-dropdown/AppDropdownElement.ts +++ b/src/components/app-dropdown/AppDropdownElement.ts @@ -88,7 +88,7 @@ class AppDropdownElement extends BaseComponentElement { return this.value; } - validate = (): boolean => { + validate = (change = false): boolean => { return this.validator.validate(); }; diff --git a/src/components/app-form/AppFormElement.ts b/src/components/app-form/AppFormElement.ts index 0c62d6a..102ddea 100644 --- a/src/components/app-form/AppFormElement.ts +++ b/src/components/app-form/AppFormElement.ts @@ -12,6 +12,7 @@ class AppFormElement extends BaseComponentElement { @querys inputField: NodeListOf; @querys appDropdown: NodeListOf; @attr custom: string; + @attr renderInput: string; @attr hasCancel: string; slotted: any; isValid: boolean = false; @@ -24,6 +25,10 @@ class AppFormElement extends BaseComponentElement { return findMethod(this.custom, this.appMain); } + get customRender() { + return findMethod(this.renderInput, this.appMain); + } + public inputChange = (e) => { this.validate(); this.update(); @@ -103,13 +108,15 @@ class AppFormElement extends BaseComponentElement { } elementConnected = (): void => { - const _template = document.createElement('template'); - const _slot = this.innerHTML; - _template.innerHTML = _slot; - this.innerHTML = null; - this.update(); - - this.formElement.replaceChild(_template.content, this.innerSlot); + if (this.renderInput) { + this.update(); + } else { + const _template = document.createElement('template'); + const _slot = this.innerHTML; + _template.innerHTML = _slot; + this.update(); + this.formElement?.replaceChild(_template.content, this.innerSlot); + } }; render = (): TemplateResult => { @@ -139,7 +146,7 @@ class AppFormElement extends BaseComponentElement { return html`
- + ${this.renderInput ? this.customRender() : html``} ${renderError(this.error)}
${renderSubmit(this.isValid)}${renderCancel(isTrue(this.hasCancel))}
diff --git a/src/components/app-main/AppMainElement.ts b/src/components/app-main/AppMainElement.ts index 4dd7864..38fb7ac 100644 --- a/src/components/app-main/AppMainElement.ts +++ b/src/components/app-main/AppMainElement.ts @@ -13,7 +13,7 @@ class AppMainElement extends HTMLElement { public authStore: AuthStore; private httpClient: HttpClient; public appService: AppService; - public shadow: any; + //public shadow: any; @target appModal: AppModalElement; @target mainRoot: AppRootElement; @target appLoader: AppLoaderElement; diff --git a/src/components/input-field/InputFieldElement.ts b/src/components/input-field/InputFieldElement.ts index 0e5528c..2e3a79e 100644 --- a/src/components/input-field/InputFieldElement.ts +++ b/src/components/input-field/InputFieldElement.ts @@ -13,12 +13,14 @@ class InputFieldElement extends BaseComponentElement { @attr type: string; @attr label: string; @attr rules: string; + @attr customAction: string; @target main: HTMLElement; @target inp: HTMLElement; @closest appForm: AppFormElement; valid: boolean; displayError: boolean; randId: string; + changed: boolean = false; validator: Validator; @@ -54,7 +56,15 @@ class InputFieldElement extends BaseComponentElement { } 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 = () => { @@ -69,6 +79,9 @@ class InputFieldElement extends BaseComponentElement { }; inputChange = (e) => { + if (!this.changed && e?.target?.value) { + this.changed = true; + } this.validate(); this.appForm?.inputChange(e); }; @@ -96,6 +109,7 @@ class InputFieldElement extends BaseComponentElement { app-action=" input:input-field#inputChange blur:input-field#validateDisplay + ${this.customAction ? this.customAction : ''} " />`; }; diff --git a/src/core/utils/validator.ts b/src/core/utils/validator.ts index a91ceda..005ba79 100644 --- a/src/core/utils/validator.ts +++ b/src/core/utils/validator.ts @@ -1,6 +1,7 @@ import isEmail from 'validator/lib/isEmail'; import isDate from 'validator/lib/isDate'; import isNumeric from 'validator/lib/isNumeric'; +import isAfter from 'validator/lib/isAfter'; import matches from 'validator/lib/matches'; const validator = { @@ -10,6 +11,7 @@ const validator = { matches: matches, is_same: [isSame, '{- name} needs to be same to {- field}.'], required: [required, '{- name} is required.'], + is_after: [isAfter, '{- name} needs to be after {- field}.'], }; function required(str: string): boolean { diff --git a/src/pages/subscription-create/SubscriptionCreateElement.ts b/src/pages/subscription-create/SubscriptionCreateElement.ts index 18772ca..a55cee0 100644 --- a/src/pages/subscription-create/SubscriptionCreateElement.ts +++ b/src/pages/subscription-create/SubscriptionCreateElement.ts @@ -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 { for (const i in this.inputs) { if (this.inputs[i]?.name == 'name') { @@ -148,10 +156,16 @@ class SubscriptionCreateElement extends BasePageElement { return _return; } - render = (): TemplateResult => { - const renderInput = (type, name, label, rules, hide?) => { + onCheck = () => { + this.appForm.update(); + this.appForm.validate(); + this.appForm.update(); + }; + + renderForms = () => { + const renderInput = (type, name, label, rules, hide?, customAction?) => { if (hide) { - return html``; + return null; } return html``; }; @@ -174,26 +189,41 @@ class SubscriptionCreateElement extends BasePageElement { data-fetch="${fetch}" >`; }; + return html` +
+ ${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`
${this.errorMessage}
` : html``}`; + }; + render = (): TemplateResult => { return html` - ${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`
${this.errorMessage}
` : html``}
`; }; diff --git a/src/pages/transaction-create/TransactionCreateElement.ts b/src/pages/transaction-create/TransactionCreateElement.ts index 72478f2..eec5751 100644 --- a/src/pages/transaction-create/TransactionCreateElement.ts +++ b/src/pages/transaction-create/TransactionCreateElement.ts @@ -5,6 +5,7 @@ import { AppFormElement, InputFieldElement } from 'components/'; import { RouterService } from 'core/services'; import { BasePageElement } from 'common/'; import { AppDropdownElement } from 'components/app-dropdown/AppDropdownElement'; +import dayjs from 'dayjs'; @controller class TransactionCreateElement extends BasePageElement { @@ -84,7 +85,15 @@ class TransactionCreateElement extends BasePageElement { 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; @@ -92,9 +101,11 @@ class TransactionCreateElement extends BasePageElement { description, amount, walletId: walletData && walletData.walletId ? walletData.walletId : walletId, + transactionDate: formattedDate, transactionTypeId: walletData && walletData.transactionTypeId ? walletData.transactionTypeId : transactionTypeId, }; + const response = await this.transactionService.post(formData); if (response?.id) { @@ -125,7 +136,7 @@ class TransactionCreateElement extends BasePageElement { } render = (): TemplateResult => { - const renderInput = (type, name, label, rules, hide?) => { + const renderInput = (type, name, label, rules, hide?, customAction?) => { if (hide) { return html``; } @@ -135,6 +146,7 @@ class TransactionCreateElement extends BasePageElement { data-label="${label}" data-targets="transaction-create.inputs" data-rules="${rules}" + custom-action="${customAction}" >`; }; @@ -159,6 +171,7 @@ class TransactionCreateElement extends BasePageElement { > ${renderInput('number', 'amount', 'Amount', 'required')} ${renderInput('text', 'description', 'Description', 'required')} + ${renderInput('date', 'transactionDate', 'Transaction date', 'required')} ${renderDropdown( 'transaction-create#getWallets', 'wallet', diff --git a/src/styles/modal/modal.scss b/src/styles/modal/modal.scss index 888f976..73012b9 100644 --- a/src/styles/modal/modal.scss +++ b/src/styles/modal/modal.scss @@ -16,6 +16,7 @@ app-modal { width: 960px; min-height: 160px; max-height: 560px; + overflow-y: auto; padding-bottom: 10px; margin: 0; top: 50%; @@ -41,7 +42,7 @@ app-modal { .button-content { position: absolute; left: 4px; - bottom: 4px; + margin-top: 20pxf; } } } diff --git a/yarn.lock b/yarn.lock index 3d7fa1c..9d60438 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2179,6 +2179,11 @@ dashdash@^1.12.0: dependencies: 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: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"