implemented dropdowns

This commit is contained in:
Fran Jurmanović
2021-06-06 14:25:58 +02:00
parent 2b0fcf4878
commit 53ee8dfd73
10 changed files with 246 additions and 20 deletions

View File

@@ -1,5 +1,5 @@
import { attr, controller, target } from "@github/catalyst";
import { firstUpper } from "core/utils";
import { findMethod, firstUpper } from "core/utils";
import { html, TemplateResult } from "@github/jtml";
import { RouterService } from "core/services";
import randomId from "core/utils/random-id";
@@ -10,20 +10,98 @@ import { BaseComponentElement } from "common/";
@controller
class AppDropdownElement extends BaseComponentElement {
@attr name: string;
@attr type: string;
@attr label: string;
@attr rules: string;
@target main: HTMLElement;
@target inp: HTMLElement;
@attr displaykey: string;
@attr valuekey: string;
@attr fetch: string;
fetchFunc: any;
error: string;
randId: string;
items: Array<any>;
totalItems: number;
page: number = 1;
rpp: number = 30;
constructor() {
super();
}
getItems = async (options?: any): Promise<void> => {
if (typeof this.fetchFunc !== "function") return;
try {
const response = await this.fetchFunc(options);
this.setItems(response);
} catch (err) {
this.update();
}
};
setItems = (response): void => {
if (response) {
let items = [];
if (Array.isArray(response)) {
items = response;
} else if (Array.isArray(response.items)) {
items = response.items;
this.totalItems = response?.totalRecords;
} else {
items = [];
}
this.items = items;
this.renderOptions(items);
this.renderOptions(items);
}
};
private renderOptions = (items) => {
const displayKey = this.displaykey || "name";
const valueKey = this.valuekey || "id";
const options = items?.map((item) => {
const val = { name: item[displayKey], value: item[valueKey] };
if (
this.optionValues.some((value) => {
if (value.name == val.name && value.value == val.value) {
return true;
}
return false;
})
)
return;
const _option = document.createElement("option");
_option.setAttribute("value", val.value);
_option.innerText = val.name;
this.inp?.appendChild(_option);
});
};
get optionValues() {
let values = [];
this.inp.childNodes.forEach((item: HTMLElement) => {
const value = item.getAttribute("value");
const name = item.innerText;
values.push({ name, value });
});
return values;
}
onChange = () => {
this.renderOptions(this.items);
};
public elementConnected = (): void => {
this.randId = `${name}${randomId()}`;
this.fetchFunc = findMethod(this.fetch, this.appMain);
this.update();
const options = {
rpp: this.rpp,
page: this.page,
};
this.getItems(options);
};
get valid(): boolean {
@@ -37,7 +115,8 @@ class AppDropdownElement extends BaseComponentElement {
validate(): boolean {
let _return = true;
const rules = this.rules?.split("|").filter((a) => a);
const value = (this.inp as HTMLInputElement)?.value;
const value = (this.inp as HTMLSelectElement)?.value;
console.log(_return, rules, value);
rules
.slice()
.reverse()
@@ -67,7 +146,12 @@ class AppDropdownElement extends BaseComponentElement {
}
render = (): TemplateResult => {
return html``;
return html`<div data-target="app-dropdown.main">
<select
data-target="app-dropdown.inp"
data-action="change:app-dropdown#onChange"
></select>
</div>`;
};
}

View File

@@ -2,7 +2,7 @@ import { attr, controller, target } from "@github/catalyst";
import { html, TemplateResult, unsafeHTML } from "@github/jtml";
import { BaseComponentElement } from "common/";
import { InputFieldElement } from "components/input-field/InputFieldElement";
import { isTrue, querys } from "core/utils";
import { findMethod, isTrue, querys } from "core/utils";
@controller
class AppFormElement extends BaseComponentElement {
@@ -29,16 +29,8 @@ class AppFormElement extends BaseComponentElement {
return;
}
const actionString = this.custom;
if (actionString) {
const methodSep = actionString.lastIndexOf("#");
const tag = actionString.slice(0, methodSep);
const method = actionString.slice(methodSep + 1);
const element = this.appMain.querySelector(tag);
if (element) {
element?.[method]?.(e);
}
}
const submitFunc = findMethod(actionString, this.appMain);
submitFunc?.(e);
return false;
};
@@ -71,7 +63,7 @@ class AppFormElement extends BaseComponentElement {
get valid() {
let _valid = 0;
this.inputField?.forEach((input) => {
if (input.required && (input.inp as HTMLInputElement).value) {
if (input.required && (input.inp as HTMLSelectElement).value) {
_valid++;
}
});

View File

@@ -71,7 +71,7 @@ class AppMenuElement extends BaseComponentElement {
return null;
};
openModal = (): void => {
modalWallet = (): void => {
const _modal = this.appMain.appModal;
if (_modal) {
this.appMain.closeModal();
@@ -80,6 +80,15 @@ class AppMenuElement extends BaseComponentElement {
}
};
modalTransaction = (): void => {
const _modal = this.appMain.appModal;
if (_modal) {
this.appMain.closeModal();
} else {
this.appMain.createModal("transaction-create");
}
};
render = (): TemplateResult => {
const { isAuth, totalWallets, walletData } = this;
@@ -132,11 +141,15 @@ class AppMenuElement extends BaseComponentElement {
return html`
<div data-target="app-menu.sidebar">
${menuHeader(__CONFIG__.appName)} ${regularMenu("/", "Home")}
${authMenu("/history", "Transaction History")}
${authMenu(
"/history",
"Transaction History",
"click:app-menu#modalTransaction"
)}
${authMenu(
"/wallet/all",
"My Wallets",
"click:app-menu#openModal"
"click:app-menu#modalWallet"
)}
${renderWallets(walletData)}
<span class="menu-item divider"></span>

View File

@@ -6,6 +6,7 @@ export * from "./app-root/AppRootElement";
export * from "./app-slot/AppSlotElement";
export * from "./app-menu/AppMenuElement";
export * from "./input-field/InputFieldElement";
export * from "./app-dropdown/AppDropdownElement";
export * from "./app-loader/AppLoaderElement";
export * from "./circle-loader/CircleLoaderElement";
export * from "./app-form/AppFormElement";

View File

@@ -27,6 +27,7 @@ class InputFieldElement extends BaseComponentElement {
public elementConnected = (): void => {
this.randId = `${name}${randomId()}`;
this.update();
this.validate();
};
get valid(): boolean {

View File

@@ -0,0 +1,18 @@
import { AppMainElement } from "components/";
export default function findMethod(
actionString: string,
appMain: AppMainElement
): Function {
if (actionString) {
const methodSep = actionString.lastIndexOf("#");
const tag = actionString.slice(0, methodSep);
const method = actionString.slice(methodSep + 1);
const element = appMain.querySelector(tag);
if (element) {
return element?.[method];
}
}
return () => {};
}

View File

@@ -6,3 +6,4 @@ export { default as isTrue } from "./isTrue";
export { default as firstUpper } from "./first-upper";
export { default as query } from "./query-deco";
export { default as querys } from "./querys-deco";
export { default as findMethod } from "./find-method";

View File

@@ -6,3 +6,4 @@ export * from "./not-found/NotFoundElement";
export * from "./history-page/HistoryPageElement";
export * from "./wallet-list/WalletListElement";
export * from "./wallet-create/WalletCreateElement";
export * from "./transaction-create/TransactionCreateElement";

View File

@@ -0,0 +1,116 @@
import { targets, controller } from "@github/catalyst";
import { html, TemplateResult } from "@github/jtml";
import { AuthService, TransactionsService, WalletService } from "services/";
import { InputFieldElement } from "components/";
import { RouterService } from "core/services";
import { BasePageElement } from "common/";
import { AppDropdownElement } from "components/app-dropdown/AppDropdownElement";
@controller
class TransactionCreateElement extends BasePageElement {
@targets inputs: Array<InputFieldElement | AppDropdownElement>;
private transactionService: TransactionsService;
private walletService: WalletService;
authService: AuthService;
errorMessage: string;
constructor() {
super({
title: "New Transaction",
});
}
elementConnected = (): void => {
this.walletService = new WalletService(this.appMain?.appService);
this.transactionService = new TransactionsService(
this.appMain?.appService
);
this.authService = new AuthService(this.appMain.appService);
this.update();
};
get nameInput(): InputFieldElement | AppDropdownElement {
for (const i in this.inputs) {
if (this.inputs[i]?.name == "name") {
return this.inputs[i];
}
}
}
get values(): any {
const formObject: any = {};
this.inputs.forEach((input: InputFieldElement) => {
const inputType = input.inp;
formObject[input.name] = (inputType as HTMLInputElement).value;
});
return formObject;
}
getWallets = async (options): Promise<void> => {
try {
const response = await this.walletService.getAll(options);
return response;
} catch (err) {}
};
onSubmit = async (): Promise<void> => {
try {
if (!this.validate()) {
return;
}
const { name: description, wallet: walletId } = this.values;
const response = await this.transactionService.post({
description,
walletId,
});
if (response?.id) {
this.appMain.triggerWalletUpdate();
this.routerService.goTo("/history", {
walletId: response.id,
});
}
} catch (err) {
this.errorMessage = "Unable to create transaction!";
this.update();
}
};
validate(): boolean {
let _return = true;
this.inputs.forEach((input: InputFieldElement) => {
const valid: boolean = input.validate();
if (!valid) _return = false;
});
return _return;
}
render = (): TemplateResult => {
return html`
<div>Create wallet</div>
<app-form
data-custom="transaction-create#onSubmit"
data-has-cancel="true"
>
<input-field
data-type="text"
data-name="name"
data-label="Name"
data-targets="transaction-create.inputs"
data-rules="required"
></input-field>
<app-dropdown
data-name="wallet"
data-label="Wallet"
data-targets="transaction-create.inputs"
data-rules="required"
data-fetch="transaction-create#getWallets"
>
</app-dropdown>
${this.errorMessage
? html`<div>${this.errorMessage}</div>`
: html``}
</app-form>
`;
};
}
export type { TransactionCreateElement };

View File

@@ -2,7 +2,6 @@ app-main {
* {
font-family: Roboto;
font-size: 14px;
color: $white;
}
input,