Add layout shells, desktop views, module-level page caches, and UI fixes for auth, home, wallet, transactions, address, and related pages. Co-authored-by: Cursor <cursoragent@cursor.com>
127 lines
3.8 KiB
Vue
127 lines
3.8 KiB
Vue
<template>
|
||
<div class="dtxn">
|
||
<div class="dtxn__container">
|
||
<header class="dtxn-topbar">
|
||
<p class="dtxn-topbar__eyebrow">گزارشها</p>
|
||
<h1 class="dtxn-topbar__title">تراکنشها</h1>
|
||
</header>
|
||
|
||
<div class="dtxn-toolbar">
|
||
<div class="dtxn-tabs">
|
||
<button
|
||
v-for="tab in BOURSECU_TRANSACTION_TABS"
|
||
:key="tab.id"
|
||
type="button"
|
||
class="dtxn-tabs__btn"
|
||
:class="{ 'dtxn-tabs__btn--active': activeTabId === tab.id }"
|
||
@click="setActiveTab(tab.id)"
|
||
>
|
||
{{ tab.label }}
|
||
</button>
|
||
</div>
|
||
|
||
<div v-if="activeTab.showTradeToggle" class="dtxn-toggle">
|
||
<button
|
||
type="button"
|
||
class="dtxn-toggle__btn"
|
||
:class="{ 'dtxn-toggle__btn--active': tradeSide === 'buy' }"
|
||
@click="setTradeSide('buy')"
|
||
>
|
||
خرید
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="dtxn-toggle__btn"
|
||
:class="{ 'dtxn-toggle__btn--active': tradeSide === 'sell' }"
|
||
@click="setTradeSide('sell')"
|
||
>
|
||
فروش
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dtxn-filters">
|
||
<div class="dtxn-filters__label">
|
||
<BasicIcon icon="vuesax-linear:filter" size="16" />
|
||
<span>فیلترها:</span>
|
||
</div>
|
||
<a-select
|
||
v-model:value="statusFilter"
|
||
allow-clear
|
||
class="dtxn-filters__select"
|
||
placeholder="وضعیت"
|
||
size="large"
|
||
@change="applyInlineFilters"
|
||
>
|
||
<a-select-option value="active">فعال</a-select-option>
|
||
<a-select-option value="inactive">غیرفعال</a-select-option>
|
||
</a-select>
|
||
<BaseDatePicker
|
||
v-model:value="dateFilter"
|
||
class="dtxn-filters__date"
|
||
placeholder="تاریخ"
|
||
size="large"
|
||
@onchange="applyInlineFilters"
|
||
/>
|
||
</div>
|
||
|
||
<div ref="listRef" :class="loading ? 'min-h-[40vh]' : ''" class="mt-5">
|
||
<div v-if="!loading" class="dtxn-list">
|
||
<list-anim>
|
||
<Item
|
||
v-for="item in items"
|
||
:key="item.id"
|
||
:item="item"
|
||
variant="desktop"
|
||
/>
|
||
</list-anim>
|
||
<div :ref="bindDesktopObserver" class="w-full opacity-0 relative">
|
||
در حال بارگذاری
|
||
</div>
|
||
<TransactionSkeleton v-if="loadingMore" class="mt-1 mb-8" />
|
||
</div>
|
||
|
||
<template v-else>
|
||
<TransactionSkeleton v-for="i in 8" :key="i" class="mt-1" />
|
||
</template>
|
||
|
||
<div v-if="!loading && items.length === 0" class="dtxn-empty">
|
||
<img :src="emptyImage" alt="" class="dtxn-empty__image" />
|
||
<p class="dtxn-empty__text">{{ emptyText }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { ref } from 'vue'
|
||
import { loading, loadingMore } from '@/utils'
|
||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker/src/BaseDatePicker.vue'
|
||
import ListAnim from '@/components/ListAnim.vue'
|
||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||
import emptyImage from '@/assets/img/cash_empty.svg'
|
||
import Item from '../components/Item.vue'
|
||
import { BOURSECU_TRANSACTION_TABS } from '../config/boursecuTabs'
|
||
import { useTransactionsPageContext } from '../composables/useTransactionsPage'
|
||
|
||
const listRef = ref<HTMLElement | null>(null)
|
||
|
||
const {
|
||
items,
|
||
dateFilter,
|
||
statusFilter,
|
||
activeTabId,
|
||
tradeSide,
|
||
activeTab,
|
||
emptyText,
|
||
setActiveTab,
|
||
setTradeSide,
|
||
applyInlineFilters,
|
||
bindDesktopObserver,
|
||
} = useTransactionsPageContext()
|
||
</script>
|
||
|
||
<style lang="less" src="./styles/desktop-transactions.less"></style>
|