Skip to content

Commit

Permalink
feat(c4): entry editor and navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterSkriba committed Mar 5, 2024
1 parent 85e4d72 commit 856a439
Show file tree
Hide file tree
Showing 13 changed files with 380 additions and 6 deletions.
31 changes: 31 additions & 0 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,62 @@
*/
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
export namespace Components {
interface XskribaAmbulanceWlEditor {
"entryId": string;
}
interface XskribaAmbulanceWlList {
}
}
export interface XskribaAmbulanceWlEditorCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLXskribaAmbulanceWlEditorElement;
}
declare global {
interface HTMLXskribaAmbulanceWlEditorElementEventMap {
"editor-closed": string;
}
interface HTMLXskribaAmbulanceWlEditorElement extends Components.XskribaAmbulanceWlEditor, HTMLStencilElement {
addEventListener<K extends keyof HTMLXskribaAmbulanceWlEditorElementEventMap>(type: K, listener: (this: HTMLXskribaAmbulanceWlEditorElement, ev: XskribaAmbulanceWlEditorCustomEvent<HTMLXskribaAmbulanceWlEditorElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof HTMLXskribaAmbulanceWlEditorElementEventMap>(type: K, listener: (this: HTMLXskribaAmbulanceWlEditorElement, ev: XskribaAmbulanceWlEditorCustomEvent<HTMLXskribaAmbulanceWlEditorElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
var HTMLXskribaAmbulanceWlEditorElement: {
prototype: HTMLXskribaAmbulanceWlEditorElement;
new (): HTMLXskribaAmbulanceWlEditorElement;
};
interface HTMLXskribaAmbulanceWlListElement extends Components.XskribaAmbulanceWlList, HTMLStencilElement {
}
var HTMLXskribaAmbulanceWlListElement: {
prototype: HTMLXskribaAmbulanceWlListElement;
new (): HTMLXskribaAmbulanceWlListElement;
};
interface HTMLElementTagNameMap {
"xskriba-ambulance-wl-editor": HTMLXskribaAmbulanceWlEditorElement;
"xskriba-ambulance-wl-list": HTMLXskribaAmbulanceWlListElement;
}
}
declare namespace LocalJSX {
interface XskribaAmbulanceWlEditor {
"entryId"?: string;
"onEditor-closed"?: (event: XskribaAmbulanceWlEditorCustomEvent<string>) => void;
}
interface XskribaAmbulanceWlList {
}
interface IntrinsicElements {
"xskriba-ambulance-wl-editor": XskribaAmbulanceWlEditor;
"xskriba-ambulance-wl-list": XskribaAmbulanceWlList;
}
}
export { LocalJSX as JSX };
declare module "@stencil/core" {
export namespace JSX {
interface IntrinsicElements {
"xskriba-ambulance-wl-editor": LocalJSX.XskribaAmbulanceWlEditor & JSXBase.HTMLAttributes<HTMLXskribaAmbulanceWlEditorElement>;
"xskriba-ambulance-wl-list": LocalJSX.XskribaAmbulanceWlList & JSXBase.HTMLAttributes<HTMLXskribaAmbulanceWlListElement>;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { newE2EPage } from '@stencil/core/testing';

describe('xskriba-ambulance-wl-app', () => {
it('renders', async () => {
const page = await newE2EPage();
await page.setContent('<xskriba-ambulance-wl-app></xskriba-ambulance-wl-app>');

const element = await page.find('xskriba-ambulance-wl-app');
expect(element).toHaveClass('hydrated');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { newSpecPage } from '@stencil/core/testing'
import { XskribaAmbulanceWlApp } from '../xskriba-ambulance-wl-app'

describe('xskriba-ambulance-wl-app', () => {
it('renders editor', async () => {
const page = await newSpecPage({
url: `http://localhost/entry/@new`,
components: [XskribaAmbulanceWlApp],
html: `<xskriba-ambulance-wl-app base-path="/"></xskriba-ambulance-wl-app>`
})
page.win.navigation = new EventTarget()
const child = await page.root.shadowRoot.firstElementChild
expect(child.tagName.toLocaleLowerCase()).toEqual('xskriba-ambulance-wl-editor')
})

it('renders list', async () => {
const page = await newSpecPage({
url: `http://localhost/ambulance-wl/`,
components: [XskribaAmbulanceWlApp],
html: `<xskriba-ambulance-wl-app base-path="/ambulance-wl/"></xskriba-ambulance-wl-app>`
})
page.win.navigation = new EventTarget()
const child = await page.root.shadowRoot.firstElementChild
expect(child.tagName.toLocaleLowerCase()).toEqual('xskriba-ambulance-wl-list')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: block;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Component, Host, Prop, State, h } from '@stencil/core'

declare global {
interface Window {
navigation: any
}
}

@Component({
tag: 'xskriba-ambulance-wl-app',
styleUrl: 'xskriba-ambulance-wl-app.css',
shadow: true
})
export class XskribaAmbulanceWlApp {
@State() private relativePath = ''

@Prop() basePath: string = ''

componentWillLoad() {
const baseUri = new URL(this.basePath, document.baseURI || '/').pathname

const toRelative = (path: string) => {
if (path.startsWith(baseUri)) {
this.relativePath = path.slice(baseUri.length)
} else {
this.relativePath = ''
}
}

window.navigation?.addEventListener('navigate', (ev: Event) => {
if ((ev as any).canIntercept) {
;(ev as any).intercept()
}
let path = new URL((ev as any).destination.url).pathname
toRelative(path)
})

toRelative(location.pathname)
}

render() {
let element = 'list'
let entryId = '@new'

if (this.relativePath.startsWith('entry/')) {
element = 'editor'
entryId = this.relativePath.split('/')[1]
}

const navigate = (path: string) => {
const absolute = new URL(path, new URL(this.basePath, document.baseURI)).pathname
window.navigation.navigate(absolute)
}

return (
<Host>
{element === 'editor' ? (
<xskriba-ambulance-wl-editor entry-id={entryId} oneditor-closed={() => navigate('./list')}></xskriba-ambulance-wl-editor>
) : (
<xskriba-ambulance-wl-list onentry-clicked={(ev: CustomEvent<string>) => navigate('./entry/' + ev.detail)}></xskriba-ambulance-wl-list>
)}
</Host>
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { newE2EPage } from '@stencil/core/testing';

describe('xskriba-ambulance-wl-editor', () => {
it('renders', async () => {
const page = await newE2EPage();
await page.setContent('<xskriba-ambulance-wl-editor></xskriba-ambulance-wl-editor>');

const element = await page.find('xskriba-ambulance-wl-editor');
expect(element).toHaveClass('hydrated');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { newSpecPage } from '@stencil/core/testing'
import { XskribaAmbulanceWlEditor } from '../xskriba-ambulance-wl-editor'

describe('xskriba-ambulance-wl-editor', () => {
it('buttons shall be of different type', async () => {
const page = await newSpecPage({
components: [XskribaAmbulanceWlEditor],
html: `<xskriba-ambulance-wl-editor entry-id="@new"></xskriba-ambulance-wl-editor>`
})
let items: any = await page.root.shadowRoot.querySelectorAll('md-filled-button')
expect(items.length).toEqual(1)
items = await page.root.shadowRoot.querySelectorAll('md-outlined-button')
expect(items.length).toEqual(1)

items = await page.root.shadowRoot.querySelectorAll('md-filled-tonal-button')
expect(items.length).toEqual(1)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
:host {
--_wl-editor_gap: var(--wl-gap, 0.5rem);

display: flex;
flex-direction: column;
gap: var(--_wl-editor_gap);
padding: var(--_wl-editor_gap);
}

.duration-slider {
display: flex;
flex-direction: row;
align-content: space-around;
align-items: center;
}

.actions {
display: flex;
flex-direction: row;
justify-content: flex-end;
gap: 1rem;
}

.stretch-fill {
flex: 10 0 0;
}

md-divider {
margin-bottom: var(--_wl-editor_gap);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Component, Host, Prop, State, h, EventEmitter, Event } from '@stencil/core'

@Component({
tag: 'xskriba-ambulance-wl-editor',
styleUrl: 'xskriba-ambulance-wl-editor.css',
shadow: true
})
export class XskribaAmbulanceWlEditor {
@Prop() entryId: string

@Event({ eventName: 'editor-closed' }) editorClosed: EventEmitter<string>

@State() private duration = 15

private handleSliderInput(event: Event) {
this.duration = +(event.target as HTMLInputElement).value
}

render() {
return (
<Host>
<md-filled-text-field label="Meno a Priezvisko">
<md-icon slot="leading-icon">person</md-icon>
</md-filled-text-field>

<md-filled-text-field label="Registračné číslo pacienta">
<md-icon slot="leading-icon">fingerprint</md-icon>
</md-filled-text-field>

<md-filled-text-field label="Čakáte od" disabled>
<md-icon slot="leading-icon">watch_later</md-icon>
</md-filled-text-field>

<md-filled-select label="Dôvod návštevy">
<md-icon slot="leading-icon">sick</md-icon>
<md-select-option value="folowup">
<div slot="headline">Kontrola</div>
</md-select-option>
<md-select-option value="nausea">
<div slot="headline">Nevoľnosť</div>
</md-select-option>
<md-select-option value="fever">
<div slot="headline">Horúčka</div>
</md-select-option>
<md-select-option value="ache-in-throat">
<div slot="headline">Bolesti hrdla</div>
</md-select-option>
</md-filled-select>

<div class="duration-slider">
<span class="label">Predpokladaná doba trvania:&nbsp; </span>
<span class="label">{this.duration}</span>
<span class="label">&nbsp;minút</span>
<md-slider min="2" max="45" value={this.duration} ticks labeled oninput={this.handleSliderInput.bind(this)}></md-slider>
</div>

<md-divider></md-divider>
<div class="actions">
<md-filled-tonal-button id="delete" onClick={() => this.editorClosed.emit('delete')}>
<md-icon slot="icon">delete</md-icon>
Zmazať
</md-filled-tonal-button>
<span class="stretch-fill"></span>
<md-outlined-button id="cancel" onClick={() => this.editorClosed.emit('cancel')}>
Zrušiť
</md-outlined-button>
<md-filled-button id="confirm" onClick={() => this.editorClosed.emit('store')}>
<md-icon slot="icon">save</md-icon>
Uložiť
</md-filled-button>
</div>
</Host>
)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Component, Host, h } from '@stencil/core'
import { Component, Event, EventEmitter, Host, h } from '@stencil/core'

@Component({
tag: 'xskriba-ambulance-wl-list',
styleUrl: 'xskriba-ambulance-wl-list.css',
shadow: true
})
export class XskribaAmbulanceWlList {
@Event({ eventName: 'entry-clicked' }) entryClicked: EventEmitter<string>

waitingPatients: any[]

private async getWaitingPatientsAsync() {
Expand Down Expand Up @@ -45,8 +47,8 @@ export class XskribaAmbulanceWlList {
return (
<Host>
<md-list>
{this.waitingPatients.map(patient => (
<md-list-item>
{this.waitingPatients.map((patient, index) => (
<md-list-item onClick={() => this.entryClicked.emit(index.toString())}>
<div slot="headline">{patient.name}</div>
<div slot="supporting-text">{'Predpokladaný vstup: ' + this.isoDateToLocale(patient.estimatedStart)}</div>
<md-icon slot="start">person</md-icon>
Expand Down
13 changes: 11 additions & 2 deletions src/global/app.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import '@material/web/list/list'
import '@material/web/list/list-item'
import '@material/web/icon/icon'
import '@material/web/textfield/filled-text-field'
import '@material/web/select/filled-select'
import '@material/web/select/select-option'
import '@material/web/slider/slider'
import '@material/web/button/filled-button'
import '@material/web/button/filled-tonal-button'
import '@material/web/button/outlined-button'
import '@material/web/divider/divider'

import { registerNavigationApi } from './navigation.js'

export default function () {
// or export default async function()
// package initialization code
registerNavigationApi()
}
Loading

0 comments on commit 856a439

Please sign in to comment.