Files
myprojplanet_vite/src/components/pageris/pageris.vue
Surya Paolo 89a8d10eae - verifica email se non è stata verificata (componente)
- altri aggiornamenti grafica PAGERIS.
- OLLAMA AI
2025-12-11 18:34:39 +01:00

1187 lines
37 KiB
Vue

<template>
<q-page class="ris-activity-page">
<!-- Azioni RIS -->
<section class="ris-actions-section">
<div class="ris-actions-grid">
<q-btn
unelevated
class="ris-action-btn send-btn"
@click="handleSend"
>
<q-icon name="arrow_upward" size="24px" />
<span>Invia RIS</span>
</q-btn>
<q-btn
unelevated
class="ris-action-btn receive-btn"
@click="handleReceive"
>
<q-icon name="arrow_downward" size="24px" />
<span>Ricevi RIS</span>
</q-btn>
</div>
</section>
<!-- Quick Actions Tabs (Desktop) -->
<section class="quick-actions-section desktop-only">
<div class="quick-actions-grid">
<q-btn
flat
class="quick-action-btn"
:class="{ active: selectedTab === 'transactions' }"
@click="changeTab('transactions')"
>
<div class="btn-content">
<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="btn-content">
<q-icon name="bar_chart" size="28px" />
<span>Statistiche</span>
</div>
</q-btn>
<q-btn
flat
class="quick-action-btn"
:class="{ active: selectedTab === 'circuits' }"
@click="changeTab('circuits')"
>
<div class="btn-content">
<q-icon name="account_balance" size="28px" />
<span>Circuiti</span>
</div>
</q-btn>
<q-btn
flat
class="quick-action-btn"
:class="{ active: selectedTab === 'settings' }"
@click="changeTab('settings')"
>
<div class="btn-content">
<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 -->
<section class="circuits-section">
<div class="circuits-header">
<h2 class="section-title">
<q-icon name="account_balance_wallet" size="20px" class="title-icon" />
Circuiti Abilitati
</h2>
<span class="scroll-hint">Scorri per vedere altri </span>
</div>
<!-- Container scrollabile per i circuiti -->
<div class="circuits-scroll-container">
<div class="circuits-list">
<div
v-for="circuit in userCircuits"
:key="circuit._id"
class="circuit-card"
:class="{ selected: selectedCircuit?._id === circuit._id }"
@click="selectCircuit(circuit)"
>
<div class="circuit-card-content">
<div class="circuit-left">
<div class="circuit-header">
<span class="circuit-name">{{ circuit.name }}</span>
<q-badge
:color="circuit.isCircItalia ? 'deep-purple' : 'cyan'"
class="circuit-badge"
>
{{ circuitStore.getTypeCircuit(circuit) }}
</q-badge>
</div>
<div class="circuit-balance">
{{ circuitStore.getSaldoByCircuitId(circuit._id) }}
<span class="currency">{{ circuit.symbol }}</span>
</div>
</div>
<div class="circuit-right">
<div class="limit-row fido">
<q-icon name="remove_circle_outline" size="16px" />
<span class="limit-label">Fido:</span>
<span class="limit-value">{{
circuitStore.getFidoConcessoByUsername(
userStore.my,
circuit._id,
userStore.my.username,
''
) || 0
}}</span>
</div>
<div class="limit-row max">
<q-icon name="add_circle_outline" size="16px" />
<span class="limit-label">Max:</span>
<span class="limit-value">{{
circuitStore.getMaxAccumuloByUsername(
userStore.my,
circuit._id,
userStore.my.username,
''
) || 0
}}</span>
</div>
</div>
</div>
<!-- Indicatore circuito selezionato -->
<div v-if="selectedCircuit?._id === circuit._id" class="selected-indicator">
<q-icon name="check_circle" size="18px" />
<span>Circuito selezionato</span>
</div>
</div>
</div>
</div>
<q-btn
outline
class="explore-btn"
@click="viewCircuits()"
>
<q-icon name="explore" size="20px" />
<span>Esplora altri circuiti</span>
</q-btn>
</section>
<!-- Statistiche del circuito selezionato -->
<section class="statistics-section" :key="selectedCircuit?._id">
<h3 class="stats-title">
<q-icon name="insights" size="20px" />
Statistiche {{ selectedCircuit?.name }}
</h3>
<div class="stats-grid">
<div class="stat-card total">
<q-icon name="repeat" size="28px" />
<div class="stat-value">{{ currentCircuitData.totTransato }} {{ currentCircuitData.symbol }}</div>
<div class="stat-label">Transati</div>
</div>
<div class="stat-card members">
<q-icon name="people" size="28px" />
<div class="stat-value">{{ currentCircuitData.numMembers }}</div>
<div class="stat-label">Membri</div>
</div>
<div class="stat-card sent">
<q-icon name="arrow_upward" size="28px" />
<div class="stat-value">{{ currentCircuitData.sentCount }}</div>
<div class="stat-label">Inviate</div>
</div>
<div class="stat-card received">
<q-icon name="arrow_downward" size="28px" />
<div class="stat-value">{{ currentCircuitData.receivedCount }}</div>
<div class="stat-label">Ricevute</div>
</div>
</div>
</section>
<!-- Activity Feed -->
<section class="activity-section">
<h3 class="section-title">
<q-icon name="history" size="20px" class="title-icon" />
Attività Recente
</h3>
<div class="activity-feed">
<q-infinite-scroll
@load="loadMoreTransactions"
:offset="250"
>
<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">
<q-avatar
:color="tx.type === 'sent' ? 'red-5' : 'green-5'"
text-color="white"
size="48px"
>
<q-icon :name="tx.type === 'sent' ? 'arrow_upward' : 'arrow_downward'" size="24px" />
</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 class="separator"></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>
</section>
</div>
<!-- Tab: Statistiche -->
<div
v-show="selectedTab === 'statistics'"
class="tab-content"
>
<div class="wallet-card">
<h2 class="wallet-title">Statistiche Dettagliate</h2>
<!-- Balance Bar -->
<div class="wallet-balances-compact">
<CRISBalanceBar
:current-balance="currentCircuitData.account.saldo"
:min-limit="currentCircuitData.fidoConcesso"
:max-limit="currentCircuitData.qta_maxConcessa"
:label="currentCircuitData.name"
/>
</div>
<!-- Toggle Personali/Community -->
<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="sm"
toggle-color="white"
text-color="white"
class="transactions-toggle"
:options="[
{ label: 'Personali', value: 'mine' },
{ label: '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="36px"
: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="14px" 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>
<q-btn
unelevated
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"
class="circuits-toggle"
:options="[
{ label: 'I miei Circuiti', value: 'mycircuits', icon: 'account_box' },
{ label: 'Tutti i Circuiti', value: 'allcircuits', icon: 'view_list' },
]"
/>
</div>
<div v-show="selectedCirc === 'mycircuits'" class="my-circuits-content">
<div
v-for="circuit in userCircuits"
:key="circuit.id"
class="circuit-detail-card"
>
<div class="circuit-detail-header">
<div class="circuit-detail-title">
<h3>{{ circuit.name }}</h3>
<q-badge :color="circuit.isCircItalia ? 'deep-purple' : 'cyan'">
{{ circuitStore.getTypeCircuit(circuit) }}
</q-badge>
</div>
<div class="circuit-detail-balance" :style="`color: ${circuit.color || '#667eea'}`">
{{ circuitStore.getSaldoByCircuitId(circuit._id) }}
<span class="currency" :style="`background: ${circuit.color || '#667eea'}`">{{ circuit.symbol }}</span>
</div>
</div>
<div class="circuit-detail-body">
<div class="info-row">
<q-icon name="handshake" size="20px" />
<span class="info-label">Fiducia concessa:</span>
<span class="info-value">
{{ circuitStore.getFidoConcessoByUsername(userStore.my, circuit._id, userStore.my.username, '') || 0 }} RIS
</span>
</div>
<div class="info-row">
<q-icon name="account_balance_wallet" size="20px" />
<span class="info-label">Massimo accumulo:</span>
<span class="info-value">
{{ circuitStore.getMaxAccumuloByUsername(userStore.my, circuit._id, userStore.my.username, '') || 0 }} RIS
</span>
</div>
<div class="info-row">
<q-icon name="people" size="20px" />
<span class="info-label">Membri totali:</span>
<span class="info-value">{{ circuit.numMembers || 0 }}</span>
</div>
</div>
<div class="circuit-detail-actions">
<q-btn
flat
class="action-btn"
icon="visibility"
label="Dettagli"
@click="viewCircuitDetails(circuit)"
/>
<q-btn
flat
class="action-btn"
icon="settings"
label="Impostazioni"
@click="openCircuitSettings(circuit)"
/>
</div>
</div>
</div>
<div v-show="selectedCirc === 'allcircuits'" class="all-circuits-content">
<div class="section-header">
<h2 class="section-title">Lista Circuiti</h2>
</div>
<div class="circuits-finder">
<span
v-for="(circuit, index) in listcircuitsfind"
:key="index"
class="circuit-finder-item"
>
<CMyCircuit
:mycircuit="circuit"
:visu="visu"
:username="userStore.my.username"
/>
</span>
</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>
<!-- Tab: Impostazioni -->
<div
v-show="selectedTab === 'settings'"
class="tab-content"
>
<div class="settings-card">
<h2 class="settings-title">
<q-icon name="settings" size="24px" />
Impostazioni
</h2>
<div class="settings-list">
<div class="settings-item">
<div class="settings-item-left">
<q-icon name="notifications" size="24px" />
<span>Notifiche</span>
</div>
<q-toggle v-model="settingsNotifications" color="primary" />
</div>
<div class="settings-item">
<div class="settings-item-left">
<q-icon name="dark_mode" size="24px" />
<span>Tema Scuro</span>
</div>
<q-toggle v-model="settingsDarkMode" color="primary" />
</div>
<div class="settings-item clickable" @click="openPrivacy">
<div class="settings-item-left">
<q-icon name="security" size="24px" />
<span>Privacy e Sicurezza</span>
</div>
<q-icon name="chevron_right" size="24px" color="grey-6" />
</div>
<div class="settings-item clickable" @click="openHelp">
<div class="settings-item-left">
<q-icon name="help" size="24px" />
<span>Aiuto e Supporto</span>
</div>
<q-icon name="chevron_right" size="24px" color="grey-6" />
</div>
</div>
</div>
</div>
<!-- Mobile Bottom Navigation -->
<nav class="mobile-nav">
<div class="mobile-nav-grid">
<q-btn
flat
class="mobile-nav-btn"
:class="{ active: selectedTab === 'transactions' }"
@click="changeTab('transactions')"
>
<q-icon name="swap_vert" size="24px" />
<span>Scambi</span>
</q-btn>
<q-btn
flat
class="mobile-nav-btn"
:class="{ active: selectedTab === 'statistics' }"
@click="changeTab('statistics')"
>
<q-icon name="bar_chart" size="24px" />
<span>Stats</span>
</q-btn>
<q-btn
flat
class="mobile-nav-btn"
:class="{ active: selectedTab === 'circuits' }"
@click="changeTab('circuits')"
>
<q-icon name="account_balance" size="24px" />
<span>Circuiti</span>
</q-btn>
<q-btn
flat
class="mobile-nav-btn"
:class="{ active: selectedTab === 'settings' }"
@click="changeTab('settings')"
>
<q-icon name="settings" size="24px" />
<span>Altro</span>
</q-btn>
</div>
</nav>
<!-- Dialog Invia RIS -->
<q-dialog
v-model="showSendDialog"
persistent
maximized
transition-show="slide-up"
transition-hide="slide-down"
>
<q-card class="send-dialog">
<q-card-section class="dialog-header send">
<div class="dialog-title">
<q-icon name="north_east" size="24px" />
<span>Invia RIS</span>
</div>
<q-btn
flat
round
dense
icon="close"
color="white"
@click="closeSendDialog()"
/>
</q-card-section>
<q-card-section class="dialog-content">
<q-input
v-model="sendSearch"
label="Cerca destinatario..."
outlined
dense
clearable
class="search-input"
@update:model-value="searchRecipients"
>
<template v-slot:prepend>
<q-icon name="search" />
</template>
</q-input>
<!-- Contatti recenti -->
<div v-if="recentContacts.length && !sendSearch" class="contacts-section">
<div class="contacts-title">
<q-icon name="history" size="16px" />
<span>Usati di recente</span>
</div>
<div
v-for="contact in recentContacts"
:key="contact.username"
class="contact-item recent"
@click="selectRecipient(contact)"
>
<q-avatar round size="44px">
<img :src="userStore.getImgByProfile(contact)" />
<q-badge
v-if="tools.isUserOnline(contact)"
floating
color="green"
rounded
/>
</q-avatar>
<div class="contact-info">
<div v-if="contact.name" class="contact-name">
{{ contact.name }}
<span v-if="contact.surname">{{ contact.surname }}</span>
</div>
<div class="contact-username">@{{ contact.username }}</div>
</div>
<q-icon name="chevron_right" size="20px" color="grey-6" />
</div>
</div>
<!-- Risultati ricerca -->
<div v-if="sendSearch && filteredContacts.length" class="contacts-section">
<div class="contacts-title">
<q-icon name="people" size="16px" />
<span>Risultati ricerca</span>
</div>
<div class="contacts-scrollable">
<div
v-for="contact in filteredContacts"
:key="contact.id"
class="contact-item"
@click="selectRecipient(contact)"
>
<q-avatar size="44px" :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" color="grey-6" />
</div>
</div>
</div>
<div v-if="sendSearch && !filteredContacts.length" class="no-results">
<q-icon name="search_off" size="56px" color="grey-5" />
<p>Nessun contatto trovato</p>
</div>
</q-card-section>
</q-card>
</q-dialog>
<!-- Dialog Ricevi RIS -->
<q-dialog
v-model="showReceiveDialog"
persistent
transition-show="slide-up"
transition-hide="slide-down"
>
<q-card class="receive-dialog">
<q-card-section class="dialog-header receive">
<div class="dialog-title">
<q-icon name="south_west" size="24px" />
<span>Ricevi RIS</span>
</div>
<q-btn
flat
round
dense
icon="close"
color="white"
@click="closeReceiveDialog()"
/>
</q-card-section>
<q-card-section class="dialog-content">
<div class="info-banner">
<q-icon name="info" size="20px" 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..."
outlined
dense
clearable
class="search-input"
@update:model-value="searchSenders"
>
<template v-slot:prepend>
<q-icon name="search" />
</template>
</q-input>
<div v-if="filteredSenders.length" class="contacts-section">
<div class="contacts-title">
<q-icon name="people" size="16px" />
<span>{{ receiveSearch ? 'Risultati ricerca' : 'Contatti disponibili' }}</span>
</div>
<div class="contacts-scrollable">
<div
v-for="contact in filteredSenders"
:key="contact.id"
class="contact-item"
@click="selectSender(contact)"
>
<q-avatar size="44px" :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" color="grey-6" />
</div>
</div>
</div>
<div v-if="receiveSearch && !filteredSenders.length" class="no-results">
<q-icon name="search_off" size="56px" color="grey-5" />
<p>Nessun contatto trovato</p>
</div>
</q-card-section>
</q-card>
</q-dialog>
<!-- Dialog Conferma Invio -->
<div v-if="showConfirmSendDialog">
<CSendCoins
:loadprofile="true"
:showprop="showConfirmSendDialog"
:to_user="selectedRecipient"
@close="showConfirmSendDialog = false"
/>
</div>
<!-- Dialog Conferma Ricezione -->
<q-dialog
v-model="showConfirmReceiveDialog"
persistent
>
<q-card class="confirm-dialog">
<q-card-section class="dialog-header receive">
<div class="dialog-title">Richiesta ricezione</div>
</q-card-section>
<q-card-section class="dialog-content">
<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="amount-input"
: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="2"
class="description-input"
/>
<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="dialog-actions">
<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';
import { IAccount } from 'app/src/model';
const userStore = useUserStore();
const circuitStore = useCircuitStore();
const $q = useQuasar();
const $router = useRouter();
const { t } = useI18n();
const ind = ref(0);
const filter = ref(costanti.FIND_CIRCUIT);
const isTest = true;
// Settings
const settingsNotifications = ref(true);
const settingsDarkMode = ref(true);
const allTransactions = ref<any[]>([]);
const transactionsView = ref<'mine' | 'all'>('mine');
const userCircuits = computed(() => {
return circuitStore.updateListCircuit(costanti.MY_CIRCUITS, true);
});
const selectedCircuit = ref(userCircuits.value[0]);
const selectedTab = ref('transactions');
const selectedCirc = ref('mycircuits');
const userAccount = ref(<IAccount|null>null)
const changeTab = (tab: string) => {
selectedTab.value = tab;
window.scrollTo({ top: 0, behavior: 'smooth' });
};
const selectCircuit = (circuit: (typeof userCircuits.value)[0]) => {
selectedCircuit.value = circuit;
};
const currentCircuitData = computed(() => {
const circuitId = selectedCircuit.value?._id;
const txs = allTransactions.value.filter((tx) => tx.circuitId === circuitId);
userAccount.value = userStore.getAccountByCircuitId(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,
account: userAccount.value,
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 },
],
};
});
const allContacts = computed(() => userStore.getLastRecentUserTransactions());
const recentContacts = computed(() => userStore.getLastRecentUserTransactions());
const hasTransactions = computed(() => allTransactions.value.length > 0);
const groupedTransactions = computed(() => {
const groups: { date: string; transactions: typeof allTransactions.value }[] = [];
const grouped = new Map<string, typeof allTransactions.value>();
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',
});
};
// Dialog states
const showSendDialog = ref(false);
const showReceiveDialog = ref(false);
const showConfirmSendDialog = ref(false);
const showConfirmReceiveDialog = ref(false);
// Send states
const sendCircuit = ref(userCircuits.value[0]);
const sendSearch = ref('');
const selectedRecipient = ref<any>(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)
);
});
// Receive states
const receiveCircuit = ref(userCircuits.value[0]);
const receiveSearch = ref('');
const selectedSender = ref<any>(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;
});
// Functions
const handleSend = () => {
showSendDialog.value = true;
};
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: any) => {
selectedRecipient.value = contact;
showSendDialog.value = false;
showConfirmSendDialog.value = true;
};
const selectSender = (contact: any) => {
selectedSender.value = contact;
showReceiveDialog.value = false;
showConfirmReceiveDialog.value = true;
};
const cancelReceive = () => {
showConfirmReceiveDialog.value = false;
receiveAmount.value = null;
receiveDescription.value = '';
selectedSender.value = null;
};
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) => {
setTimeout(() => {
done(true);
}, 500);
};
const viewTransactionDetail = (tx: any) => {
console.log('Visualizza dettaglio transazione:', tx);
};
const viewCircuitDetails = (circuit: any) => {
console.log('Visualizza dettagli circuito:', circuit);
};
const openCircuitSettings = (circuit: any) => {
console.log('Apri impostazioni circuito:', circuit);
};
const viewCircuits = () => {
selectedTab.value = 'circuits';
selectedCirc.value = 'allcircuits';
};
const openTransaction = (tx: any) => {
console.log('Apri transazione:', tx);
};
const goToTransactions = () => {
selectedTab.value = 'transactions';
window.scrollTo({ top: 0, behavior: 'smooth' });
};
const openPrivacy = () => {
console.log('Apri privacy');
};
const openHelp = () => {
console.log('Apri aiuto');
};
const visu = computed(() => ({}));
const listcircuitsfind = computed(() => {
return circuitStore.updateListCircuit(costanti.FIND_CIRCUIT) || [];
});
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'),
fromInitial: 'M',
toInitial: 'L',
fromName: 'Mario',
toName: 'Laura',
},
{
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'),
fromInitial: 'L',
toInitial: 'G',
fromName: 'Laura',
toName: 'Giuseppe',
},
{
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'),
fromInitial: 'G',
toInitial: 'A',
fromName: 'Giuseppe',
toName: 'Anna',
},
];
};
onMounted(() => {
initializeTransactions();
if (userStore.my.profile.mycircuits.length <= 0) {
filter.value = costanti.FIND_CIRCUIT;
}
ind.value = tools.getIndMainCardsByTable(shared_consts.TABLES_CIRCUITS);
});
</script>
<style lang="scss" scoped>
@import './pageris.scss';
</style>