Skip to content

Commit

Permalink
enhancement: improve filters for mobile (#5994)
Browse files Browse the repository at this point in the history
* enhancement: improve filters for mobile

* chore: code conventions

---------

Co-authored-by: Jean Ribeiro <contact@jeanribeiro.dev>
Co-authored-by: Jean Ribeiro <iamjeanribeiro@gmail.com>
  • Loading branch information
3 people committed Feb 28, 2023
1 parent da8b94c commit f7a2aa0
Show file tree
Hide file tree
Showing 13 changed files with 387 additions and 6 deletions.
70 changes: 70 additions & 0 deletions packages/mobile/components/drawers/DateTimePickerDrawer.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<script lang="ts">
import SveltyPicker from 'svelty-picker'
import { Button } from '@ui'
import { localize } from '@core/i18n'
import { closeDrawer, DrawerId } from '@/auxiliary/drawer'
export let value: Date = undefined
export let startDate: Date = null
export let mode: 'auto' | 'datetime' | 'date' | 'time' = 'auto'
export let onConfirm: (value: Date) => void = () => {}
const sveltyPickerStartDate = convertDateToSveltyPickerFormat(startDate)
let sveltyPickerDate = convertDateToSveltyPickerFormat(value) ?? sveltyPickerStartDate
function convertDateToSveltyPickerFormat(date: Date): string {
return date?.toLocaleString('sv')
}
function onConfirmClick(): void {
onConfirm(new Date(sveltyPickerDate))
closeDrawer(DrawerId.DateTimePicker)
}
</script>

<datetime-picker-drawer class="w-full h-full space-y-6 flex flex-auto flex-col items-center flex-shrink-0">
<SveltyPicker
pickerOnly
autoclose
{mode}
clearBtn={false}
todayBtn={false}
startDate={sveltyPickerStartDate}
format="yyyy-mm-dd hh:ii"
theme="datetime-picker-colors"
bind:value={sveltyPickerDate}
/>
<Button onClick={onConfirmClick} classes="w-full">{localize('actions.confirm')}</Button>
</datetime-picker-drawer>

<style type="text/scss">
:global(body.scheme-dark) {
:global(.datetime-picker-colors) {
--sdt-color: theme('colors.white');
--sdt-btn-bg-hover: theme('colors.gray.800');
--sdt-btn-bg-hover: theme('colors.gray.800');
--sdt-btn-header-bg-hover: theme('colors.gray.800');
--sdt-clock-bg: theme('colors.gray.800');
--sdt-clock-bg-minute: theme('colors.gray.800');
}
}
:global(.datetime-picker-colors) {
--sdt-primary: theme('colors.blue.500');
--sdt-color: theme('colors.gray.600');
--sdt-color-selected: theme('colors.white');
--sdt-bg-main: none;
--sdt-bg-today: var(--sdt-primary);
--sdt-today-color: theme('colors.white');
--sdt-btn-bg-hover: theme('colors.gray.200');
--sdt-btn-header-bg-hover: theme('colors.gray.200');
--sdt-clock-bg: theme('colors.gray.200');
--sdt-clock-bg-minute: theme('colors.gray.200');
--sdt-clock-bg-shadow: none;
--sdt-shadow: none;
}
</style>
2 changes: 2 additions & 0 deletions packages/mobile/components/drawers/DrawerManager.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ConfirmDrawer,
CreateAccountDrawer,
CustomizeAccountDrawer,
DateTimePickerDrawer,
DeleteAccountDrawer,
EnterPasswordDrawer,
FilterDrawer,
Expand All @@ -30,6 +31,7 @@
[DrawerId.BalanceBreakdown]: BalanceBreakdownDrawer,
[DrawerId.DeleteAccount]: DeleteAccountDrawer,
[DrawerId.Filter]: FilterDrawer,
[DrawerId.DateTimePicker]: DateTimePickerDrawer,
}
</script>

