1719 lines
46 KiB
Vue
1719 lines
46 KiB
Vue
|
|
<template>
|
||
|
|
<q-page class="ris-activity-page">
|
||
|
|
<!-- Azioni rapide -->
|
||
|
|
<!-- Azioni RIS -->
|
||
|
|
<section class="ris-actions-section">
|
||
|
|
<div class="ris-actions-grid">
|
||
|
|
<q-btn
|
||
|
|
unelevated
|
||
|
|
rounded
|
||
|
|
class="ris-action-btn send-btn"
|
||
|
|
icon="arrow_upward"
|
||
|
|
label="Invia RIS"
|
||
|
|
@click="handleSend"
|
||
|
|
/>
|
||
|
|
<q-btn
|
||
|
|
unelevated
|
||
|
|
rounded
|
||
|
|
class="ris-action-btn receive-btn"
|
||
|
|
icon="arrow_downward"
|
||
|
|
label="Ricevi RIS"
|
||
|
|
@click="handleReceive"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<section class="quick-actions-section">
|
||
|
|
<div class="quick-actions-grid">
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
class="quick-action-btn"
|
||
|
|
:class="{ active: selectedTab === 'transactions' }"
|
||
|
|
@click="changeTab('transactions')"
|
||
|
|
>
|
||
|
|
<div class="column items-center q-gutter-y-xs">
|
||
|
|
<q-icon
|
||
|
|
name="swap_vert"
|
||
|
|
size="28px"
|
||
|
|
/>
|
||
|
|
<span>Invia Ricevi</span>
|
||
|
|
</div>
|
||
|
|
</q-btn>
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
class="quick-action-btn"
|
||
|
|
:class="{ active: selectedTab === 'statistics' }"
|
||
|
|
@click="changeTab('statistics')"
|
||
|
|
>
|
||
|
|
<div class="column items-center q-gutter-y-xs">
|
||
|
|
<q-icon
|
||
|
|
name="bar_chart"
|
||
|
|
size="28px"
|
||
|
|
/>
|
||
|
|
<span>Stat</span>
|
||
|
|
</div>
|
||
|
|
</q-btn>
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
class="quick-action-btn"
|
||
|
|
:class="{ active: selectedTab === 'circuits' }"
|
||
|
|
@click="changeTab('circuits')"
|
||
|
|
>
|
||
|
|
<div class="column items-center q-gutter-y-xs">
|
||
|
|
<q-icon
|
||
|
|
name="account_balance"
|
||
|
|
size="28px"
|
||
|
|
/>
|
||
|
|
<span>Circuiti</span>
|
||
|
|
</div>
|
||
|
|
</q-btn>
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
class="quick-action-btn"
|
||
|
|
@click="changeTab('settings')"
|
||
|
|
>
|
||
|
|
<div class="column items-center q-gutter-y-xs">
|
||
|
|
<q-icon
|
||
|
|
name="settings"
|
||
|
|
size="28px"
|
||
|
|
/>
|
||
|
|
<span>Impostazioni</span>
|
||
|
|
</div>
|
||
|
|
</q-btn>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<!-- Tab: Transazioni -->
|
||
|
|
<div
|
||
|
|
v-show="selectedTab === 'transactions'"
|
||
|
|
class="tab-content"
|
||
|
|
>
|
||
|
|
<!-- Circuiti abilitati -->
|
||
|
|
<div class="circuits-header">
|
||
|
|
<h2 class="section-title">Circuiti Abilitati:</h2>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="circuits-tabs">
|
||
|
|
<div
|
||
|
|
v-for="circuit in userCircuits"
|
||
|
|
:key="circuit.id"
|
||
|
|
class="circuit-tab"
|
||
|
|
:class="{ active: selectedCircuit?.id === circuit.id }"
|
||
|
|
@click="selectCircuit(circuit)"
|
||
|
|
>
|
||
|
|
<div class="circuit-tab-header">
|
||
|
|
<div class="circuit-tab-name">{{ circuit.name }}</div>
|
||
|
|
<q-badge
|
||
|
|
:color="circuit.isNational ? 'primary' : 'secondary'"
|
||
|
|
class="circuit-badge"
|
||
|
|
>
|
||
|
|
{{ circuit.type }}
|
||
|
|
</q-badge>
|
||
|
|
</div>
|
||
|
|
<div class="circuit-tab-balance">
|
||
|
|
{{ circuit.balance }} <span class="currency">RIS</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<q-btn
|
||
|
|
outline
|
||
|
|
color="blue"
|
||
|
|
rounded
|
||
|
|
class="explore-btn"
|
||
|
|
@click="viewCircuits()"
|
||
|
|
>
|
||
|
|
<q-icon name="explore" />
|
||
|
|
<span>Esplora altri circuiti</span>
|
||
|
|
</q-btn>
|
||
|
|
|
||
|
|
<!-- Statistiche del circuito selezionato -->
|
||
|
|
<div class="statistics-section">
|
||
|
|
<h3 class="stats-title">Statistiche {{ selectedCircuit?.name }}</h3>
|
||
|
|
<div class="wallet-transactions">
|
||
|
|
<div class="transaction-stat total">
|
||
|
|
<q-icon
|
||
|
|
name="repeat"
|
||
|
|
size="sm"
|
||
|
|
/>
|
||
|
|
<span class="stat-number">{{ currentCircuitData.totalTransactions }}</span>
|
||
|
|
<span class="stat-label">Transazioni</span>
|
||
|
|
</div>
|
||
|
|
<div class="transaction-stat members">
|
||
|
|
<q-icon
|
||
|
|
name="people"
|
||
|
|
size="sm"
|
||
|
|
/>
|
||
|
|
<span class="stat-number">{{ currentCircuitData.uniqueMembers }}</span>
|
||
|
|
<span class="stat-label">Membri coinvolti</span>
|
||
|
|
</div>
|
||
|
|
<div class="transaction-stat sent">
|
||
|
|
<q-icon
|
||
|
|
name="arrow_upward"
|
||
|
|
size="sm"
|
||
|
|
/>
|
||
|
|
<span class="stat-number">{{ currentCircuitData.sentCount }}</span>
|
||
|
|
<span class="stat-label">Inviate</span>
|
||
|
|
</div>
|
||
|
|
<div class="transaction-stat received">
|
||
|
|
<q-icon
|
||
|
|
name="arrow_downward"
|
||
|
|
size="sm"
|
||
|
|
/>
|
||
|
|
<span class="stat-number">{{ currentCircuitData.receivedCount }}</span>
|
||
|
|
<span class="stat-label">Ricevute</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Feed attività -->
|
||
|
|
<div class="activity-feed">
|
||
|
|
<q-infinite-scroll
|
||
|
|
@load="loadMoreTransactions"
|
||
|
|
:offset="250"
|
||
|
|
>
|
||
|
|
<!-- Gruppo per data -->
|
||
|
|
<div
|
||
|
|
v-for="group in groupedTransactions"
|
||
|
|
:key="group.date"
|
||
|
|
class="date-group"
|
||
|
|
>
|
||
|
|
<div class="date-header">{{ group.date }}</div>
|
||
|
|
|
||
|
|
<div
|
||
|
|
v-for="tx in group.transactions"
|
||
|
|
:key="tx.id"
|
||
|
|
class="activity-card"
|
||
|
|
@click="viewTransactionDetail(tx)"
|
||
|
|
>
|
||
|
|
<div class="activity-icon-wrapper">
|
||
|
|
<q-avatar
|
||
|
|
:color="tx.type === 'sent' ? 'red-4' : 'green-4'"
|
||
|
|
text-color="white"
|
||
|
|
size="48px"
|
||
|
|
>
|
||
|
|
<q-icon :name="tx.type === 'sent' ? 'send' : 'download'" />
|
||
|
|
</q-avatar>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="activity-content">
|
||
|
|
<div class="activity-title">
|
||
|
|
{{ tx.type === 'sent' ? 'Inviato a' : 'Ricevuto da' }}
|
||
|
|
<strong>{{ tx.otherUser }}</strong>
|
||
|
|
</div>
|
||
|
|
<div class="activity-meta">
|
||
|
|
<span>{{ tx.time }}</span>
|
||
|
|
<span>•</span>
|
||
|
|
<span>{{ tx.circuitName }}</span>
|
||
|
|
</div>
|
||
|
|
<div
|
||
|
|
v-if="tx.description"
|
||
|
|
class="activity-description"
|
||
|
|
>
|
||
|
|
{{ tx.description }}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div
|
||
|
|
class="activity-amount"
|
||
|
|
:class="tx.type"
|
||
|
|
>
|
||
|
|
<div class="amount-value">
|
||
|
|
{{ tx.type === 'sent' ? '-' : '+' }}{{ tx.amount }}
|
||
|
|
</div>
|
||
|
|
<div class="amount-currency">RIS</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<template v-slot:loading>
|
||
|
|
<div class="loading-indicator">
|
||
|
|
<q-spinner-dots
|
||
|
|
size="40px"
|
||
|
|
color="primary"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
</q-infinite-scroll>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Empty state -->
|
||
|
|
<div
|
||
|
|
v-if="!hasTransactions"
|
||
|
|
class="empty-state"
|
||
|
|
>
|
||
|
|
<q-icon
|
||
|
|
name="receipt_long"
|
||
|
|
size="64px"
|
||
|
|
color="grey-5"
|
||
|
|
/>
|
||
|
|
<p>Nessuna transazione ancora</p>
|
||
|
|
<q-btn
|
||
|
|
outline
|
||
|
|
color="primary"
|
||
|
|
@click="handleSend()"
|
||
|
|
>Inizia a scambiare RIS</q-btn
|
||
|
|
>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Tab: Statistiche -->
|
||
|
|
<div
|
||
|
|
v-show="selectedTab === 'statistics'"
|
||
|
|
class="tab-content"
|
||
|
|
>
|
||
|
|
<div class="section-header">
|
||
|
|
<h2 class="section-title">Statistiche Dettagliate</h2>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!--<div
|
||
|
|
v-for="circuit in userCircuits"
|
||
|
|
:key="circuit.id"
|
||
|
|
class="stats-card"
|
||
|
|
>
|
||
|
|
<div class="stats-card-header">
|
||
|
|
<h3>{{ circuit.name }}</h3>
|
||
|
|
<q-badge :color="circuit.isNational ? 'primary' : 'secondary'">
|
||
|
|
{{ circuit.type }}
|
||
|
|
</q-badge>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="stats-grid">
|
||
|
|
<div class="stat-item">
|
||
|
|
<q-icon
|
||
|
|
name="account_balance_wallet"
|
||
|
|
size="32px"
|
||
|
|
color="primary"
|
||
|
|
/>
|
||
|
|
<div class="stat-content">
|
||
|
|
<div class="stat-label">Saldo Attuale</div>
|
||
|
|
<div class="stat-value">{{ circuit.balance }} RIS</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="stat-item">
|
||
|
|
<q-icon
|
||
|
|
name="trending_up"
|
||
|
|
size="32px"
|
||
|
|
color="green"
|
||
|
|
/>
|
||
|
|
<div class="stat-content">
|
||
|
|
<div class="stat-label">Totale Ricevuto</div>
|
||
|
|
<div class="stat-value">{{ circuit.totalReceived || 0 }} RIS</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="stat-item">
|
||
|
|
<q-icon
|
||
|
|
name="trending_down"
|
||
|
|
size="32px"
|
||
|
|
color="red"
|
||
|
|
/>
|
||
|
|
<div class="stat-content">
|
||
|
|
<div class="stat-label">Totale Inviato</div>
|
||
|
|
<div class="stat-value">{{ circuit.totalSent || 0 }} RIS</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="stat-item">
|
||
|
|
<q-icon
|
||
|
|
name="repeat"
|
||
|
|
size="32px"
|
||
|
|
color="orange"
|
||
|
|
/>
|
||
|
|
<div class="stat-content">
|
||
|
|
<div class="stat-label">Transazioni</div>
|
||
|
|
<div class="stat-value">{{ circuit.transactionCount || 0 }}</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="stat-item">
|
||
|
|
<q-icon
|
||
|
|
name="people"
|
||
|
|
size="32px"
|
||
|
|
color="purple"
|
||
|
|
/>
|
||
|
|
<div class="stat-content">
|
||
|
|
<div class="stat-label">Contatti Attivi</div>
|
||
|
|
<div class="stat-value">{{ circuit.activeContacts || 0 }}</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="stat-item">
|
||
|
|
<q-icon
|
||
|
|
name="calendar_today"
|
||
|
|
size="32px"
|
||
|
|
color="blue"
|
||
|
|
/>
|
||
|
|
<div class="stat-content">
|
||
|
|
<div class="stat-label">Membro da</div>
|
||
|
|
<div class="stat-value">{{ circuit.memberSince || '-' }}</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>-->
|
||
|
|
|
||
|
|
<div class="wallet-card">
|
||
|
|
<!-- Saldi compatti circuito selezionato -->
|
||
|
|
<div class="wallet-balances-compact">
|
||
|
|
<CRISBalanceBar
|
||
|
|
:current-balance="currentCircuitData.realBalance"
|
||
|
|
:min-limit="currentCircuitData.trustLimit"
|
||
|
|
:max-limit="currentCircuitData.maxAccumulation"
|
||
|
|
:label="currentCircuitData.title"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Ultime 3 transazioni del circuito selezionato -->
|
||
|
|
<!-- SOSTITUISCI la sezione recent-transactions -->
|
||
|
|
|
||
|
|
<div class="recent-transactions">
|
||
|
|
<div class="transactions-header">
|
||
|
|
<h4 class="transactions-title">Ultimi Scambi</h4>
|
||
|
|
<q-btn-toggle
|
||
|
|
v-model="transactionsView"
|
||
|
|
dense
|
||
|
|
no-caps
|
||
|
|
unelevated
|
||
|
|
rounded
|
||
|
|
size="md"
|
||
|
|
toggle-color="primary"
|
||
|
|
:options="[
|
||
|
|
{ label: 'Personali', value: 'mine' },
|
||
|
|
{ label: 'Della Community', value: 'all' },
|
||
|
|
]"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Tue Transazioni -->
|
||
|
|
<div
|
||
|
|
v-if="transactionsView === 'mine'"
|
||
|
|
class="transaction-list"
|
||
|
|
>
|
||
|
|
<div
|
||
|
|
v-for="(tx, idx) in currentCircuitData.recentTransactions.slice(0, 3)"
|
||
|
|
:key="idx"
|
||
|
|
class="transaction-item"
|
||
|
|
@click="openTransaction(tx)"
|
||
|
|
>
|
||
|
|
<q-avatar
|
||
|
|
size="32px"
|
||
|
|
:color="tx.amount > 0 ? 'positive' : 'negative'"
|
||
|
|
text-color="white"
|
||
|
|
>
|
||
|
|
{{ tx.userInitial }}
|
||
|
|
</q-avatar>
|
||
|
|
<div class="transaction-content">
|
||
|
|
<span class="transaction-desc">{{ tx.description }}</span>
|
||
|
|
<span class="transaction-time">{{ tx.time }}</span>
|
||
|
|
</div>
|
||
|
|
<span
|
||
|
|
:class="['transaction-amount', tx.amount > 0 ? 'positive' : 'negative']"
|
||
|
|
>
|
||
|
|
{{ tx.amount > 0 ? '+' : '' }}{{ tx.amount }}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Transazioni Community -->
|
||
|
|
<div
|
||
|
|
v-if="transactionsView === 'all'"
|
||
|
|
class="transaction-list"
|
||
|
|
>
|
||
|
|
<div
|
||
|
|
v-for="(tx, idx) in allTransactions.slice(0, 3)"
|
||
|
|
:key="idx"
|
||
|
|
class="transaction-item"
|
||
|
|
@click="openTransaction(tx)"
|
||
|
|
>
|
||
|
|
<div class="transaction-users">
|
||
|
|
<q-avatar
|
||
|
|
size="28px"
|
||
|
|
color="primary"
|
||
|
|
text-color="white"
|
||
|
|
>
|
||
|
|
{{ tx.fromInitial }}
|
||
|
|
</q-avatar>
|
||
|
|
<q-icon
|
||
|
|
name="arrow_forward"
|
||
|
|
size="xs"
|
||
|
|
color="grey-6"
|
||
|
|
/>
|
||
|
|
<q-avatar
|
||
|
|
size="28px"
|
||
|
|
color="secondary"
|
||
|
|
text-color="white"
|
||
|
|
>
|
||
|
|
{{ tx.toInitial }}
|
||
|
|
</q-avatar>
|
||
|
|
</div>
|
||
|
|
<div class="transaction-content">
|
||
|
|
<span class="transaction-desc">{{ tx.fromName }} → {{ tx.toName }}</span>
|
||
|
|
<span class="transaction-time">{{ tx.time }}</span>
|
||
|
|
</div>
|
||
|
|
<span class="transaction-amount community">
|
||
|
|
{{ tx.amount > 0 ? '+' : '' }}{{ tx.amount }}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Focus su attività di scambio -->
|
||
|
|
<q-btn
|
||
|
|
unelevated
|
||
|
|
rounded
|
||
|
|
class="wallet-detail-btn"
|
||
|
|
label="Dettaglio Transazioni"
|
||
|
|
icon-right="arrow_forward"
|
||
|
|
@click="goToTransactions"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Tab: I miei Circuiti -->
|
||
|
|
<div
|
||
|
|
v-show="selectedTab === 'circuits'"
|
||
|
|
class="tab-content"
|
||
|
|
>
|
||
|
|
<div class="section-header row justify-center">
|
||
|
|
<q-btn-toggle
|
||
|
|
v-model="selectedCirc"
|
||
|
|
dense
|
||
|
|
no-caps
|
||
|
|
unelevated
|
||
|
|
rounded
|
||
|
|
size="md"
|
||
|
|
toggle-color="primary"
|
||
|
|
:options="[
|
||
|
|
{ label: 'I miei Circuiti', value: 'mycircuits', icon: 'account_box' },
|
||
|
|
{ label: 'Tutti i Circuiti', value: 'allcircuits', icon: 'view_list' },
|
||
|
|
]"
|
||
|
|
class="dual-btns q-ma-sm q-pa-sm"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div
|
||
|
|
v-show="selectedCirc === 'mycircuits'"
|
||
|
|
class="tab-content"
|
||
|
|
>
|
||
|
|
<div
|
||
|
|
v-for="circuit in userCircuits"
|
||
|
|
:key="circuit.id"
|
||
|
|
class="circuit-card"
|
||
|
|
>
|
||
|
|
<div class="circuit-card-header">
|
||
|
|
<div class="circuit-card-title">
|
||
|
|
<h3>{{ circuit.name }}</h3>
|
||
|
|
<q-badge :color="circuit.isNational ? 'primary' : 'secondary'">
|
||
|
|
{{ circuit.type }}
|
||
|
|
</q-badge>
|
||
|
|
</div>
|
||
|
|
<div class="circuit-card-balance">
|
||
|
|
{{ circuit.balance }} <span class="currency">RIS</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="circuit-card-body">
|
||
|
|
<div class="circuit-info-row">
|
||
|
|
<q-icon
|
||
|
|
name="handshake"
|
||
|
|
size="20px"
|
||
|
|
/>
|
||
|
|
<span class="info-label">Fiducia concessa:</span>
|
||
|
|
<span class="info-value">{{ circuit.fido || 0 }} RIS</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="circuit-info-row">
|
||
|
|
<q-icon
|
||
|
|
name="savings"
|
||
|
|
size="20px"
|
||
|
|
/>
|
||
|
|
<span class="info-label">Saldo minimo:</span>
|
||
|
|
<span class="info-value">{{ circuit.minBalance || 0 }} RIS</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="circuit-info-row">
|
||
|
|
<q-icon
|
||
|
|
name="location_on"
|
||
|
|
size="20px"
|
||
|
|
/>
|
||
|
|
<span class="info-label">Tipo:</span>
|
||
|
|
<span class="info-value">{{
|
||
|
|
circuit.isNational ? 'Nazionale' : 'Provinciale'
|
||
|
|
}}</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="circuit-info-row">
|
||
|
|
<q-icon
|
||
|
|
name="people"
|
||
|
|
size="20px"
|
||
|
|
/>
|
||
|
|
<span class="info-label">Membri totali:</span>
|
||
|
|
<span class="info-value">{{ circuit.members || 0 }}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="circuit-card-actions">
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
color="primary"
|
||
|
|
icon="visibility"
|
||
|
|
label="Dettagli"
|
||
|
|
@click="viewCircuitDetails(circuit)"
|
||
|
|
/>
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
color="primary"
|
||
|
|
icon="settings"
|
||
|
|
label="Impostazioni"
|
||
|
|
@click="openCircuitSettings(circuit)"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div
|
||
|
|
v-show="selectedCirc === 'allcircuits'"
|
||
|
|
class="tab-content"
|
||
|
|
>
|
||
|
|
<div class="section-header">
|
||
|
|
<h2 class="section-title">Lista Circuiti</h2>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<div>
|
||
|
|
<span
|
||
|
|
v-for="(circuit, index) in listcircuitsfind"
|
||
|
|
:key="index"
|
||
|
|
class="q-my-sm"
|
||
|
|
clickable
|
||
|
|
>
|
||
|
|
<CMyCircuit
|
||
|
|
:mycircuit="circuit"
|
||
|
|
:visu="visu"
|
||
|
|
:username="userStore.my.username"
|
||
|
|
>
|
||
|
|
</CMyCircuit>
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<CFinder
|
||
|
|
:ind="ind"
|
||
|
|
:table="shared_consts.TABLES_CIRCUITS"
|
||
|
|
:noButtAdd="!tools.isManager()"
|
||
|
|
:showFilterPersonal="true"
|
||
|
|
:showBarSelection="false"
|
||
|
|
:labelBtnAddExtra="
|
||
|
|
ind >= 0 && tools.isManager()
|
||
|
|
? `Aggiungi ` + costanti.MAINCARDS[ind].strsingolo
|
||
|
|
: ''
|
||
|
|
"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Dialog Invia RIS -->
|
||
|
|
<q-dialog
|
||
|
|
v-model="showSendDialog"
|
||
|
|
persistent
|
||
|
|
maximized
|
||
|
|
>
|
||
|
|
<q-card class="send-dialog">
|
||
|
|
<q-card-section class="dialog-header">
|
||
|
|
<div class="dialog-title">
|
||
|
|
<q-icon
|
||
|
|
name="north_east"
|
||
|
|
size="24px"
|
||
|
|
/>
|
||
|
|
<span>Invia RIS</span>
|
||
|
|
</div>
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
round
|
||
|
|
dense
|
||
|
|
icon="close"
|
||
|
|
@click="closeSendDialog()"
|
||
|
|
/>
|
||
|
|
</q-card-section>
|
||
|
|
|
||
|
|
<q-card-section>
|
||
|
|
<q-input
|
||
|
|
v-model="sendSearch"
|
||
|
|
label="Cerca destinatario (nome, username, email)"
|
||
|
|
outlined
|
||
|
|
dense
|
||
|
|
clearable
|
||
|
|
class="q-mb-md"
|
||
|
|
@update:model-value="searchRecipients"
|
||
|
|
>
|
||
|
|
<template v-slot:prepend>
|
||
|
|
<q-icon name="search" />
|
||
|
|
</template>
|
||
|
|
</q-input>
|
||
|
|
|
||
|
|
<!--<q-select
|
||
|
|
v-model="sendCircuit"
|
||
|
|
:options="userCircuits"
|
||
|
|
option-label="name"
|
||
|
|
label="Da circuito"
|
||
|
|
outlined
|
||
|
|
dense
|
||
|
|
class="q-mb-md"
|
||
|
|
>
|
||
|
|
<template v-slot:prepend>
|
||
|
|
<q-icon name="account_balance_wallet" />
|
||
|
|
</template>
|
||
|
|
</q-select>-->
|
||
|
|
|
||
|
|
<!-- Contatti recenti -->
|
||
|
|
<div
|
||
|
|
v-if="recentContacts.length && !sendSearch"
|
||
|
|
class="contacts-section"
|
||
|
|
>
|
||
|
|
<div class="section-title">
|
||
|
|
<q-icon
|
||
|
|
name="history"
|
||
|
|
size="16px"
|
||
|
|
/>
|
||
|
|
Usati di recente
|
||
|
|
</div>
|
||
|
|
<div
|
||
|
|
v-for="contact in recentContacts"
|
||
|
|
:key="contact.id"
|
||
|
|
class="contact-item recent"
|
||
|
|
@click="selectRecipient(contact)"
|
||
|
|
>
|
||
|
|
<q-avatar
|
||
|
|
size="40px"
|
||
|
|
:color="contact.avatarColor"
|
||
|
|
text-color="white"
|
||
|
|
>
|
||
|
|
{{ contact.initials }}
|
||
|
|
</q-avatar>
|
||
|
|
<div class="contact-info">
|
||
|
|
<div class="contact-name">{{ contact.name }}</div>
|
||
|
|
<div class="contact-username">@{{ contact.username }}</div>
|
||
|
|
</div>
|
||
|
|
<q-icon
|
||
|
|
name="chevron_right"
|
||
|
|
size="20px"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Tutti i contatti -->
|
||
|
|
<div
|
||
|
|
v-if="sendSearch && filteredContacts.length"
|
||
|
|
class="contacts-section"
|
||
|
|
>
|
||
|
|
<div class="section-title">
|
||
|
|
<q-icon
|
||
|
|
name="people"
|
||
|
|
size="16px"
|
||
|
|
/>
|
||
|
|
{{ sendSearch ? 'Risultati ricerca' : 'Tutti i contatti' }}
|
||
|
|
</div>
|
||
|
|
<div class="contacts-scrollable">
|
||
|
|
<div
|
||
|
|
v-for="contact in filteredContacts"
|
||
|
|
:key="contact.id"
|
||
|
|
class="contact-item"
|
||
|
|
@click="selectRecipient(contact)"
|
||
|
|
>
|
||
|
|
<q-avatar
|
||
|
|
size="40px"
|
||
|
|
:color="contact.avatarColor"
|
||
|
|
text-color="white"
|
||
|
|
>
|
||
|
|
{{ contact.initials }}
|
||
|
|
</q-avatar>
|
||
|
|
<div class="contact-info">
|
||
|
|
<div class="contact-name">{{ contact.name }}</div>
|
||
|
|
<div class="contact-username">@{{ contact.username }}</div>
|
||
|
|
<div class="contact-email">{{ contact.email }}</div>
|
||
|
|
</div>
|
||
|
|
<q-icon
|
||
|
|
name="chevron_right"
|
||
|
|
size="20px"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div
|
||
|
|
v-if="sendSearch && !filteredContacts.length"
|
||
|
|
class="no-results"
|
||
|
|
>
|
||
|
|
<q-icon
|
||
|
|
name="search_off"
|
||
|
|
size="48px"
|
||
|
|
/>
|
||
|
|
<p>Nessun contatto trovato</p>
|
||
|
|
</div>
|
||
|
|
</q-card-section>
|
||
|
|
</q-card>
|
||
|
|
</q-dialog>
|
||
|
|
|
||
|
|
<!-- Dialog Ricevi RIS -->
|
||
|
|
<q-dialog
|
||
|
|
v-model="showReceiveDialog"
|
||
|
|
persistent
|
||
|
|
>
|
||
|
|
<q-card class="receive-dialog">
|
||
|
|
<q-card-section class="dialog-header">
|
||
|
|
<div class="dialog-title">
|
||
|
|
<q-icon
|
||
|
|
name="south_west"
|
||
|
|
size="24px"
|
||
|
|
/>
|
||
|
|
<span>Ricevi RIS</span>
|
||
|
|
</div>
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
round
|
||
|
|
dense
|
||
|
|
icon="close"
|
||
|
|
@click="closeReceiveDialog()"
|
||
|
|
/>
|
||
|
|
</q-card-section>
|
||
|
|
|
||
|
|
<q-card-section>
|
||
|
|
<q-select
|
||
|
|
v-model="receiveCircuit"
|
||
|
|
:options="userCircuits"
|
||
|
|
option-label="name"
|
||
|
|
label="Sul circuito"
|
||
|
|
outlined
|
||
|
|
dense
|
||
|
|
class="q-mb-md"
|
||
|
|
>
|
||
|
|
<template v-slot:prepend>
|
||
|
|
<q-icon name="account_balance_wallet" />
|
||
|
|
</template>
|
||
|
|
</q-select>
|
||
|
|
|
||
|
|
<div class="receive-info">
|
||
|
|
<q-icon
|
||
|
|
name="info"
|
||
|
|
color="info"
|
||
|
|
/>
|
||
|
|
<p>
|
||
|
|
Scegli da chi vuoi ricevere RIS. Il mittente dovrà confermare la
|
||
|
|
transazione.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<q-input
|
||
|
|
v-model="receiveSearch"
|
||
|
|
label="Cerca mittente (nome, username, email)"
|
||
|
|
outlined
|
||
|
|
dense
|
||
|
|
clearable
|
||
|
|
class="q-mb-md"
|
||
|
|
@update:model-value="searchSenders"
|
||
|
|
>
|
||
|
|
<template v-slot:prepend>
|
||
|
|
<q-icon name="search" />
|
||
|
|
</template>
|
||
|
|
</q-input>
|
||
|
|
|
||
|
|
<!-- Contatti per ricevere -->
|
||
|
|
<div
|
||
|
|
v-if="filteredSenders.length"
|
||
|
|
class="contacts-section"
|
||
|
|
>
|
||
|
|
<div class="section-title">
|
||
|
|
<q-icon
|
||
|
|
name="people"
|
||
|
|
size="16px"
|
||
|
|
/>
|
||
|
|
{{ receiveSearch ? 'Risultati ricerca' : 'Contatti disponibili' }}
|
||
|
|
</div>
|
||
|
|
<div class="contacts-scrollable">
|
||
|
|
<div
|
||
|
|
v-for="contact in filteredSenders"
|
||
|
|
:key="contact.id"
|
||
|
|
class="contact-item"
|
||
|
|
@click="selectSender(contact)"
|
||
|
|
>
|
||
|
|
<q-avatar
|
||
|
|
size="40px"
|
||
|
|
:color="contact.avatarColor"
|
||
|
|
text-color="white"
|
||
|
|
>
|
||
|
|
{{ contact.initials }}
|
||
|
|
</q-avatar>
|
||
|
|
<div class="contact-info">
|
||
|
|
<div class="contact-name">{{ contact.name }}</div>
|
||
|
|
<div class="contact-username">@{{ contact.username }}</div>
|
||
|
|
<div class="contact-email">{{ contact.email }}</div>
|
||
|
|
</div>
|
||
|
|
<q-icon
|
||
|
|
name="chevron_right"
|
||
|
|
size="20px"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div
|
||
|
|
v-if="receiveSearch && !filteredSenders.length"
|
||
|
|
class="no-results"
|
||
|
|
>
|
||
|
|
<q-icon
|
||
|
|
name="search_off"
|
||
|
|
size="48px"
|
||
|
|
/>
|
||
|
|
<p>Nessun contatto trovato</p>
|
||
|
|
</div>
|
||
|
|
</q-card-section>
|
||
|
|
</q-card>
|
||
|
|
</q-dialog>
|
||
|
|
|
||
|
|
<div v-if="showConfirmSendDialog">
|
||
|
|
<CSendCoins
|
||
|
|
:showprop="selectedRecipient?.username"
|
||
|
|
:circuitname="sendCircuit?.name"
|
||
|
|
:to_user="selectedRecipient"
|
||
|
|
></CSendCoins>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Dialog Conferma Invio -->
|
||
|
|
<!--<q-dialog
|
||
|
|
v-model="showConfirmSendDialog"
|
||
|
|
persistent
|
||
|
|
>
|
||
|
|
<q-card class="confirm-dialog">
|
||
|
|
<q-card-section class="dialog-header">
|
||
|
|
<div class="dialog-title">Conferma invio</div>
|
||
|
|
</q-card-section>
|
||
|
|
|
||
|
|
<q-card-section>
|
||
|
|
<div class="confirm-details">
|
||
|
|
<div class="confirm-row">
|
||
|
|
<span class="confirm-label">A:</span>
|
||
|
|
<span class="confirm-value">{{ selectedRecipient?.name }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="confirm-row">
|
||
|
|
<span class="confirm-label">Circuito:</span>
|
||
|
|
<span class="confirm-value">{{ sendCircuit?.name }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="confirm-row">
|
||
|
|
<span class="confirm-label">Saldo attuale:</span>
|
||
|
|
<span class="confirm-value">{{ sendCircuit?.balance }} RIS</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<q-input
|
||
|
|
v-model="sendAmount"
|
||
|
|
type="number"
|
||
|
|
label="Importo RIS"
|
||
|
|
outlined
|
||
|
|
class="q-mb-md"
|
||
|
|
:rules="[(val) => val > 0 || 'Inserisci un importo valido']"
|
||
|
|
>
|
||
|
|
<template v-slot:append>
|
||
|
|
<span class="input-currency">RIS</span>
|
||
|
|
</template>
|
||
|
|
</q-input>
|
||
|
|
|
||
|
|
<q-input
|
||
|
|
v-model="sendDescription"
|
||
|
|
label="Descrizione (opzionale)"
|
||
|
|
outlined
|
||
|
|
type="textarea"
|
||
|
|
rows="3"
|
||
|
|
class="q-mb-md"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<div class="confirm-result">
|
||
|
|
<span class="result-label">Nuovo saldo:</span>
|
||
|
|
<span
|
||
|
|
class="result-value"
|
||
|
|
:class="{ negative: newBalance < 0 }"
|
||
|
|
>
|
||
|
|
{{ newBalance }} RIS
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</q-card-section>
|
||
|
|
|
||
|
|
<q-card-actions
|
||
|
|
align="right"
|
||
|
|
class="q-px-md q-pb-md"
|
||
|
|
>
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
label="Annulla"
|
||
|
|
@click="cancelSend()"
|
||
|
|
/>
|
||
|
|
<q-btn
|
||
|
|
unelevated
|
||
|
|
label="Invia"
|
||
|
|
color="primary"
|
||
|
|
:disable="!sendAmount || sendAmount <= 0"
|
||
|
|
@click="confirmSend()"
|
||
|
|
/>
|
||
|
|
</q-card-actions>
|
||
|
|
</q-card>
|
||
|
|
</q-dialog>
|
||
|
|
-->
|
||
|
|
|
||
|
|
<!-- Dialog Conferma Ricezione -->
|
||
|
|
<q-dialog
|
||
|
|
v-model="showConfirmReceiveDialog"
|
||
|
|
persistent
|
||
|
|
>
|
||
|
|
<q-card class="confirm-dialog">
|
||
|
|
<q-card-section class="dialog-header">
|
||
|
|
<div class="dialog-title">Richiesta ricezione</div>
|
||
|
|
</q-card-section>
|
||
|
|
|
||
|
|
<q-card-section>
|
||
|
|
<div class="confirm-details">
|
||
|
|
<div class="confirm-row">
|
||
|
|
<span class="confirm-label">Da:</span>
|
||
|
|
<span class="confirm-value">{{ selectedSender?.name }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="confirm-row">
|
||
|
|
<span class="confirm-label">Circuito:</span>
|
||
|
|
<span class="confirm-value">{{ receiveCircuit?.name }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="confirm-row">
|
||
|
|
<span class="confirm-label">Saldo attuale:</span>
|
||
|
|
<span class="confirm-value">{{ receiveCircuit?.balance }} RIS</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<q-input
|
||
|
|
v-model="receiveAmount"
|
||
|
|
type="number"
|
||
|
|
label="Importo RIS da ricevere"
|
||
|
|
outlined
|
||
|
|
class="q-mb-md"
|
||
|
|
:rules="[(val) => val > 0 || 'Inserisci un importo valido']"
|
||
|
|
>
|
||
|
|
<template v-slot:append>
|
||
|
|
<span class="input-currency">RIS</span>
|
||
|
|
</template>
|
||
|
|
</q-input>
|
||
|
|
|
||
|
|
<q-input
|
||
|
|
v-model="receiveDescription"
|
||
|
|
label="Descrizione (opzionale)"
|
||
|
|
outlined
|
||
|
|
type="textarea"
|
||
|
|
rows="3"
|
||
|
|
class="q-mb-md"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<div class="confirm-result">
|
||
|
|
<span class="result-label">Nuovo saldo:</span>
|
||
|
|
<span class="result-value positive"> {{ newReceiveBalance }} RIS </span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="receive-note">
|
||
|
|
<q-icon
|
||
|
|
name="info"
|
||
|
|
size="18px"
|
||
|
|
/>
|
||
|
|
<span>Il mittente riceverà una notifica per confermare l'invio</span>
|
||
|
|
</div>
|
||
|
|
</q-card-section>
|
||
|
|
|
||
|
|
<q-card-actions
|
||
|
|
align="right"
|
||
|
|
class="q-px-md q-pb-md"
|
||
|
|
>
|
||
|
|
<q-btn
|
||
|
|
flat
|
||
|
|
label="Annulla"
|
||
|
|
@click="cancelReceive()"
|
||
|
|
/>
|
||
|
|
<q-btn
|
||
|
|
unelevated
|
||
|
|
label="Richiedi"
|
||
|
|
color="positive"
|
||
|
|
:disable="!receiveAmount || receiveAmount <= 0"
|
||
|
|
@click="confirmReceive()"
|
||
|
|
/>
|
||
|
|
</q-card-actions>
|
||
|
|
</q-card>
|
||
|
|
</q-dialog>
|
||
|
|
</q-page>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
import { useCircuitStore, useUserStore } from 'app/src/store';
|
||
|
|
import { useQuasar } from 'quasar';
|
||
|
|
import { ref, computed, onMounted } from 'vue';
|
||
|
|
import { useI18n } from 'vue-i18n';
|
||
|
|
import { useRouter } from 'vue-router';
|
||
|
|
|
||
|
|
import { CRISBalanceBar } from '@/components/CRISBalanceBar';
|
||
|
|
import { CSendCoins } from '@/components/CSendCoins';
|
||
|
|
import { CMyCircuit } from '@/components/CMyCircuit';
|
||
|
|
import { CFinder } from '@/components/CFinder';
|
||
|
|
import { costanti } from '@costanti';
|
||
|
|
import { shared_consts } from 'app/src/common/shared_vuejs';
|
||
|
|
import { tools } from 'app/src/store/Modules/tools';
|
||
|
|
|
||
|
|
const userStore = useUserStore();
|
||
|
|
const circuitStore = useCircuitStore();
|
||
|
|
const $q = useQuasar();
|
||
|
|
const $router = useRouter();
|
||
|
|
const { t } = useI18n();
|
||
|
|
|
||
|
|
const ind = ref(0);
|
||
|
|
|
||
|
|
const totalMembers = ref(0);
|
||
|
|
const totalTrades = ref(0);
|
||
|
|
const totalEvents = ref(0);
|
||
|
|
|
||
|
|
const totalTransactions = ref(0);
|
||
|
|
const uniqueMembers = ref(0);
|
||
|
|
const lastTradeTime = ref('Mai');
|
||
|
|
|
||
|
|
const filter = ref(costanti.FIND_CIRCUIT);
|
||
|
|
|
||
|
|
const isTest = true; // Cambia a false in produzione
|
||
|
|
|
||
|
|
const recentTrades = ref<any[]>([
|
||
|
|
// Esempio struttura:
|
||
|
|
// { userInitial: 'M', description: 'Scambio completato', time: '2h fa', amount: 50 }
|
||
|
|
]);
|
||
|
|
|
||
|
|
const allTransactions = ref<any[]>([]);
|
||
|
|
|
||
|
|
// Inizializza con dati completi
|
||
|
|
const initializeTransactions = () => {
|
||
|
|
allTransactions.value = [
|
||
|
|
{
|
||
|
|
id: '1',
|
||
|
|
type: 'sent',
|
||
|
|
amount: 50,
|
||
|
|
otherUser: 'Mario Rossi',
|
||
|
|
circuitName: 'RIS Treviso',
|
||
|
|
circuitId: '1',
|
||
|
|
description: 'Riparazione bicicletta',
|
||
|
|
date: '2024-12-02',
|
||
|
|
time: '14:30',
|
||
|
|
timestamp: new Date('2024-12-02T14:30:00'),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '2',
|
||
|
|
type: 'received',
|
||
|
|
amount: 75,
|
||
|
|
otherUser: 'Laura Bianchi',
|
||
|
|
circuitName: 'RIS Treviso',
|
||
|
|
circuitId: '1',
|
||
|
|
description: 'Lezione di inglese',
|
||
|
|
date: '2024-12-01',
|
||
|
|
time: '16:45',
|
||
|
|
timestamp: new Date('2024-12-01T16:45:00'),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '3',
|
||
|
|
type: 'sent',
|
||
|
|
amount: 30,
|
||
|
|
otherUser: 'Giuseppe Verdi',
|
||
|
|
circuitName: 'RIS Italia',
|
||
|
|
circuitId: '2',
|
||
|
|
description: '',
|
||
|
|
date: '2024-11-30',
|
||
|
|
time: '10:15',
|
||
|
|
timestamp: new Date('2024-11-30T10:15:00'),
|
||
|
|
},
|
||
|
|
];
|
||
|
|
};
|
||
|
|
|
||
|
|
// Dati wallet (da collegare allo store)
|
||
|
|
const availableBalance = ref(0); // Saldo utilizzabile (include fido)
|
||
|
|
const realBalance = ref(0); // Saldo reale effettivo
|
||
|
|
const trustLimit = ref(-100); // Fido concesso (negativo)
|
||
|
|
const maxAccumulation = ref(200); // Massimo accumulo
|
||
|
|
const receivedCount = ref(0);
|
||
|
|
const sentCount = ref(0);
|
||
|
|
|
||
|
|
const transactionsView = ref<'mine' | 'all'>('mine');
|
||
|
|
|
||
|
|
// Dati finti circuiti
|
||
|
|
const userCircuits = ref([
|
||
|
|
{
|
||
|
|
id: '1',
|
||
|
|
name: 'RIS Treviso',
|
||
|
|
type: 'Provinciale',
|
||
|
|
isNational: false,
|
||
|
|
balance: 250,
|
||
|
|
fido: 500,
|
||
|
|
minBalance: -200,
|
||
|
|
members: 87,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '2',
|
||
|
|
name: 'RIS Italia',
|
||
|
|
type: 'Nazionale',
|
||
|
|
isNational: true,
|
||
|
|
balance: -120,
|
||
|
|
fido: 1000,
|
||
|
|
minBalance: -500,
|
||
|
|
members: 1243,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '3',
|
||
|
|
name: 'RIS Veneto',
|
||
|
|
type: 'Regionale',
|
||
|
|
isNational: false,
|
||
|
|
balance: 80,
|
||
|
|
fido: 300,
|
||
|
|
minBalance: -150,
|
||
|
|
members: 234,
|
||
|
|
},
|
||
|
|
]);
|
||
|
|
|
||
|
|
const selectedCircuit = ref(userCircuits.value[0]);
|
||
|
|
|
||
|
|
// Tab selector
|
||
|
|
const selectedTab = ref('transactions');
|
||
|
|
const selectedCirc = ref('mycircuits');
|
||
|
|
|
||
|
|
const changeTab = (tab: string) => {
|
||
|
|
selectedTab.value = tab;
|
||
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||
|
|
};
|
||
|
|
|
||
|
|
const selectCircuit = (circuit: (typeof userCircuits.value)[0]) => {
|
||
|
|
selectedCircuit.value = circuit;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Statistiche del circuito corrente
|
||
|
|
const currentCircuitData = computed(() => {
|
||
|
|
const circuitId = selectedCircuit.value?.id;
|
||
|
|
const txs = allTransactions.value.filter((tx) => tx.circuitId === circuitId);
|
||
|
|
|
||
|
|
const uniqueMembersSet = new Set(txs.map((tx) => tx.otherUser)).size;
|
||
|
|
const sentCount = txs.filter((tx) => tx.type === 'sent').length;
|
||
|
|
const receivedCount = txs.filter((tx) => tx.type === 'received').length;
|
||
|
|
|
||
|
|
return {
|
||
|
|
...selectedCircuit.value,
|
||
|
|
totalTransactions: txs.length,
|
||
|
|
uniqueMembers: uniqueMembersSet,
|
||
|
|
sentCount,
|
||
|
|
receivedCount,
|
||
|
|
recentTransactions: [
|
||
|
|
{
|
||
|
|
userInitial: 'A',
|
||
|
|
description: 'Consulenza legale',
|
||
|
|
time: '3 giorni fa',
|
||
|
|
amount: -80,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
userInitial: 'F',
|
||
|
|
description: 'Prodotti artigianali',
|
||
|
|
time: '4 giorni fa',
|
||
|
|
amount: 50,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
userInitial: 'S',
|
||
|
|
description: 'Corso di cucina',
|
||
|
|
time: '5 giorni fa',
|
||
|
|
amount: -40,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
};
|
||
|
|
});
|
||
|
|
|
||
|
|
// Dati finti contatti
|
||
|
|
const allContacts = ref([
|
||
|
|
{
|
||
|
|
id: '1',
|
||
|
|
name: 'Mario Rossi',
|
||
|
|
username: 'mrossi',
|
||
|
|
email: 'mario.rossi@email.it',
|
||
|
|
initials: 'MR',
|
||
|
|
avatarColor: 'primary',
|
||
|
|
lastUsed: new Date('2024-11-28'),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '2',
|
||
|
|
name: 'Laura Bianchi',
|
||
|
|
username: 'lbianchi',
|
||
|
|
email: 'laura.b@email.it',
|
||
|
|
initials: 'LB',
|
||
|
|
avatarColor: 'secondary',
|
||
|
|
lastUsed: new Date('2024-11-25'),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '3',
|
||
|
|
name: 'Giuseppe Verdi',
|
||
|
|
username: 'gverdi',
|
||
|
|
email: 'g.verdi@email.it',
|
||
|
|
initials: 'GV',
|
||
|
|
avatarColor: 'accent',
|
||
|
|
lastUsed: new Date('2024-11-20'),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '4',
|
||
|
|
name: 'Anna Neri',
|
||
|
|
username: 'aneri',
|
||
|
|
email: 'anna.neri@email.it',
|
||
|
|
initials: 'AN',
|
||
|
|
avatarColor: 'positive',
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '5',
|
||
|
|
name: 'Paolo Ferrari',
|
||
|
|
username: 'pferrari',
|
||
|
|
email: 'p.ferrari@email.it',
|
||
|
|
initials: 'PF',
|
||
|
|
avatarColor: 'info',
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '6',
|
||
|
|
name: 'Chiara Colombo',
|
||
|
|
username: 'ccolombo',
|
||
|
|
email: 'chiara.c@email.it',
|
||
|
|
initials: 'CC',
|
||
|
|
avatarColor: 'warning',
|
||
|
|
},
|
||
|
|
]);
|
||
|
|
|
||
|
|
const recentContacts = computed(() =>
|
||
|
|
allContacts.value
|
||
|
|
.filter((c) => c.lastUsed)
|
||
|
|
.sort((a, b) => b.lastUsed!.getTime() - a.lastUsed!.getTime())
|
||
|
|
.slice(0, 3)
|
||
|
|
);
|
||
|
|
|
||
|
|
const hasTransactions = computed(() => allTransactions.value.length > 0);
|
||
|
|
|
||
|
|
// Raggruppa transazioni per data
|
||
|
|
const groupedTransactions = computed(() => {
|
||
|
|
const groups: { date: string; transactions: typeof allTransactions.value }[] = [];
|
||
|
|
const grouped = new Map<string, typeof allTransactions.value>();
|
||
|
|
|
||
|
|
// Filtra solo transazioni con timestamp valido
|
||
|
|
const validTransactions = allTransactions.value.filter((tx) => tx.timestamp);
|
||
|
|
|
||
|
|
validTransactions.forEach((tx) => {
|
||
|
|
const dateKey = formatDateHeader(tx.timestamp);
|
||
|
|
if (!grouped.has(dateKey)) {
|
||
|
|
grouped.set(dateKey, []);
|
||
|
|
}
|
||
|
|
grouped.get(dateKey)!.push(tx);
|
||
|
|
});
|
||
|
|
|
||
|
|
grouped.forEach((transactions, date) => {
|
||
|
|
groups.push({ date, transactions });
|
||
|
|
});
|
||
|
|
|
||
|
|
return groups;
|
||
|
|
});
|
||
|
|
|
||
|
|
const formatDateHeader = (date: Date | string | undefined): string => {
|
||
|
|
if (!date) return 'Data sconosciuta';
|
||
|
|
|
||
|
|
const dateObj = typeof date === 'string' ? new Date(date) : date;
|
||
|
|
|
||
|
|
if (!(dateObj instanceof Date) || isNaN(dateObj.getTime())) {
|
||
|
|
return 'Data non valida';
|
||
|
|
}
|
||
|
|
|
||
|
|
const today = new Date();
|
||
|
|
const yesterday = new Date(today);
|
||
|
|
yesterday.setDate(yesterday.getDate() - 1);
|
||
|
|
|
||
|
|
if (dateObj.toDateString() === today.toDateString()) return 'Oggi';
|
||
|
|
if (dateObj.toDateString() === yesterday.toDateString()) return 'Ieri';
|
||
|
|
|
||
|
|
return dateObj.toLocaleDateString('it-IT', {
|
||
|
|
day: 'numeric',
|
||
|
|
month: 'long',
|
||
|
|
year: 'numeric',
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
// Stati dialog
|
||
|
|
const showSendDialog = ref(false);
|
||
|
|
const showReceiveDialog = ref(false);
|
||
|
|
const showConfirmSendDialog = ref(false);
|
||
|
|
const showConfirmReceiveDialog = ref(false);
|
||
|
|
|
||
|
|
// Stati invio
|
||
|
|
const sendCircuit = ref(userCircuits.value[0]);
|
||
|
|
const sendSearch = ref('');
|
||
|
|
const selectedRecipient = ref<(typeof allContacts.value)[0] | null>(null);
|
||
|
|
const sendAmount = ref<number | null>(null);
|
||
|
|
const sendDescription = ref('');
|
||
|
|
|
||
|
|
const filteredContacts = computed(() => {
|
||
|
|
if (!sendSearch.value) return allContacts.value;
|
||
|
|
const search = sendSearch.value.toLowerCase();
|
||
|
|
return allContacts.value.filter(
|
||
|
|
(c) =>
|
||
|
|
c.name.toLowerCase().includes(search) ||
|
||
|
|
c.username.toLowerCase().includes(search) ||
|
||
|
|
c.email.toLowerCase().includes(search)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
const newBalance = computed(() => {
|
||
|
|
if (!sendAmount.value || !sendCircuit.value) return sendCircuit.value?.balance || 0;
|
||
|
|
return sendCircuit.value.balance - sendAmount.value;
|
||
|
|
});
|
||
|
|
|
||
|
|
// Stati ricezione
|
||
|
|
const receiveCircuit = ref(userCircuits.value[0]);
|
||
|
|
const receiveSearch = ref('');
|
||
|
|
const selectedSender = ref<(typeof allContacts.value)[0] | null>(null);
|
||
|
|
const receiveAmount = ref<number | null>(null);
|
||
|
|
const receiveDescription = ref('');
|
||
|
|
|
||
|
|
const filteredSenders = computed(() => {
|
||
|
|
if (!receiveSearch.value) return allContacts.value;
|
||
|
|
const search = receiveSearch.value.toLowerCase();
|
||
|
|
return allContacts.value.filter(
|
||
|
|
(c) =>
|
||
|
|
c.name.toLowerCase().includes(search) ||
|
||
|
|
c.username.toLowerCase().includes(search) ||
|
||
|
|
c.email.toLowerCase().includes(search)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
const newReceiveBalance = computed(() => {
|
||
|
|
if (!receiveAmount.value || !receiveCircuit.value)
|
||
|
|
return receiveCircuit.value?.balance || 0;
|
||
|
|
return receiveCircuit.value.balance + receiveAmount.value;
|
||
|
|
});
|
||
|
|
|
||
|
|
// Funzioni
|
||
|
|
const handleSend = () => {
|
||
|
|
// $router.push('/send-coins');
|
||
|
|
showSendDialog.value = true;
|
||
|
|
// sendCircuit.value = selectedCircuit.value;
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleReceive = () => {
|
||
|
|
showReceiveDialog.value = true;
|
||
|
|
receiveCircuit.value = selectedCircuit.value;
|
||
|
|
};
|
||
|
|
|
||
|
|
const closeSendDialog = () => {
|
||
|
|
showSendDialog.value = false;
|
||
|
|
sendSearch.value = '';
|
||
|
|
selectedRecipient.value = null;
|
||
|
|
};
|
||
|
|
|
||
|
|
const closeReceiveDialog = () => {
|
||
|
|
showReceiveDialog.value = false;
|
||
|
|
receiveSearch.value = '';
|
||
|
|
selectedSender.value = null;
|
||
|
|
};
|
||
|
|
|
||
|
|
const searchRecipients = () => {
|
||
|
|
console.log('Ricerca destinatari:', sendSearch.value);
|
||
|
|
};
|
||
|
|
|
||
|
|
const searchSenders = () => {
|
||
|
|
console.log('Ricerca mittenti:', receiveSearch.value);
|
||
|
|
};
|
||
|
|
|
||
|
|
const selectRecipient = (contact: (typeof allContacts.value)[0]) => {
|
||
|
|
selectedRecipient.value = contact;
|
||
|
|
showSendDialog.value = false;
|
||
|
|
showConfirmSendDialog.value = true;
|
||
|
|
};
|
||
|
|
|
||
|
|
const selectSender = (contact: (typeof allContacts.value)[0]) => {
|
||
|
|
selectedSender.value = contact;
|
||
|
|
showReceiveDialog.value = false;
|
||
|
|
showConfirmReceiveDialog.value = true;
|
||
|
|
};
|
||
|
|
|
||
|
|
const cancelSend = () => {
|
||
|
|
showConfirmSendDialog.value = false;
|
||
|
|
sendAmount.value = null;
|
||
|
|
sendDescription.value = '';
|
||
|
|
selectedRecipient.value = null;
|
||
|
|
};
|
||
|
|
|
||
|
|
const cancelReceive = () => {
|
||
|
|
showConfirmReceiveDialog.value = false;
|
||
|
|
receiveAmount.value = null;
|
||
|
|
receiveDescription.value = '';
|
||
|
|
selectedSender.value = null;
|
||
|
|
};
|
||
|
|
|
||
|
|
const confirmSend = () => {
|
||
|
|
console.log('Invio confermato:', {
|
||
|
|
recipient: selectedRecipient.value,
|
||
|
|
circuit: sendCircuit.value,
|
||
|
|
amount: sendAmount.value,
|
||
|
|
description: sendDescription.value,
|
||
|
|
});
|
||
|
|
|
||
|
|
showConfirmSendDialog.value = false;
|
||
|
|
cancelSend();
|
||
|
|
};
|
||
|
|
|
||
|
|
const confirmReceive = () => {
|
||
|
|
console.log('Ricezione richiesta:', {
|
||
|
|
sender: selectedSender.value,
|
||
|
|
circuit: receiveCircuit.value,
|
||
|
|
amount: receiveAmount.value,
|
||
|
|
description: receiveDescription.value,
|
||
|
|
});
|
||
|
|
|
||
|
|
showConfirmReceiveDialog.value = false;
|
||
|
|
cancelReceive();
|
||
|
|
};
|
||
|
|
|
||
|
|
const loadMoreTransactions = (index: number, done: (stop?: boolean) => void) => {
|
||
|
|
console.log('Carica più transazioni, index:', index);
|
||
|
|
setTimeout(() => {
|
||
|
|
done(true);
|
||
|
|
}, 500);
|
||
|
|
};
|
||
|
|
|
||
|
|
const viewTransactionDetail = (tx: (typeof allTransactions.value)[0]) => {
|
||
|
|
console.log('Visualizza dettaglio transazione:', tx);
|
||
|
|
};
|
||
|
|
|
||
|
|
const viewCircuitDetails = (circuit: (typeof userCircuits.value)[0]) => {
|
||
|
|
console.log('Visualizza dettagli circuito:', circuit);
|
||
|
|
// Implementa visualizzazione dettagli
|
||
|
|
};
|
||
|
|
|
||
|
|
const openCircuitSettings = (circuit: (typeof userCircuits.value)[0]) => {
|
||
|
|
console.log('Apri impostazioni circuito:', circuit);
|
||
|
|
// Implementa impostazioni circuito
|
||
|
|
};
|
||
|
|
|
||
|
|
const viewCircuits = () => {
|
||
|
|
console.log('Esplora altri circuiti');
|
||
|
|
// Implementa navigazione
|
||
|
|
};
|
||
|
|
|
||
|
|
const openTransaction = (tx: any) => {
|
||
|
|
console.log('Apri transazione:', tx);
|
||
|
|
};
|
||
|
|
|
||
|
|
const goToTransactions = () => {
|
||
|
|
selectedTab.value = 'transactions';
|
||
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||
|
|
};
|
||
|
|
|
||
|
|
const visu = computed(() => {
|
||
|
|
return {
|
||
|
|
// Configurazione visualizzazione
|
||
|
|
};
|
||
|
|
});
|
||
|
|
|
||
|
|
const listcircuitsfind = computed(() => {
|
||
|
|
return circuitStore.updateListCircuit(costanti.FIND_CIRCUIT) || [];
|
||
|
|
});
|
||
|
|
|
||
|
|
// Dati circuiti
|
||
|
|
const circuits = ref({
|
||
|
|
provinciale: {
|
||
|
|
availableBalance: 0,
|
||
|
|
realBalance: 0,
|
||
|
|
trustLimit: -100,
|
||
|
|
maxAccumulation: 200,
|
||
|
|
totalTransactions: 0,
|
||
|
|
sentCount: 0,
|
||
|
|
receivedCount: 0,
|
||
|
|
uniqueMembers: 0,
|
||
|
|
lastTradeTime: 'Mai',
|
||
|
|
recentTransactions: [] as any[],
|
||
|
|
title: 'RIS Provinciale',
|
||
|
|
},
|
||
|
|
italia: {
|
||
|
|
availableBalance: 0,
|
||
|
|
realBalance: 0,
|
||
|
|
trustLimit: -200,
|
||
|
|
maxAccumulation: 400,
|
||
|
|
totalTransactions: 0,
|
||
|
|
sentCount: 0,
|
||
|
|
receivedCount: 0,
|
||
|
|
uniqueMembers: 0,
|
||
|
|
lastTradeTime: 'Mai',
|
||
|
|
recentTransactions: [] as any[],
|
||
|
|
title: 'RIS Italia',
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
onMounted(() => {
|
||
|
|
initializeTransactions(); // Inizializza le transazioni
|
||
|
|
loadTestData();
|
||
|
|
//
|
||
|
|
if (userStore.my.profile.mycircuits.length <= 0) {
|
||
|
|
filter.value = costanti.FIND_CIRCUIT;
|
||
|
|
}
|
||
|
|
|
||
|
|
ind.value = tools.getIndMainCardsByTable(shared_consts.TABLES_CIRCUITS);
|
||
|
|
});
|
||
|
|
|
||
|
|
const loadTestData = () => {
|
||
|
|
if (!isTest) return;
|
||
|
|
|
||
|
|
// Circuito Provinciale
|
||
|
|
circuits.value.provinciale = {
|
||
|
|
title: 'RIS Provinciale',
|
||
|
|
availableBalance: 50,
|
||
|
|
realBalance: -50,
|
||
|
|
trustLimit: -100,
|
||
|
|
maxAccumulation: 200,
|
||
|
|
totalTransactions: 15,
|
||
|
|
sentCount: 8,
|
||
|
|
receivedCount: 7,
|
||
|
|
uniqueMembers: 12,
|
||
|
|
lastTradeTime: '2 giorni fa',
|
||
|
|
recentTransactions: [
|
||
|
|
{ userInitial: 'M', description: 'Ortaggi freschi', time: '2h fa', amount: 15 },
|
||
|
|
{
|
||
|
|
userInitial: 'L',
|
||
|
|
description: 'Lezione chitarra',
|
||
|
|
time: '5h fa',
|
||
|
|
amount: -25,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
userInitial: 'G',
|
||
|
|
description: 'Riparazione bici',
|
||
|
|
time: '1 giorno fa',
|
||
|
|
amount: 30,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
};
|
||
|
|
|
||
|
|
// Circuito Italia
|
||
|
|
circuits.value.italia = {
|
||
|
|
title: 'RIS Italia',
|
||
|
|
availableBalance: -50,
|
||
|
|
realBalance: 150,
|
||
|
|
trustLimit: -200,
|
||
|
|
maxAccumulation: 400,
|
||
|
|
totalTransactions: 8,
|
||
|
|
sentCount: 3,
|
||
|
|
receivedCount: 5,
|
||
|
|
uniqueMembers: 7,
|
||
|
|
lastTradeTime: '5 giorni fa',
|
||
|
|
recentTransactions: [
|
||
|
|
{
|
||
|
|
userInitial: 'A',
|
||
|
|
description: 'Consulenza legale',
|
||
|
|
time: '3 giorni fa',
|
||
|
|
amount: -80,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
userInitial: 'F',
|
||
|
|
description: 'Prodotti artigianali',
|
||
|
|
time: '4 giorni fa',
|
||
|
|
amount: 50,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
userInitial: 'S',
|
||
|
|
description: 'Corso di cucina',
|
||
|
|
time: '5 giorni fa',
|
||
|
|
amount: -40,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
};
|
||
|
|
|
||
|
|
// Transazioni community (tutti)
|
||
|
|
allTransactions.value = [
|
||
|
|
{
|
||
|
|
id: 'test-1',
|
||
|
|
type: 'received',
|
||
|
|
fromInitial: 'M',
|
||
|
|
toInitial: 'L',
|
||
|
|
fromName: 'Mario',
|
||
|
|
toName: 'Laura',
|
||
|
|
otherUser: 'Mario',
|
||
|
|
circuitName: 'RIS Treviso',
|
||
|
|
circuitId: '1',
|
||
|
|
description: 'Scambio ortaggi',
|
||
|
|
amount: 25,
|
||
|
|
time: '1h fa',
|
||
|
|
date: new Date().toISOString().split('T')[0],
|
||
|
|
timestamp: new Date(Date.now() - 60 * 60 * 1000),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: 'test-2',
|
||
|
|
type: 'sent',
|
||
|
|
fromInitial: 'G',
|
||
|
|
toInitial: 'C',
|
||
|
|
fromName: 'Giovanni',
|
||
|
|
toName: 'Chiara',
|
||
|
|
otherUser: 'Giovanni',
|
||
|
|
circuitName: 'RIS Treviso',
|
||
|
|
circuitId: '1',
|
||
|
|
description: 'Consulenza',
|
||
|
|
amount: 40,
|
||
|
|
time: '2h fa',
|
||
|
|
date: new Date().toISOString().split('T')[0],
|
||
|
|
timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: 'test-3',
|
||
|
|
type: 'received',
|
||
|
|
fromInitial: 'P',
|
||
|
|
toInitial: 'A',
|
||
|
|
fromName: 'Paolo',
|
||
|
|
toName: 'Anna',
|
||
|
|
otherUser: 'Paolo',
|
||
|
|
circuitName: 'RIS Italia',
|
||
|
|
circuitId: '2',
|
||
|
|
description: 'Servizio',
|
||
|
|
amount: 15,
|
||
|
|
time: '3h fa',
|
||
|
|
date: new Date().toISOString().split('T')[0],
|
||
|
|
timestamp: new Date(Date.now() - 3 * 60 * 60 * 1000),
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
// Scambi test data
|
||
|
|
recentTrades.value = [
|
||
|
|
{
|
||
|
|
userInitial: 'M',
|
||
|
|
description: 'Scambio ortaggi freschi',
|
||
|
|
time: '2h fa',
|
||
|
|
amount: 15,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
userInitial: 'L',
|
||
|
|
description: 'Lezione di chitarra',
|
||
|
|
time: '5h fa',
|
||
|
|
amount: -25,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
userInitial: 'G',
|
||
|
|
description: 'Riparazione bicicletta',
|
||
|
|
time: '1 giorno fa',
|
||
|
|
amount: 30,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
userInitial: 'A',
|
||
|
|
description: 'Pane fatto in casa',
|
||
|
|
time: '2 giorni fa',
|
||
|
|
amount: -10,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
userInitial: 'S',
|
||
|
|
description: 'Consulenza informatica',
|
||
|
|
time: '3 giorni fa',
|
||
|
|
amount: 40,
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
// Statistiche test data
|
||
|
|
totalMembers.value = 342;
|
||
|
|
totalTrades.value = 1567;
|
||
|
|
totalEvents.value = 89;
|
||
|
|
};
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="scss" scoped>
|
||
|
|
@import './pageris.scss';
|
||
|
|
</style>
|