Move creation and joining to their own views and components

This commit is contained in:
Mikko Ahlroth 2019-06-25 12:36:24 +03:00
parent 293e1ca8cd
commit 51c24a2d39
7 changed files with 252 additions and 174 deletions

View file

@ -1,138 +0,0 @@
import { LitElement, html } from 'lit-element'
import './budget-qr-reader'
import { QRReadEvent } from './budget-qr-reader'
import './input'
import './button'
import { InputField } from './input'
import './icon'
export class JoinBudgetEvent extends CustomEvent<{ uuid: string }> { }
export class CreateBudgetEvent extends CustomEvent<{
amount: number,
currency: string,
name: string
}> { }
class BudgetAddComponent extends LitElement {
hasCreateError: boolean
hasJoinError: boolean
showQRReader: boolean
static get properties() {
return {
hasCreateError: { type: Boolean },
hasJoinError: { type: Boolean },
showQRReader: { type: Boolean }
}
}
constructor() {
super()
this.hasCreateError = false
this.hasJoinError = false
this.showQRReader = false
}
onCreate(e: Event) {
e.preventDefault()
const root = this.shadowRoot
const amountInputEl = <InputField>root.getElementById('create-budget-amount')
const currencyInputEl = <InputField>root.getElementById('create-budget-currency')
const nameInputEl = <InputField>root.getElementById('create-budget-name')
const name = nameInputEl.getValue().trim()
const amount = parseInt(amountInputEl.getValue())
if (isNaN(amount)) {
this.hasCreateError = true
return
}
this.dispatchEvent(new CreateBudgetEvent(
'createBudget',
{ detail: { amount, currency: currencyInputEl.getValue(), name } }
))
amountInputEl.clearValue()
currencyInputEl.clearValue()
nameInputEl.clearValue()
}
onJoin(e: Event) {
e.preventDefault()
const inputEl = <InputField>this.shadowRoot.getElementById('join-budget-uuid')
this.dispatchEvent(new JoinBudgetEvent(
'joinBudget',
{ detail: { uuid: inputEl.getValue() } }
))
inputEl.clearValue()
}
onQRRead(e: QRReadEvent) {
const text = e.detail.text
this.dispatchEvent(new JoinBudgetEvent(
'joinBudget',
{ detail: { uuid: text } }
))
this.showQRReader = false
}
toggleShowQRReader() {
this.showQRReader = !this.showQRReader
}
render() {
return html`
<h2>Create a budget</h2>
<input-field
id="create-budget-name"
type="text"
placeholder="Name (optional)"
></input-field>
<input-field
id="create-budget-amount"
type="number"
placeholder="Amount"
required
></input-field>
<input-field
id="create-budget-currency"
type="text"
placeholder="Currency (3 chars)"
pattern="[A-Z]{3}"
maxlength="3"
required
></input-field>
<fa-button @click=${this.onCreate}>Create budget</fa-button>
${this.hasCreateError ? html`<p>Could not create budget, check the amount and currency.</p>` : null}
<h2> or join existing budget</h2>
<p>Add below the budget secret that you can get from the person who created the budget.</p>
<input-field
id="join-budget-uuid"
type="text"
placeholder="aaaaaaaa-bbbb-4ccc-9ddd-ffffffffffff"
maxlength="36"
pattern="[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}"
required
></input-field>
<fa-button @click=${this.onJoin}>
<fa-icon name="plus" alt="Join budget"></fa-icon>
</fa-button>
<fa-button type="button" @click=${this.toggleShowQRReader}>
<fa-icon name="qrcode" alt="Read QR using camera"></fa-icon>
</fa-button>
<div>
${this.showQRReader ? html`<budget-qr-reader @qrRead=${this.onQRRead}></budget-qr-reader>` : null}
</div>
${this.hasJoinError ? html`<p>Could not add given budget, please check it is correctly typed.</p>` : null}
`
}
}
customElements.define('budget-add', BudgetAddComponent)

View file