Expand Down
1 change: 1 addition & 0 deletions packages/mobile/components/drawers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { default as BalanceBreakdownDrawer } from './BalanceBreakdownDrawer.svel
export { default as ConfirmDrawer } from './ConfirmDrawer.svelte'
export { default as CreateAccountDrawer } from './CreateAccountDrawer.svelte'
export { default as CustomizeAccountDrawer } from './CustomizeAccountDrawer.svelte'
export { default as DateTimePickerDrawer } from './DateTimePickerDrawer.svelte'
export { default as DeleteAccountDrawer } from './DeleteAccountDrawer.svelte'
export { default as DrawerManager } from './DrawerManager.svelte'
export { default as EnterPasswordDrawer } from './EnterPasswordDrawer.svelte'
Expand Down
11 changes: 5 additions & 6 deletions packages/mobile/components/filters/FilterItem.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
<script lang="ts">
import {
FontWeight,
Text,
Toggle,
AssetFilterItem,
DateFilterItem,
NumberFilterItem,
SelectionFilterItem,
AssetFilterItem,
OrderFilterItem,
} from '@ui'
SelectionFilterItem,
} from '@components'
import { FontWeight, Text, Toggle } from '@ui'
import { localize } from '@core/i18n'
import { FilterUnit } from '@core/utils/interfaces/filter'
Expand Down
35 changes: 35 additions & 0 deletions packages/mobile/components/molecules/DateInputButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script lang="ts">
import { Icon, Text } from '@ui'
import { appSettings } from '@core/app'
import { formatDate } from '@core/i18n'
import { DrawerId, openDrawer } from '@/auxiliary/drawer'
import { Icon as IconEnum } from '@lib/auxiliary/icon'
export let value: string = undefined
export let onConfirm: (value: string) => void = () => {}
let anchor: HTMLElement
$: formattedDate = value ? formatDate(new Date(value), { dateStyle: 'short', locale: $appSettings.language }) : ''
function onShowDateTimePickerClick(): void {
openDrawer(DrawerId.DateTimePicker, { onConfirm, mode: 'date' })
}
</script>

<button
bind:this={anchor}
on:click={onShowDateTimePickerClick}
class="flex flex-row justify-between border border-solid border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 hover:border-gray-500 dark:hover:border-gray-700 text-center rounded-xl px-2 py-1"
>
<Icon width="20" height="20" classes="text-gray-500" icon={IconEnum.Calendar} />
<Text>{formattedDate}</Text>
</button>

