Skip to content

Commit

Permalink
feat(other): advanced routing panel in other tab
Browse files Browse the repository at this point in the history
  • Loading branch information
jacob-xhio committed Mar 15, 2024
1 parent bd39629 commit 5764694
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 2 deletions.
7 changes: 6 additions & 1 deletion client-app/src/desktop/AppModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,12 @@ export class AppModel extends HoistAppModel {
{name: 'pinPad', path: '/pinPad'},
{name: 'placeholder', path: '/placeholder'},
{name: 'popups', path: '/popups'},
{name: 'timestamp', path: '/timestamp'}
{name: 'timestamp', path: '/timestamp'},
{
name: 'advancedRouting',
path: '/advancedRouting',
children: [{name: 'routeParam', path: '/:routeParam'}]
}
]
},
{
Expand Down
4 changes: 3 additions & 1 deletion client-app/src/desktop/tabs/other/OtherTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {pinPadPanel} from './PinPadPanel';
import {placeholderPanel} from './PlaceholderPanel';
import {popupsPanel} from './PopupsPanel';
import {relativeTimestampPanel} from './relativetimestamp/RelativeTimestampPanel';
import {advancedRoutingPanel} from './routing/AdvancedRoutingPanel';

export const otherTab = hoistCmp.factory(() =>
tabContainer({
Expand Down Expand Up @@ -44,7 +45,8 @@ export const otherTab = hoistCmp.factory(() =>
{id: 'pinPad', title: 'PIN Pad', content: pinPadPanel},
{id: 'placeholder', title: 'Placeholder', content: placeholderPanel},
{id: 'popups', content: popupsPanel},
{id: 'timestamp', content: relativeTimestampPanel}
{id: 'timestamp', content: relativeTimestampPanel},
{id: 'advancedRouting', content: advancedRoutingPanel}
]
},
className: 'toolbox-tab'
Expand Down
171 changes: 171 additions & 0 deletions client-app/src/desktop/tabs/other/routing/AdvancedRoutingPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import {HoistModel, hoistCmp, creates, XH} from '@xh/hoist/core';
import {grid, gridCountLabel, GridModel} from '@xh/hoist/cmp/grid';
import {action, observable, makeObservable} from '@xh/hoist/mobx';
import {panel} from '@xh/hoist/desktop/cmp/panel';
import {wrapper} from '../../../common';
import React from 'react';
import {Icon} from '@xh/hoist/icon';
import {filler, hbox, hframe, span, vbox, vframe} from '@xh/hoist/cmp/layout';
import {colAutosizeButton, refreshButton} from '@xh/hoist/desktop/cmp/button';
import {select} from '@xh/hoist/desktop/cmp/input';

export const advancedRoutingPanel = hoistCmp.factory({
displayName: 'AdvancedRoutingPanel',
model: creates(() => new AdvancedRoutingPanelModel()),

render({model}) {
return wrapper({
description: [
<p>
This example demonstrates how to use URL route parameters to store and restore
the state of a component. The state of the grid (grouping, sorting, and selected
record) is stored in the URL, and the state is restored when the URL is
revisited.
</p>,
<p>
The state is encoded in the URL as a <code>base64</code> string, which is then
decoded and parsed to restore the state.
</p>,
<p>
The current state encoding is: <br />
<code>{'{'}</code>
<br />
<code>groupBy: {model.groupBy || 'None'}</code>
<br />
<code>sortBy: {model.sortBy || 'None'}</code>
<br />
<code>selectedId: {model.gridModel.selectedRecord?.id || 'None'}</code>
<br />
<code>{'}'}</code>
</p>,
<p></p>
],
item: panel({
ref: model.panelRef,
mask: 'onLoad',
item: hframe(
vframe(
grid(),
hbox({
items: [Icon.info()],
className: 'tb-sample-grid__selbar'
})
)
),
tbar: [
refreshButton(),
colAutosizeButton(),
span('Group by:'),
select({
bind: 'groupBy',
options: [
{value: 'city', label: 'City'},
{value: 'trade_date', label: 'Trade Date'},
{value: 'city,trade_date', label: 'City › Trade Date'},
{value: null, label: 'None'}
],
width: 160
}),
span('Sort by:'),
select({
bind: 'sortBy',
options: [
{value: 'id|desc', label: 'Company ID (Desc)'},
{value: 'id|asc', label: 'Company ID (Asc)'},
{value: 'company|desc', label: 'Company Name (Desc)'},
{value: 'company|asc', label: 'Company Name (Asc)'},
{value: 'city|desc', label: 'City (Desc)'},
{value: 'city|asc', label: 'City (Asc)'},
{value: 'trade_date|desc', label: 'Trade Date (Desc)'},
{value: 'trade_date|asc', label: 'Trade Date (Asc)'},
{value: null, label: 'None'}
]
}),
filler(),
gridCountLabel({unit: 'companies'}),
vbox({})
]
})
});
}
});

class AdvancedRoutingPanelModel extends HoistModel {
@observable groupBy = null;
@observable sortBy = null;

constructor() {
super();
makeObservable(this);

this.addReaction({
track: () => XH.routerState.params,
run: () => this.parseRouteParams(),
fireImmediately: true
});

this.addReaction({
track: () => [this.groupBy, this.sortBy, this.gridModel.selectedRecord?.id],
run: () => this.updateRoute(),
fireImmediately: true
});
}

gridModel = new GridModel({
columns: [
{field: 'id', flex: 0},
{field: 'company', flex: 1},
{field: 'city', flex: 1},
{field: 'trade_date', flex: 1}
]
});

@action
private setGroupBy(groupBy: string) {
this.groupBy = groupBy;

// Always select first when regrouping.
const groupByArr = groupBy ? groupBy.split(',') : [];
this.gridModel.setGroupBy(groupByArr);
}

@action
private setSortBy(sortBy: string) {
this.sortBy = sortBy;

// Always select first when resorting.
const sortByArr = sortBy ? sortBy.split(',') : [];
this.gridModel.setSortBy(sortByArr);
}

@action
private async setSelected(recordId: string | number) {
await this.gridModel.selectAsync(Number(recordId));
}

@action
private async parseRouteParams() {
const advParam = XH.routerState.params.routeParam;
if (!advParam) return;
const decodedParam = atob(advParam);
const {groupBy, sortBy, selectedId} = JSON.parse(decodedParam);
if (groupBy) this.setGroupBy(groupBy);
if (sortBy) this.setSortBy(sortBy);
if (selectedId) await this.setSelected(selectedId);
}

@action
private updateRoute() {
if (!XH.routerState.name.startsWith('default.other.advancedRouting')) return;
const {groupBy, sortBy} = this;
const selectedId = this.gridModel.selectedRecord?.id;
const routeParam = btoa(JSON.stringify({groupBy, sortBy, selectedId}));
XH.navigate('default.other.advancedRouting.routeParam', {routeParam});
}

override async doLoadAsync(loadSpec) {
const {trades} = await XH.fetchJson({url: 'trade'});
this.gridModel.loadData(trades);
await this.parseRouteParams();
}
}

0 comments on commit 5764694

Please sign in to comment.