@ -0,0 +1,71 @@
import { LitElement, html } from 'lit-element'
import { InputField } from './input'
import './input'
export class CreateBudgetEvent extends CustomEvent<{
amount: number,
currency: string,
name: string
}> { }
class BudgetCreateComponent extends LitElement {
hasError: boolean
static get properties() {
return {
hasError: { type: Boolean }
}
}
onCreate(e: Event) {
e.preventDefault()
const root = this.shadowRoot
const amountInputEl = <InputField>root.getElementById('create-budget-amount')
const currencyInputEl = <InputField>root.getElementById('create-budget-currency')
const nameInputEl = <InputField>root.getElementById('create-budget-name')
const name = nameInputEl.getValue().trim()
const amount = parseInt(amountInputEl.getValue())
if (isNaN(amount)) {
this.hasError = true
return
}
this.dispatchEvent(new CreateBudgetEvent(
'createBudget',
{ detail: { amount, currency: currencyInputEl.getValue(), name } }
))
amountInputEl.clearValue()
currencyInputEl.clearValue()
nameInputEl.clearValue()
}
render() {
return html`
<label for="create-budget-name-field">Name (optional)</label>
<input-field
id="create-budget-name"
type="text"
></input-field>
<label for="create-budget-amount-field">Amount</label>
<input-field
id="create-budget-amount"
type="number"
required
></input-field>
<label for="create-budget-currency-field">Currency (3 chars)</label>
<input-field
id="create-budget-currency"
type="text"
pattern="[A-Z]{3}"
maxlength="3"
required
></input-field>
<fa-button @click=${this.onCreate}>Create budget</fa-button>
${this.hasError ? html`<p>Could not create budget, check the amount and currency.</p>` : null}
`
}
}
customElements.define('budget-create', BudgetCreateComponent)

View file

