Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhancement: improve filters for mobile #5994

Merged
merged 3 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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>