<style lang="scss">
button {
width: 93px;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script lang="ts">
import { Radio } from '@ui'
import type { IDropdownChoice } from '@core/utils'
import { AssetFilterUnit } from '@core/utils/interfaces/filter'
import { visibleSelectedAccountAssets } from '@core/wallet'
export let filterUnit: AssetFilterUnit
const { baseCoin, nativeTokens } = $visibleSelectedAccountAssets
const choices: IDropdownChoice[] = [baseCoin, ...nativeTokens].map((choice) => ({
label: choice.metadata.name,
value: choice.id,
}))
if (!filterUnit.selected) {
filterUnit.selected = baseCoin.id
}
let selectedFilterUnit: string = filterUnit.selected
$: selectedFilterUnit, updateFilterUnit()
function updateFilterUnit(): void {
let asset = undefined
if (selectedFilterUnit === baseCoin.id) {
asset = baseCoin
} else {
asset = nativeTokens.find((_nativeToken) => _nativeToken.id === selectedFilterUnit)
}
filterUnit.selected = asset?.id || ''
}
</script>

<asset-filter-item class="flex flex-col overflow-y-auto">
{#each choices as choice}
<Radio value={choice.value} bind:group={selectedFilterUnit} label={choice.label} />
{/each}
</asset-filter-item>
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<script lang="ts">
import { DateInputButton } from '@components'
import { Icon, NumberInput, Radio, Text } from '@ui'
import { localize } from '@core/i18n'
import type { IDropdownChoice } from '@core/utils'
import { DateFilterOption, DateUnit } from '@core/utils/enums/filters'
import { DateFilterUnit } from '@core/utils/interfaces/filter'
import { Icon as IconEnum } from '@lib/auxiliary/icon'
export let filterUnit: DateFilterUnit
const choices: IDropdownChoice[] = filterUnit.choices.map((choice) => ({
label: localize(`${filterUnit.localeKey}.${choice}`),
value: choice,
}))
const unitChoices: IDropdownChoice[] = Object.keys(DateUnit).map((val) => ({
label: localize(`${filterUnit.localeKey}.${val}`),
value: val,
}))
let selectedFilterUnit: DateFilterOption = filterUnit.selected
$: selectedFilterUnit, updateFilterUnit()
function updateFilterUnit(): void {
const updated = filterUnit.selected !== selectedFilterUnit
filterUnit.selected = selectedFilterUnit
if (updated) {
switch (filterUnit.selected) {
case DateFilterOption.Equals:
case DateFilterOption.After:
case DateFilterOption.AfterOrEquals:
case DateFilterOption.Before:
filterUnit.subunit = {
type: 'single',
value: undefined,
}
break
case DateFilterOption.Range:
filterUnit.subunit = {
type: 'range',
start: undefined,
end: undefined,
}
break
case DateFilterOption.Last:
filterUnit.subunit = {
type: 'unit',
amount: '0',
unit: DateUnit.Days,
}
break
}
}
}
function updateSubunitStart(value: string): void {
if (filterUnit.subunit.type === 'range') {
filterUnit.subunit.start = value
}
}
function updateSubunitEnd(value: string): void {
if (filterUnit.subunit.type === 'range') {
filterUnit.subunit.end = value
}
}
function updateSubunitValue(value: string): void {
if (filterUnit.subunit.type === 'single') {
filterUnit.subunit.value = value
}
}
</script>

<date-filter-options class="flex flex-col overflow-y-auto">
{#each choices as choice}
<Radio value={choice.value} bind:group={selectedFilterUnit} label={choice.label} />
{/each}
</date-filter-options>

{#if filterUnit.selected}
<div class="flex flex-row items-center space-x-2 mt-2">
{#if filterUnit.selected !== DateFilterOption.Range}
<Icon height="24" width="20" icon={IconEnum.ArrowRight} />
{/if}
{#if filterUnit.subunit.type === 'range'}
<DateInputButton value={filterUnit.subunit.start} onConfirm={updateSubunitStart} />
<Text>{localize('general.and')}</Text>
<DateInputButton value={filterUnit.subunit.end} onConfirm={updateSubunitEnd} />
{:else if filterUnit.subunit.type === 'single'}
<DateInputButton value={filterUnit.subunit.value} onConfirm={updateSubunitValue} />
{:else if filterUnit.subunit.type === 'unit'}
<NumberInput bind:value={filterUnit.subunit.amount} placeholder="" />
<date-filter-subunit-options class="flex flex-col overflow-y-auto flex-shrink-0">
{#each unitChoices as choice}
<Radio value={choice.value} bind:group={filterUnit.subunit.unit} label={choice.label} />
{/each}
</date-filter-subunit-options>
{/if}
</div>
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<script lang="ts">
import { Icon, NumberInput, Radio, Text } from '@ui'
import { localize } from '@core/i18n'
import type { IDropdownChoice } from '@core/utils'
import { NumberFilterOption } from '@core/utils/enums/filters'
import { NumberFilterUnit } from '@core/utils/interfaces/filter'
import { Icon as IconEnum } from '@lib/auxiliary/icon'
export let filterUnit: NumberFilterUnit
const choices: IDropdownChoice[] = filterUnit.choices.map((choice) => ({
label: localize(`${filterUnit.localeKey}.${choice}`),
value: choice,
}))
let selectedFilterUnit: NumberFilterOption = filterUnit.selected
$: selectedFilterUnit, updateFilterUnit()
function updateFilterUnit(): void {
const updated = filterUnit.selected !== selectedFilterUnit
filterUnit.selected = selectedFilterUnit
if (updated) {
switch (filterUnit.selected) {
case NumberFilterOption.Equal:
case NumberFilterOption.Greater:
case NumberFilterOption.Less:
filterUnit.subunit = {
type: 'single',
amount: '',
}
break
case NumberFilterOption.Range:
filterUnit.subunit = {
type: 'range',
start: '',
end: '',
}
break
}
}
}
</script>

<number-filter-options class="flex flex-col overflow-y-auto">
{#each choices as choice}
<Radio value={choice.value} bind:group={selectedFilterUnit} label={choice.label} />
{/each}
</number-filter-options>

{#if filterUnit.selected}
<div class="flex flex-row items-center space-x-2 mt-2">
<Icon height="24" width="20" icon={IconEnum.ArrowRight} />
{#if filterUnit.subunit.type === 'range'}
<NumberInput bind:value={filterUnit.subunit.start} autofocus placeholder="" />
<Text>{localize('general.and')}</Text>
<NumberInput bind:value={filterUnit.subunit.end} placeholder="" />
{:else}
<NumberInput bind:value={filterUnit.subunit.amount} autofocus placeholder="" />
{/if}
</div>
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script lang="ts">
import { HR, Radio } from '@ui'
import { localize } from '@core/i18n'
import type { IDropdownChoice } from '@core/utils'
import { OrderOption } from '@core/utils/enums/filters'
import { OrderFilterUnit } from '@core/utils/interfaces/filter'
export let filterUnit: OrderFilterUnit
const choices: IDropdownChoice[] = filterUnit.choices.map((choice) => ({
label: localize(`${filterUnit.localeKey}.${choice}`),
value: choice,
}))
const ascDescChoices: IDropdownChoice[] = [OrderOption.Asc, OrderOption.Desc].map((choice) => ({
label: localize(`filters.ascDesc.${choice}`),
value: choice,
}))
</script>

<order-filter-item class="flex flex-col justify-between space-y-2">
<div>
{#each choices as choice}
<Radio value={choice.value} bind:group={filterUnit.selected} label={choice.label} />
{/each}
</div>
<HR />
<div>
{#each ascDescChoices as choice}
<Radio value={choice.value} bind:group={filterUnit.ascDesc} label={choice.label} />
{/each}
</div>
</order-filter-item>

0 comments on commit f7a2aa0

Please sign in to comment.