Files
myprojplanet_vite/src/components/pageris/pageris.vue

1719 lines
46 KiB
Vue
Raw Normal View History

2025-12-05 17:56:05 +01:00
<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>