@ -59,6 +59,8 @@ class BudgetDisplayComponent extends LitElement {
display: grid;
column-gap: 10px;
grid-template: 'now curr' 'of init' / auto 66%;
margin-top: 20px;
}
.money-left {
@ -191,21 +193,23 @@ class BudgetDisplayComponent extends LitElement {
${this.budget.events.map(event => this._renderEvent(this.budget, event))}
</ul>
<fa-button @click=${this.onSpendMoney}>
<fa-icon name="credit-card" alt="Spend money"></fa-icon>
</fa-button>
<fa-button @click=${this.onReset}>
<fa-icon name="undo" alt="Reset"></fa-icon>
</fa-button>
<fa-button @click=${this.onRename}>
<fa-icon name="edit" alt="Rename"></fa-icon>
</fa-button>
<fa-button @click=${this.toggleShare}>
<fa-icon name="qrcode" alt="Share"></fa-icon>
</fa-button>
<fa-button @click=${this.onRemove}>
<fa-icon name="trash" alt="Remove"></fa-icon>
</fa-button>
<div class="actions" aria-label="Actions for budget '${this.budget.name}'">
<fa-button @click=${this.onSpendMoney}>
<fa-icon name="credit-card" alt="Spend money"></fa-icon>
</fa-button>
<fa-button @click=${this.onReset}>
<fa-icon name="undo" alt="Reset to given amount"></fa-icon>
</fa-button>
<fa-button @click=${this.onRename}>
<fa-icon name="edit" alt="Rename"></fa-icon>
</fa-button>
<fa-button @click=${this.toggleShare}>
<fa-icon name="qrcode" alt="Share with QR code"></fa-icon>
</fa-button>
<fa-button @click=${this.onRemove}>
<fa-icon name="trash" alt="Remove"></fa-icon>
</fa-button>
</div>
<div>
${this.showShare ? html`<budget-qr .uuid=${this.budget.uuid}></budget-qr>` : null}

View file

@ -0,0 +1,70 @@
import { LitElement, html } from 'lit-element'
import { InputField } from './input';
import { QRReadEvent } from './budget-qr-reader';
export class JoinBudgetEvent extends CustomEvent<{ uuid: string }> { }
class BudgetJoinComponent extends LitElement {
hasError: boolean
showQRReader: boolean
static get properties() {
return {
hasError: { type: Boolean },
showQRReader: { type: Boolean }
}
}
onJoin(e: Event) {
e.preventDefault()
const inputEl = <InputField>this.shadowRoot.getElementById('join-budget-uuid')
this.dispatchEvent(new JoinBudgetEvent(
'joinBudget',
{ detail: { uuid: inputEl.getValue() } }
))
inputEl.clearValue()
}
onQRRead(e: QRReadEvent) {
const text = e.detail.text
this.dispatchEvent(new JoinBudgetEvent(
'joinBudget',
{ detail: { uuid: text } }
))
this.showQRReader = false
}
toggleShowQRReader() {
this.showQRReader = !this.showQRReader
}
render() {
return html`
<p>Add below the budget secret that you can get from the person who created the budget.</p>
<input-field
id="join-budget-uuid"
type="text"
placeholder="aaaaaaaa-bbbb-4ccc-9ddd-ffffffffffff"
maxlength="36"
pattern="[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}"
required
></input-field>
<fa-button @click=${this.onJoin}>
<fa-icon name="plus" alt="Join budget"></fa-icon>
</fa-button>
<fa-button type="button" @click=${this.toggleShowQRReader}>
<fa-icon name="qrcode" alt="Read QR using camera"></fa-icon>
</fa-button>
<div>
${this.showQRReader ? html`<budget-qr-reader @qrRead=${this.onQRRead}></budget-qr-reader>` : null}
</div>
${this.hasError ? html`<p>Could not add given budget, please check it is correctly typed.</p>` : null}
`
}
}
customElements.define('budget-join', BudgetJoinComponent)

View file

@ -41,7 +41,9 @@ const ICONS = [
['qrcode', '\\f029'],
['undo', '\\f0e2'],
['trash', '\\f1f8'],
['plus', '\\f067']
['plus', '\\f067'],
['arrow-left', '\\f060'],
['user-friends', '\\f500']
]
function icon2css(name: string, code: string) {

View file

@ -48,7 +48,7 @@ export class InputField extends LitElement {
<input
id=${this.inputId}
type=${this.type}
placeholder=${this.placeholder}
placeholder=${this.placeholder ? this.placeholder : ''}
maxlength=${this.maxlength}
pattern=${this.pattern}
?required=${this.required}

View file

@ -1,14 +1,26 @@
import { LitElement, html, css } from 'lit-element'
import { LitElement, html, css, TemplateResult } from 'lit-element'
import { Budget } from '../services/models/budget'
import { CreateBudgetEvent, JoinBudgetEvent } from './budget-add'
import './budget-add'
import { JoinBudgetEvent } from './budget-join'
import './budget-join'
import './budget-list'
import { readBudget, readEvent } from '../services/readers'
import { getBudget, GetError, addEvent, resetBudget, createBudget, CreationError } from '../services/api'
import { getFromLocal, storeToLocal } from '../services/storage'
import { SpendMoneyEvent, ResetBudgetEvent, RemoveBudgetEvent, RenameBudgetEvent } from './budget-display'
import { CreateBudgetEvent } from './budget-create'
import './budget-create'
import './button'
import './icon'
enum DisplayMode {
BudgetView,
CreateView,
JoinView
}
class WeekBudgetComponent extends LitElement {
displayMode: DisplayMode = DisplayMode.BudgetView
budgets: Budget[] = []
hasCreateError: boolean = false
hasJoinError: boolean = false
@ -17,7 +29,8 @@ class WeekBudgetComponent extends LitElement {
return {
budgets: { type: Array },
hasCreateError: { type: Boolean },
hasJoinError: { type: Boolean }
hasJoinError: { type: Boolean },
displayMode: { type: DisplayMode }
}
}
@ -26,6 +39,24 @@ class WeekBudgetComponent extends LitElement {
h1 {
color: var(--light-accent);
}
hr {
border: none;
margin: 40px 20px;
height: 1px;
background-color: var(--shaded-bright);
}
.actions {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
/* SUPER BIG */
border-radius: 10px;
font-size: 400%;
}
`
}
@ -137,23 +168,61 @@ class WeekBudgetComponent extends LitElement {
storeToLocal(this.budgets)
}
setDisplayMode(mode: DisplayMode) {
this.displayMode = mode
}
render() {
return html`
<h1>TinyBudget</h1>
<budget-list
@spendMoney=${this.onSpendMoney}
@resetBudget=${this.onResetBudget}
@renameBudget=${this.onRenameBudget}
@removeBudget=${this.onRemoveBudget}
.budgets=${this.budgets}
></budget-list>
<budget-add
@createBudget=${this.onCreateBudget}
@joinBudget=${this.onJoinBudget}
.hasCreateError=${this.hasCreateError}
.hasJoinError=${this.hasJoinError}
></budget-add>
const headingWithContent = (content: TemplateResult) => html`<h1>${content}TinyBudget</h1>`
const back = html`
<fa-button @click=${() => this.setDisplayMode(DisplayMode.BudgetView)}>
<fa-icon name="arrow-left" alt="Go back"></fa-icon>
</fa-button>
`
switch (this.displayMode) {
case DisplayMode.CreateView:
return html`
${headingWithContent(back)}
<budget-create
@createBudget=${this.onCreateBudget}
.hasError=${this.hasCreateError}
></budget-create>
`
case DisplayMode.JoinView:
return html`
${headingWithContent(back)}
<budget-join
@joinBudget=${this.onJoinBudget}
.hasError=${this.hasJoinError}
></budget-join>
`
default:
return html`
${headingWithContent(html``)}
<budget-list
@spendMoney=${this.onSpendMoney}
@resetBudget=${this.onResetBudget}
@renameBudget=${this.onRenameBudget}
@removeBudget=${this.onRemoveBudget}
.budgets=${this.budgets}
></budget-list>
<hr />
<div class="actions">
<fa-button @click=${() => this.setDisplayMode(DisplayMode.CreateView)}>
<fa-icon name="plus" alt="Create new budget"></fa-icon>
</fa-button>
<fa-button @click=${() => this.setDisplayMode(DisplayMode.JoinView)}>
<fa-icon name="user-friends" alt="Join existing budget"></fa-icon>
</fa-button>
</div>
`
}
}
async _getBudget(uuid: string): Promise<Budget> {