Compare commits
	
		
			1 Commits
		
	
	
		
			develop
			...
			refactor/n
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 9e5516972a | 
| @ -15,7 +15,7 @@ const targetNetwork = ref(DEFAULT_NETWORK); | |||||||
| const web3Onboard = init({ | const web3Onboard = init({ | ||||||
|   wallets: [injected], |   wallets: [injected], | ||||||
|   chains: Object.values(Networks).map((network) => ({ |   chains: Object.values(Networks).map((network) => ({ | ||||||
|     id: `0x${network.id.toString(16)}`, |     id: network.id, | ||||||
|     token: network.nativeCurrency.symbol, |     token: network.nativeCurrency.symbol, | ||||||
|     label: network.name, |     label: network.name, | ||||||
|     rpcUrl: network.rpcUrls.default.http[0], |     rpcUrl: network.rpcUrls.default.http[0], | ||||||
|  | |||||||
| @ -94,10 +94,6 @@ const getValidDeposits = async ( | |||||||
| 
 | 
 | ||||||
|   // remove doubles from sellers list
 |   // remove doubles from sellers list
 | ||||||
|   const depositData = await depositLogs.json(); |   const depositData = await depositLogs.json(); | ||||||
|   if (!depositData.data) { |  | ||||||
|     console.error("Error fetching deposit logs"); |  | ||||||
|     return []; |  | ||||||
|   } |  | ||||||
|   const depositAddeds = depositData.data.depositAddeds; |   const depositAddeds = depositData.data.depositAddeds; | ||||||
|   const uniqueSellers = depositAddeds.reduce( |   const uniqueSellers = depositAddeds.reduce( | ||||||
|     (acc: Record<Address, boolean>, deposit: any) => { |     (acc: Record<Address, boolean>, deposit: any) => { | ||||||
|  | |||||||
| @ -233,17 +233,17 @@ const handleSubmit = async (e: Event): Promise<void> => { | |||||||
|           <div class="flex gap-2"> |           <div class="flex gap-2"> | ||||||
|             <img |             <img | ||||||
|               alt="Rootstock image" |               alt="Rootstock image" | ||||||
|               src="@/assets/networks/rootstock.svg?url" |               src="@/assets/rootstock.svg?url" | ||||||
|               width="24" |               width="24" | ||||||
|               height="24" |               height="24" | ||||||
|               v-if=" |               v-if=" | ||||||
|                 selectedDeposits && |                 selectedDeposits && | ||||||
|                 selectedDeposits.find((d) => d.network == Networks.rootstock) |                 selectedDeposits.find((d) => d.network == Networks.rootstockTestnet) | ||||||
|               " |               " | ||||||
|             /> |             /> | ||||||
|             <img |             <img | ||||||
|               alt="Ethereum image" |               alt="Ethereum image" | ||||||
|               src="@/assets/networks/ethereum.svg?url" |               src="@/assets/ethereum.svg?url" | ||||||
|               width="24" |               width="24" | ||||||
|               height="24" |               height="24" | ||||||
|               v-if=" |               v-if=" | ||||||
|  | |||||||
| @ -1,73 +0,0 @@ | |||||||
| <script setup lang="ts"> |  | ||||||
| interface Props { |  | ||||||
|   title: string; |  | ||||||
|   value: string; |  | ||||||
|   change?: string; |  | ||||||
|   changeType?: 'positive' | 'negative' | 'neutral'; |  | ||||||
|   icon?: string; |  | ||||||
|   loading?: boolean; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const props = withDefaults(defineProps<Props>(), { |  | ||||||
|   changeType: 'neutral', |  | ||||||
|   loading: false |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <template> |  | ||||||
|   <div class="analytics-card"> |  | ||||||
|     <div class="analytics-content"> |  | ||||||
|       <div v-if="loading" class="analytics-value"> |  | ||||||
|         <div class="animate-pulse bg-gray-300 h-8 w-16 rounded"></div> |  | ||||||
|       </div> |  | ||||||
|       <div v-else class="analytics-value">{{ value }}</div> |  | ||||||
|       <div class="analytics-title">{{ title }}</div> |  | ||||||
|       <div v-if="change && !loading" class="analytics-change" :class="`change-${changeType}`"> |  | ||||||
|         {{ change }} |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|     <div v-if="icon && !loading" class="analytics-icon"> |  | ||||||
|       <img :src="icon" :alt="`${title} icon`" class="w-8 h-8" /> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
| 
 |  | ||||||
| <style scoped> |  | ||||||
| .analytics-card { |  | ||||||
|   @apply bg-white rounded-lg border border-gray-200 p-6 flex items-center justify-between shadow-lg; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .analytics-content { |  | ||||||
|   @apply flex flex-col; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .analytics-value { |  | ||||||
|   @apply text-2xl font-bold text-amber-400 mb-1 break-words overflow-hidden; |  | ||||||
|   word-break: break-all; |  | ||||||
|   max-width: 100%; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .analytics-title { |  | ||||||
|   @apply text-sm text-gray-900 mb-1; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .analytics-change { |  | ||||||
|   @apply text-xs font-medium; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .change-positive { |  | ||||||
|   @apply text-green-600; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .change-negative { |  | ||||||
|   @apply text-red-600; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .change-neutral { |  | ||||||
|   @apply text-gray-600; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .analytics-icon { |  | ||||||
|   @apply flex-shrink-0; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @ -1,279 +0,0 @@ | |||||||
| <script setup lang="ts"> |  | ||||||
| import { ref } from 'vue'; |  | ||||||
| 
 |  | ||||||
| interface Transaction { |  | ||||||
|   id: string; |  | ||||||
|   type: 'deposit' | 'lock' | 'release' | 'return'; |  | ||||||
|   timestamp: string; |  | ||||||
|   seller?: string; |  | ||||||
|   buyer?: string | null; |  | ||||||
|   amount: string; |  | ||||||
|   token: string; |  | ||||||
|   blockNumber: string; |  | ||||||
|   transactionHash: string; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface Props { |  | ||||||
|   transactions: Transaction[]; |  | ||||||
|   networkExplorerUrl: string; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const props = defineProps<Props>(); |  | ||||||
| 
 |  | ||||||
| const copyFeedback = ref<{ [key: string]: boolean }>({}); |  | ||||||
| const copyFeedbackTimeout = ref<{ [key: string]: NodeJS.Timeout | null }>({}); |  | ||||||
| 
 |  | ||||||
| const getTransactionTypeInfo = (type: string) => { |  | ||||||
|   const typeMap = { |  | ||||||
|     deposit: { label: 'Depósito', status: 'completed' as const }, |  | ||||||
|     lock: { label: 'Bloqueio', status: 'open' as const }, |  | ||||||
|     release: { label: 'Liberação', status: 'completed' as const }, |  | ||||||
|     return: { label: 'Retorno', status: 'expired' as const } |  | ||||||
|   }; |  | ||||||
|   return typeMap[type as keyof typeof typeMap] || { label: type, status: 'pending' as const }; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const getTransactionTypeColor = (type: string) => { |  | ||||||
|   const colorMap = { |  | ||||||
|     deposit: 'text-emerald-600', |  | ||||||
|     lock: 'text-amber-600',  |  | ||||||
|     release: 'text-emerald-600', |  | ||||||
|     return: 'text-gray-600' |  | ||||||
|   }; |  | ||||||
|   return colorMap[type as keyof typeof colorMap] || 'text-gray-600'; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const formatAddress = (address: string) => { |  | ||||||
|   return `${address.slice(0, 6)}...${address.slice(-4)}`; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const formatAmount = (amount: string, decimals: number = 18): string => { |  | ||||||
|   const num = parseFloat(amount) / Math.pow(10, decimals); |  | ||||||
|   return num.toString(); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const getExplorerUrl = (txHash: string) => { |  | ||||||
|   return `${props.networkExplorerUrl}/tx/${txHash}`; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const copyToClipboard = async (address: string, key: string) => { |  | ||||||
|   if (!address) { |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   try { |  | ||||||
|     await navigator.clipboard.writeText(address); |  | ||||||
| 
 |  | ||||||
|     if (copyFeedbackTimeout.value[key]) { |  | ||||||
|       clearTimeout(copyFeedbackTimeout.value[key]!); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     copyFeedback.value[key] = true; |  | ||||||
| 
 |  | ||||||
|     copyFeedbackTimeout.value[key] = setTimeout(() => { |  | ||||||
|       copyFeedback.value[key] = false; |  | ||||||
|     }, 2000); |  | ||||||
|   } catch (error) { |  | ||||||
|     console.error('Error copying to clipboard:', error); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <template> |  | ||||||
|   <div> |  | ||||||
|     <div class="hidden lg:block overflow-x-auto"> |  | ||||||
|       <table class="w-full"> |  | ||||||
|         <thead> |  | ||||||
|           <tr class="border-b border-gray-200"> |  | ||||||
|             <th class="text-left py-3 px-4 text-gray-700 font-medium">Horário</th> |  | ||||||
|             <th class="text-left py-3 px-4 text-gray-700 font-medium">Tipo</th> |  | ||||||
|             <th class="text-left py-3 px-4 text-gray-700 font-medium">Participantes</th> |  | ||||||
|             <th class="text-left py-3 px-4 text-gray-700 font-medium">Valor</th> |  | ||||||
|             <th class="text-left py-3 px-4 text-gray-700 font-medium">Bloco</th> |  | ||||||
|             <th class="text-left py-3 px-4 text-gray-700 font-medium">Ações</th> |  | ||||||
|           </tr> |  | ||||||
|         </thead> |  | ||||||
|         <tbody> |  | ||||||
|           <tr  |  | ||||||
|             v-for="transaction in transactions"  |  | ||||||
|             :key="transaction.id" |  | ||||||
|             class="border-b border-gray-100 hover:bg-gray-50 transition-colors" |  | ||||||
|           > |  | ||||||
|             <td class="py-4 px-4"> |  | ||||||
|               <div class="text-sm text-gray-600">{{ transaction.timestamp }}</div> |  | ||||||
|             </td> |  | ||||||
|             <td class="py-4 px-4"> |  | ||||||
|               <span  |  | ||||||
|                 :class="getTransactionTypeColor(transaction.type)" |  | ||||||
|                 class="text-sm font-medium" |  | ||||||
|               > |  | ||||||
|                 {{ getTransactionTypeInfo(transaction.type).label }} |  | ||||||
|               </span> |  | ||||||
|             </td> |  | ||||||
|             <td class="py-4 px-4"> |  | ||||||
|               <div class="space-y-1"> |  | ||||||
|                 <div v-if="transaction.seller" class="text-sm"> |  | ||||||
|                   <span class="text-gray-600">Vendedor: </span> |  | ||||||
|                   <div class="relative inline-block"> |  | ||||||
|                     <span  |  | ||||||
|                       class="text-gray-900 font-mono cursor-pointer hover:text-amber-500 transition-colors" |  | ||||||
|                       @click="copyToClipboard(transaction.seller, `seller-${transaction.id}`)" |  | ||||||
|                       title="Copiar" |  | ||||||
|                     > |  | ||||||
|                       {{ formatAddress(transaction.seller) }} |  | ||||||
|                     </span> |  | ||||||
|                     <transition name="fade"> |  | ||||||
|                       <span |  | ||||||
|                         v-if="copyFeedback[`seller-${transaction.id}`]" |  | ||||||
|                         class="absolute -top-6 left-1/2 transform -translate-x-1/2 text-xs text-emerald-500 font-semibold bg-white px-2 py-1 rounded shadow-sm whitespace-nowrap z-10" |  | ||||||
|                       > |  | ||||||
|                         Copiado! |  | ||||||
|                       </span> |  | ||||||
|                     </transition> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|                 <div v-if="transaction.buyer" class="text-sm"> |  | ||||||
|                   <span class="text-gray-600">Comprador: </span> |  | ||||||
|                   <div class="relative inline-block"> |  | ||||||
|                     <span  |  | ||||||
|                       class="text-gray-900 font-mono cursor-pointer hover:text-amber-500 transition-colors" |  | ||||||
|                       @click="copyToClipboard(transaction.buyer, `buyer-${transaction.id}`)" |  | ||||||
|                       title="Copiar" |  | ||||||
|                     > |  | ||||||
|                       {{ formatAddress(transaction.buyer) }} |  | ||||||
|                     </span> |  | ||||||
|                     <transition name="fade"> |  | ||||||
|                       <span |  | ||||||
|                         v-if="copyFeedback[`buyer-${transaction.id}`]" |  | ||||||
|                         class="absolute -top-6 left-1/2 transform -translate-x-1/2 text-xs text-emerald-500 font-semibold bg-white px-2 py-1 rounded shadow-sm whitespace-nowrap z-10" |  | ||||||
|                       > |  | ||||||
|                         Copiado! |  | ||||||
|                       </span> |  | ||||||
|                     </transition> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|               </div> |  | ||||||
|             </td> |  | ||||||
|             <td class="py-4 px-4"> |  | ||||||
|               <div class="text-sm font-semibold text-emerald-600"> |  | ||||||
|                 {{ formatAmount(transaction.amount, 18) }} BRZ |  | ||||||
|               </div> |  | ||||||
|             </td> |  | ||||||
|             <td class="py-4 px-4"> |  | ||||||
|               <div class="text-sm text-gray-600 font-mono"> |  | ||||||
|                 #{{ transaction.blockNumber }} |  | ||||||
|               </div> |  | ||||||
|             </td> |  | ||||||
|             <td class="py-4 px-4"> |  | ||||||
|               <a |  | ||||||
|                 :href="getExplorerUrl(transaction.transactionHash)" |  | ||||||
|                 target="_blank" |  | ||||||
|                 rel="noopener noreferrer" |  | ||||||
|                 class="inline-flex items-center px-3 py-1 bg-amber-400 text-gray-900 rounded-lg text-sm font-medium hover:bg-amber-500 transition-colors" |  | ||||||
|               > |  | ||||||
|                 Explorador |  | ||||||
|               </a> |  | ||||||
|             </td> |  | ||||||
|           </tr> |  | ||||||
|         </tbody> |  | ||||||
|       </table> |  | ||||||
|     </div> |  | ||||||
| 
 |  | ||||||
|     <!-- Mobile Cards --> |  | ||||||
|     <div class="lg:hidden space-y-4"> |  | ||||||
|       <div  |  | ||||||
|         v-for="transaction in transactions"  |  | ||||||
|         :key="transaction.id" |  | ||||||
|         class="bg-gray-50 rounded-lg p-4 border border-gray-200" |  | ||||||
|       > |  | ||||||
|         <div class="flex items-center justify-between mb-3"> |  | ||||||
|           <span  |  | ||||||
|             :class="getTransactionTypeColor(transaction.type)" |  | ||||||
|             class="text-sm font-medium" |  | ||||||
|           > |  | ||||||
|             {{ getTransactionTypeInfo(transaction.type).label }} |  | ||||||
|           </span> |  | ||||||
|           <div class="text-sm text-gray-600">{{ transaction.timestamp }}</div> |  | ||||||
|         </div> |  | ||||||
|          |  | ||||||
|         <div class="space-y-2 mb-4"> |  | ||||||
|           <div v-if="transaction.seller" class="text-sm"> |  | ||||||
|             <span class="text-gray-600">Vendedor: </span> |  | ||||||
|             <div class="relative inline-block"> |  | ||||||
|               <span  |  | ||||||
|                 class="text-gray-900 font-mono cursor-pointer hover:text-amber-500 transition-colors" |  | ||||||
|                 @click="copyToClipboard(transaction.seller, `seller-${transaction.id}`)" |  | ||||||
|                 title="Copiar" |  | ||||||
|               > |  | ||||||
|                 {{ formatAddress(transaction.seller) }} |  | ||||||
|               </span> |  | ||||||
|               <transition name="fade"> |  | ||||||
|                 <span |  | ||||||
|                   v-if="copyFeedback[`seller-${transaction.id}`]" |  | ||||||
|                   class="absolute -top-6 left-1/2 transform -translate-x-1/2 text-xs text-emerald-500 font-semibold bg-white px-2 py-1 rounded shadow-sm whitespace-nowrap z-10" |  | ||||||
|                 > |  | ||||||
|                   Copiado! |  | ||||||
|                 </span> |  | ||||||
|               </transition> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|           <div v-if="transaction.buyer" class="text-sm"> |  | ||||||
|             <span class="text-gray-600">Comprador: </span> |  | ||||||
|             <div class="relative inline-block"> |  | ||||||
|               <span  |  | ||||||
|                 class="text-gray-900 font-mono cursor-pointer hover:text-amber-500 transition-colors" |  | ||||||
|                 @click="copyToClipboard(transaction.buyer, `buyer-${transaction.id}`)" |  | ||||||
|                 title="Copiar" |  | ||||||
|               > |  | ||||||
|                 {{ formatAddress(transaction.buyer) }} |  | ||||||
|               </span> |  | ||||||
|               <transition name="fade"> |  | ||||||
|                 <span |  | ||||||
|                   v-if="copyFeedback[`buyer-${transaction.id}`]" |  | ||||||
|                   class="absolute -top-6 left-1/2 transform -translate-x-1/2 text-xs text-emerald-500 font-semibold bg-white px-2 py-1 rounded shadow-sm whitespace-nowrap z-10" |  | ||||||
|                 > |  | ||||||
|                   Copiado! |  | ||||||
|                 </span> |  | ||||||
|               </transition> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|           <div class="text-sm"> |  | ||||||
|             <span class="text-gray-600">Valor: </span> |  | ||||||
|               <span class="font-semibold text-emerald-600">{{ formatAmount(transaction.amount, 18) }} BRZ</span> |  | ||||||
|             </div> |  | ||||||
|           <div class="text-sm"> |  | ||||||
|             <span class="text-gray-600">Bloco: </span> |  | ||||||
|             <span class="text-gray-900 font-mono">#{{ transaction.blockNumber }}</span> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|          |  | ||||||
|         <a |  | ||||||
|           :href="getExplorerUrl(transaction.transactionHash)" |  | ||||||
|           target="_blank" |  | ||||||
|           rel="noopener noreferrer" |  | ||||||
|           class="inline-flex items-center px-3 py-1 bg-amber-400 text-gray-900 rounded-lg text-sm font-medium hover:bg-amber-500 transition-colors" |  | ||||||
|         > |  | ||||||
|           Ver no Explorador |  | ||||||
|         </a> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
| 
 |  | ||||||
|     <!-- Empty State --> |  | ||||||
|     <div v-if="transactions.length === 0" class="text-center py-12"> |  | ||||||
|       <div class="text-gray-500 text-lg mb-2">📭</div> |  | ||||||
|       <p class="text-gray-600">Nenhuma transação encontrada</p> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
| 
 |  | ||||||
| <style scoped> |  | ||||||
| .fade-enter-active, |  | ||||||
| .fade-leave-active { |  | ||||||
|   transition: opacity 0.3s ease; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .fade-enter-from, |  | ||||||
| .fade-leave-to { |  | ||||||
|   opacity: 0; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @ -90,13 +90,13 @@ const handleInputEvent = (event: any): void => { | |||||||
|           <div class="flex gap-2"> |           <div class="flex gap-2"> | ||||||
|             <img |             <img | ||||||
|               alt="Polygon image" |               alt="Polygon image" | ||||||
|               src="@/assets/networks/polygon.svg?url" |               src="@/assets/polygon.svg?url" | ||||||
|               width="24" |               width="24" | ||||||
|               height="24" |               height="24" | ||||||
|             /> |             /> | ||||||
|             <img |             <img | ||||||
|               alt="Ethereum image" |               alt="Ethereum image" | ||||||
|               src="@/assets/networks/ethereum.svg?url" |               src="@/assets/ethereum.svg?url" | ||||||
|               width="24" |               width="24" | ||||||
|               height="24" |               height="24" | ||||||
|             /> |             /> | ||||||
|  | |||||||
| @ -155,19 +155,6 @@ onClickOutside(infoMenuRef, () => { | |||||||
|           > |           > | ||||||
|             <div class="mt-2"> |             <div class="mt-2"> | ||||||
|               <div class="bg-white rounded-md z-10 -left-36 w-52"> |               <div class="bg-white rounded-md z-10 -left-36 w-52"> | ||||||
|                 <RouterLink |  | ||||||
|                   :to="'/explore'" |  | ||||||
|                   class="menu-button gap-2 px-4 rounded-md cursor-pointer" |  | ||||||
|                 > |  | ||||||
|                   <span |  | ||||||
|                     class="text-gray-900 py-4 text-end font-semibold text-sm whitespace-nowrap" |  | ||||||
|                   > |  | ||||||
|                     Explorar Transações |  | ||||||
|                   </span> |  | ||||||
|                 </RouterLink> |  | ||||||
|                 <div class="w-full flex justify-center"> |  | ||||||
|                   <hr class="w-4/5" /> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="menu-button gap-2 px-4 rounded-md cursor-pointer"> |                 <div class="menu-button gap-2 px-4 rounded-md cursor-pointer"> | ||||||
|                   <span |                   <span | ||||||
|                     class="text-gray-900 py-4 text-end font-semibold text-sm" |                     class="text-gray-900 py-4 text-end font-semibold text-sm" | ||||||
| @ -425,9 +412,6 @@ onClickOutside(infoMenuRef, () => { | |||||||
|           <div class="w-full flex justify-center"> |           <div class="w-full flex justify-center"> | ||||||
|             <hr class="w-4/5" /> |             <hr class="w-4/5" /> | ||||||
|           </div> |           </div> | ||||||
|           <div class="w-full flex justify-center"> |  | ||||||
|             <hr class="w-4/5" /> |  | ||||||
|           </div> |  | ||||||
|           <div class="menu-button" @click="closeMenu()"> |           <div class="menu-button" @click="closeMenu()"> | ||||||
|             <RouterLink to="/manage_bids" class="redirect_button"> |             <RouterLink to="/manage_bids" class="redirect_button"> | ||||||
|               Gerenciar Ofertas |               Gerenciar Ofertas | ||||||
|  | |||||||
| @ -33,7 +33,7 @@ const props = withDefaults( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .form-card:not(.no-border) { | .form-card:not(.no-border) { | ||||||
|   @apply border-y; |   @apply border-y-10; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .form-card.full-width { | .form-card.full-width { | ||||||
|  | |||||||
| @ -1,475 +0,0 @@ | |||||||
| import { NetworkConfig } from '@/model/NetworkEnum'; |  | ||||||
| import { ref, computed, type Ref } from 'vue'; |  | ||||||
| import { isTestnetEnvironment } from '@/config/networks'; |  | ||||||
| import { sepolia, rootstock, rootstockTestnet } from "viem/chains"; |  | ||||||
| 
 |  | ||||||
| export interface Transaction { |  | ||||||
|   id: string; |  | ||||||
|   type: 'deposit' | 'lock' | 'release' | 'return'; |  | ||||||
|   timestamp: string; |  | ||||||
|   blockTimestamp: string; |  | ||||||
|   seller?: string; |  | ||||||
|   buyer?: string | null; |  | ||||||
|   amount: string; |  | ||||||
|   token: string; |  | ||||||
|   blockNumber: string; |  | ||||||
|   transactionHash: string; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export interface AnalyticsData { |  | ||||||
|   totalVolume: string; |  | ||||||
|   totalTransactions: string; |  | ||||||
|   totalLocks: string; |  | ||||||
|   totalDeposits: string; |  | ||||||
|   totalReleases: string; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export function useGraphQL(network: Ref<NetworkConfig>) { |  | ||||||
|   const searchAddress = ref(''); |  | ||||||
|   const selectedType = ref('all'); |  | ||||||
|   const loading = ref(false); |  | ||||||
|   const error = ref<string | null>(null); |  | ||||||
|   const analyticsLoading = ref(false); |  | ||||||
|    |  | ||||||
|   const transactionsData = ref<Transaction[]>([]); |  | ||||||
|   const analyticsData = ref<AnalyticsData>({ |  | ||||||
|     totalVolume: '0', |  | ||||||
|     totalTransactions: '0', |  | ||||||
|     totalLocks: '0', |  | ||||||
|     totalDeposits: '0', |  | ||||||
|     totalReleases: '0' |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   const getGraphQLUrl = () => { |  | ||||||
|     const rskNetworkName = isTestnetEnvironment() ? rootstockTestnet.name : rootstock.name;   |  | ||||||
|      |  | ||||||
|     switch (network.value.name) { |  | ||||||
|       case sepolia.name: |  | ||||||
|         return import.meta.env.VITE_SEPOLIA_SUBGRAPH_URL!; |  | ||||||
|       case rskNetworkName: |  | ||||||
|         return import.meta.env.VITE_RSK_SUBGRAPH_URL!; |  | ||||||
|       default: |  | ||||||
|         throw new Error(`Unsupported network: ${network.value.name}`); |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const executeQuery = async (query: string, variables: any = {}) => { |  | ||||||
|     const url = getGraphQLUrl(); |  | ||||||
|      |  | ||||||
|     try { |  | ||||||
|       const response = await fetch(url, { |  | ||||||
|         method: 'POST', |  | ||||||
|         headers: { |  | ||||||
|           'Content-Type': 'application/json', |  | ||||||
|         }, |  | ||||||
|         body: JSON.stringify({ |  | ||||||
|           query, |  | ||||||
|           variables, |  | ||||||
|         }), |  | ||||||
|       }); |  | ||||||
| 
 |  | ||||||
|       if (!response.ok) { |  | ||||||
|         throw new Error(`HTTP error! status: ${response.status}`); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       const data = await response.json(); |  | ||||||
|        |  | ||||||
|       if (data.errors) { |  | ||||||
|         throw new Error(data.errors[0]?.message || 'GraphQL error'); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       return data.data; |  | ||||||
|     } catch (err) { |  | ||||||
|       console.error('GraphQL query error:', err); |  | ||||||
|       throw err; |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const fetchAllActivity = async () => { |  | ||||||
|     loading.value = true; |  | ||||||
|     error.value = null; |  | ||||||
| 
 |  | ||||||
|     const query = ` |  | ||||||
|       query GetAllActivity($first: Int = 50) { |  | ||||||
|         depositAddeds(first: $first, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           seller |  | ||||||
|           token |  | ||||||
|           amount |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|         depositWithdrawns(first: $first, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           seller |  | ||||||
|           token |  | ||||||
|           amount |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|         lockAddeds(first: $first, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           buyer |  | ||||||
|           lockID |  | ||||||
|           seller |  | ||||||
|           amount |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|         lockReleaseds(first: $first, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           buyer |  | ||||||
|           lockId |  | ||||||
|           amount |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|         lockReturneds(first: $first, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           buyer |  | ||||||
|           lockId |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     `;
 |  | ||||||
| 
 |  | ||||||
|     try { |  | ||||||
|       const data = await executeQuery(query, { first: 50 }); |  | ||||||
|       transactionsData.value = processActivityData(data); |  | ||||||
|     } catch (err) { |  | ||||||
|       error.value = err instanceof Error ? err.message : 'Failed to fetch transactions'; |  | ||||||
|     } finally { |  | ||||||
|       loading.value = false; |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const fetchUserActivity = async (userAddress: string) => { |  | ||||||
|     loading.value = true; |  | ||||||
|     error.value = null; |  | ||||||
| 
 |  | ||||||
|     const query = ` |  | ||||||
|       query GetUserActivity($userAddress: String!, $first: Int = 50) { |  | ||||||
|         depositAddeds(first: $first, where: { seller: $userAddress }, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           seller |  | ||||||
|           token |  | ||||||
|           amount |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|         depositWithdrawns(first: $first, where: { seller: $userAddress }, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           seller |  | ||||||
|           token |  | ||||||
|           amount |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|         lockAddeds(first: $first, where: { buyer: $userAddress }, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           buyer |  | ||||||
|           lockID |  | ||||||
|           seller |  | ||||||
|           amount |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|         lockReleaseds(first: $first, where: { buyer: $userAddress }, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           buyer |  | ||||||
|           lockId |  | ||||||
|           amount |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|         lockReturneds(first: $first, where: { buyer: $userAddress }, orderBy: "blockTimestamp", orderDirection: "desc") { |  | ||||||
|           id |  | ||||||
|           buyer |  | ||||||
|           lockId |  | ||||||
|           blockNumber |  | ||||||
|           blockTimestamp |  | ||||||
|           transactionHash |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     `;
 |  | ||||||
| 
 |  | ||||||
|     try { |  | ||||||
|       const data = await executeQuery(query, { userAddress, first: 50 }); |  | ||||||
|       transactionsData.value = processActivityData(data); |  | ||||||
|     } catch (err) { |  | ||||||
|       error.value = err instanceof Error ? err.message : 'Failed to fetch user transactions'; |  | ||||||
|     } finally { |  | ||||||
|       loading.value = false; |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const clearData = () => { |  | ||||||
|     transactionsData.value = []; |  | ||||||
|     analyticsData.value = { |  | ||||||
|       totalVolume: '0', |  | ||||||
|       totalTransactions: '0', |  | ||||||
|       totalLocks: '0', |  | ||||||
|       totalDeposits: '0', |  | ||||||
|       totalReleases: '0' |  | ||||||
|     }; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const fetchAnalytics = async () => { |  | ||||||
|     analyticsLoading.value = true; |  | ||||||
| 
 |  | ||||||
|     const query = ` |  | ||||||
|       query GetAnalytics { |  | ||||||
|         depositAddeds(first: 1000) { |  | ||||||
|           amount |  | ||||||
|           blockTimestamp |  | ||||||
|         } |  | ||||||
|         depositWithdrawns(first: 1000) { |  | ||||||
|           amount |  | ||||||
|           blockTimestamp |  | ||||||
|         } |  | ||||||
|         lockAddeds(first: 1000) { |  | ||||||
|           amount |  | ||||||
|           blockTimestamp |  | ||||||
|         } |  | ||||||
|         lockReleaseds(first: 1000) { |  | ||||||
|           amount |  | ||||||
|           blockTimestamp |  | ||||||
|         } |  | ||||||
|         lockReturneds(first: 1000) { |  | ||||||
|           blockTimestamp |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     `;
 |  | ||||||
| 
 |  | ||||||
|     try { |  | ||||||
|       const data = await executeQuery(query); |  | ||||||
|       analyticsData.value = processAnalyticsData(data); |  | ||||||
|     } catch (err) { |  | ||||||
|       console.error('Failed to fetch analytics:', err); |  | ||||||
|     } finally { |  | ||||||
|       analyticsLoading.value = false; |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const processActivityData = (data: any): Transaction[] => { |  | ||||||
|     if (!data) return []; |  | ||||||
|      |  | ||||||
|     const activities: Transaction[] = []; |  | ||||||
|      |  | ||||||
|     if (data.depositAddeds) { |  | ||||||
|       data.depositAddeds.forEach((deposit: any) => { |  | ||||||
|         activities.push({ |  | ||||||
|           id: deposit.id, |  | ||||||
|           blockNumber: deposit.blockNumber, |  | ||||||
|           blockTimestamp: deposit.blockTimestamp, |  | ||||||
|           transactionHash: deposit.transactionHash, |  | ||||||
|           type: 'deposit', |  | ||||||
|           seller: deposit.seller, |  | ||||||
|           buyer: undefined, |  | ||||||
|           amount: deposit.amount, |  | ||||||
|           token: deposit.token, |  | ||||||
|           timestamp: formatTimestamp(deposit.blockTimestamp) |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     if (data.depositWithdrawns) { |  | ||||||
|       data.depositWithdrawns.forEach((withdrawal: any) => { |  | ||||||
|         activities.push({ |  | ||||||
|           id: withdrawal.id, |  | ||||||
|           blockNumber: withdrawal.blockNumber, |  | ||||||
|           blockTimestamp: withdrawal.blockTimestamp, |  | ||||||
|           transactionHash: withdrawal.transactionHash, |  | ||||||
|           type: 'deposit', // Treat as deposit withdrawal
 |  | ||||||
|           seller: withdrawal.seller, |  | ||||||
|           buyer: undefined, |  | ||||||
|           amount: withdrawal.amount, |  | ||||||
|           token: withdrawal.token, |  | ||||||
|           timestamp: formatTimestamp(withdrawal.blockTimestamp) |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     if (data.lockAddeds) { |  | ||||||
|       data.lockAddeds.forEach((lock: any) => { |  | ||||||
|         activities.push({ |  | ||||||
|           id: lock.id, |  | ||||||
|           blockNumber: lock.blockNumber, |  | ||||||
|           blockTimestamp: lock.blockTimestamp, |  | ||||||
|           transactionHash: lock.transactionHash, |  | ||||||
|           type: 'lock', |  | ||||||
|           seller: lock.seller, |  | ||||||
|           buyer: lock.buyer, |  | ||||||
|           amount: lock.amount, |  | ||||||
|           token: lock.token, |  | ||||||
|           timestamp: formatTimestamp(lock.blockTimestamp) |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     if (data.lockReleaseds) { |  | ||||||
|       data.lockReleaseds.forEach((release: any) => { |  | ||||||
|         activities.push({ |  | ||||||
|           id: release.id, |  | ||||||
|           blockNumber: release.blockNumber, |  | ||||||
|           blockTimestamp: release.blockTimestamp, |  | ||||||
|           transactionHash: release.transactionHash, |  | ||||||
|           type: 'release', |  | ||||||
|           seller: undefined, // Release doesn't have seller info
 |  | ||||||
|           buyer: release.buyer, |  | ||||||
|           amount: release.amount, |  | ||||||
|           token: 'BRZ', // Default token
 |  | ||||||
|           timestamp: formatTimestamp(release.blockTimestamp) |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     if (data.lockReturneds) { |  | ||||||
|       data.lockReturneds.forEach((returnTx: any) => { |  | ||||||
|         activities.push({ |  | ||||||
|           id: returnTx.id, |  | ||||||
|           blockNumber: returnTx.blockNumber, |  | ||||||
|           blockTimestamp: returnTx.blockTimestamp, |  | ||||||
|           transactionHash: returnTx.transactionHash, |  | ||||||
|           type: 'return', |  | ||||||
|           seller: undefined, // Return doesn't have seller info
 |  | ||||||
|           buyer: returnTx.buyer, |  | ||||||
|           amount: '0', // Return doesn't have amount
 |  | ||||||
|           token: 'BRZ', // Default token
 |  | ||||||
|           timestamp: formatTimestamp(returnTx.blockTimestamp) |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     return activities.sort((a, b) => parseInt(b.blockTimestamp) - parseInt(a.blockTimestamp)); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const formatTimestamp = (timestamp: string): string => { |  | ||||||
|     const now = Date.now() / 1000; |  | ||||||
|     const diff = now - parseInt(timestamp); |  | ||||||
|      |  | ||||||
|     if (diff < 60) return 'Just now'; |  | ||||||
|     if (diff < 3600) return `${Math.floor(diff / 60)} minutes ago`; |  | ||||||
|     if (diff < 86400) return `${Math.floor(diff / 3600)} hours ago`; |  | ||||||
|     return `${Math.floor(diff / 86400)} days ago`; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const formatAmount = (amount: string): string => { |  | ||||||
|     const num = parseFloat(amount); |  | ||||||
|     if (num >= 1000000000000000) return `${(num / 1000000000000000).toFixed(1)}Q`; |  | ||||||
|     if (num >= 1000000000000) return `${(num / 1000000000000).toFixed(1)}T`; |  | ||||||
|     if (num >= 1000000000) return `${(num / 1000000000).toFixed(1)}B`; |  | ||||||
|     if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`; |  | ||||||
|     if (num >= 1000) return `${(num / 1000).toFixed(1)}K`; |  | ||||||
|     if (num < 1) return num.toFixed(4); |  | ||||||
|     return num.toFixed(2); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const processAnalyticsData = (data: any): AnalyticsData => { |  | ||||||
|     if (!data) { |  | ||||||
|       return { |  | ||||||
|         totalVolume: '0', |  | ||||||
|         totalTransactions: '0', |  | ||||||
|         totalLocks: '0', |  | ||||||
|         totalDeposits: '0', |  | ||||||
|         totalReleases: '0' |  | ||||||
|       }; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     let totalVolume = 0; |  | ||||||
|     let totalTransactions = 0; |  | ||||||
|     let totalLocks = 0; |  | ||||||
|     let totalDeposits = 0; |  | ||||||
|     let totalReleases = 0; |  | ||||||
| 
 |  | ||||||
|     if (data.depositAddeds) { |  | ||||||
|       data.depositAddeds.forEach((deposit: any) => { |  | ||||||
|         totalVolume += parseFloat(deposit.amount || '0'); |  | ||||||
|         totalTransactions++; |  | ||||||
|         totalDeposits++; |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (data.depositWithdrawns) { |  | ||||||
|       data.depositWithdrawns.forEach((withdrawal: any) => { |  | ||||||
|         totalVolume += parseFloat(withdrawal.amount || '0'); |  | ||||||
|         totalTransactions++; |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (data.lockAddeds) { |  | ||||||
|       data.lockAddeds.forEach((lock: any) => { |  | ||||||
|         totalVolume += parseFloat(lock.amount || '0'); |  | ||||||
|         totalTransactions++; |  | ||||||
|         totalLocks++; |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (data.lockReleaseds) { |  | ||||||
|       data.lockReleaseds.forEach((release: any) => { |  | ||||||
|         totalVolume += parseFloat(release.amount || '0'); |  | ||||||
|         totalTransactions++; |  | ||||||
|         totalReleases++; |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     if (data.lockReturneds) { |  | ||||||
|       data.lockReturneds.forEach((returnTx: any) => { |  | ||||||
|         totalTransactions++; |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const result = { |  | ||||||
|       totalVolume: formatAmount(totalVolume.toString()), |  | ||||||
|       totalTransactions: totalTransactions.toString(), |  | ||||||
|       totalLocks: totalLocks.toString(), |  | ||||||
|       totalDeposits: totalDeposits.toString(), |  | ||||||
|       totalReleases: totalReleases.toString() |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     return result; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const filteredTransactions = computed(() => { |  | ||||||
|     let filtered = transactionsData.value; |  | ||||||
|      |  | ||||||
|     if (selectedType.value !== 'all') { |  | ||||||
|       filtered = filtered.filter(tx => tx.type === selectedType.value); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     if (searchAddress.value) { |  | ||||||
|       const searchLower = searchAddress.value.toLowerCase(); |  | ||||||
|       filtered = filtered.filter(tx =>  |  | ||||||
|         tx.seller?.toLowerCase().includes(searchLower) || |  | ||||||
|         tx.buyer?.toLowerCase().includes(searchLower) |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     return filtered; |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   return { |  | ||||||
|     searchAddress, |  | ||||||
|     selectedType, |  | ||||||
|     transactions: filteredTransactions, |  | ||||||
|     analytics: analyticsData, |  | ||||||
|     loading, |  | ||||||
|     error, |  | ||||||
|     analyticsLoading, |  | ||||||
|     fetchAllActivity, |  | ||||||
|     fetchUserActivity, |  | ||||||
|     fetchAnalytics, |  | ||||||
|     clearData |  | ||||||
|   }; |  | ||||||
| } |  | ||||||
| @ -1,28 +1,22 @@ | |||||||
| import { sepolia, rootstock, rootstockTestnet } from "viem/chains"; | import { sepolia, rootstockTestnet } from "viem/chains"; | ||||||
| import { NetworkConfig } from "@/model/NetworkEnum" | import { NetworkConfig } from "@/model/NetworkEnum" | ||||||
| // TODO: import addresses from p2pix-smart-contracts deployments
 | // TODO: import addresses from p2pix-smart-contracts deployments
 | ||||||
| 
 | 
 | ||||||
| export const isTestnetEnvironment = () => { |  | ||||||
|   return import.meta.env.VITE_ENVIRONMENT === 'testnet' ||  |  | ||||||
|          import.meta.env.NODE_ENV === 'development' || |  | ||||||
|          import.meta.env.MODE === 'development'; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| export const Networks: {[key:string]: NetworkConfig} = { | export const Networks: {[key:string]: NetworkConfig} = { | ||||||
|   sepolia: { ...sepolia, |   sepolia: { ...sepolia, | ||||||
|     rpcUrls: { default: { http: [import.meta.env.VITE_SEPOLIA_API_URL]}}, |     rpcUrls: { default: { http: [import.meta.env.VITE_SEPOLIA_API_URL]}}, | ||||||
|     contracts: { ...sepolia.contracts, |     contracts: { ...sepolia.contracts, | ||||||
|       p2pix: { address: import.meta.env.VITE_SEPOLIA_P2PIX_ADDRESS } }, |       p2pix: {address:"0xb7cD135F5eFD9760981e02E2a898790b688939fe"} }, | ||||||
|     tokens: { |     tokens: { | ||||||
|       BRZ: { address: import.meta.env.VITE_SEPOLIA_TOKEN_ADDRESS } }, |       BRZ: {address:"0x3eBE67A2C7bdB2081CBd34ba3281E90377462289"} }, | ||||||
|     subgraphUrls: [import.meta.env.VITE_SEPOLIA_SUBGRAPH_URL] |     subgraphUrls: [import.meta.env.VITE_SEPOLIA_SUBGRAPH_URL] | ||||||
|   }, |   }, | ||||||
|   rootstock: { ...(isTestnetEnvironment() ? rootstockTestnet : rootstock), |   rootstockTestnet: { ...rootstockTestnet, | ||||||
|     rpcUrls: { default: { http: [import.meta.env.VITE_RSK_API_URL]}}, |     rpcUrls: { default: { http: [import.meta.env.VITE_RSK_API_URL]}}, | ||||||
|     contracts: { ...(isTestnetEnvironment() ? rootstockTestnet.contracts : rootstock.contracts), |     contracts: { ...rootstockTestnet.contracts, | ||||||
|       p2pix: { address: import.meta.env.VITE_RSK_P2PIX_ADDRESS } }, |       p2pix: {address:"0x57Dcba05980761169508886eEdc6f5E7EC0411Dc"} }, | ||||||
|     tokens: { |     tokens: { | ||||||
|       BRZ: { address: import.meta.env.VITE_RSK_TOKEN_ADDRESS } }, |       BRZ: {address:"0xfE841c74250e57640390f46d914C88d22C51e82e"} }, | ||||||
|     subgraphUrls: [import.meta.env.VITE_RSK_SUBGRAPH_URL] |     subgraphUrls: [import.meta.env.VITE_RSK_SUBGRAPH_URL] | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -1,14 +1,11 @@ | |||||||
| import { createRouter, createWebHistory, createWebHashHistory } from "vue-router"; | import { createRouter, createWebHistory } from "vue-router"; | ||||||
| import HomeView from "@/views/HomeView.vue"; | import HomeView from "@/views/HomeView.vue"; | ||||||
| import FaqView from "@/views/FaqView.vue"; | import FaqView from "@/views/FaqView.vue"; | ||||||
| import ManageBidsView from "@/views/ManageBidsView.vue"; | import ManageBidsView from "@/views/ManageBidsView.vue"; | ||||||
| import SellerView from "@/views/SellerView.vue"; | import SellerView from "@/views/SellerView.vue"; | ||||||
| import ExploreView from "@/views/ExploreView.vue"; |  | ||||||
| 
 | 
 | ||||||
| const router = createRouter({ | const router = createRouter({ | ||||||
|   history: import.meta.env.MODE === 'production' && import.meta.env.BASE_URL === './'  |   history: createWebHistory(import.meta.env.BASE_URL), | ||||||
|     ? createWebHashHistory()  |  | ||||||
|     : createWebHistory(import.meta.env.BASE_URL), |  | ||||||
|   routes: [ |   routes: [ | ||||||
|     { |     { | ||||||
|       path: "/", |       path: "/", | ||||||
| @ -36,11 +33,6 @@ const router = createRouter({ | |||||||
|       name: "faq", |       name: "faq", | ||||||
|       component: FaqView, |       component: FaqView, | ||||||
|     }, |     }, | ||||||
|     { |  | ||||||
|       path: "/explore", |  | ||||||
|       name: "explore", |  | ||||||
|       component: ExploreView, |  | ||||||
|     }, |  | ||||||
|   ], |   ], | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,163 +0,0 @@ | |||||||
| <script setup lang="ts"> |  | ||||||
| import { onMounted, watch } from 'vue'; |  | ||||||
| import { useUser } from '@/composables/useUser'; |  | ||||||
| import { useGraphQL } from '@/composables/useGraphQL'; |  | ||||||
| import FormCard from '@/components/ui/FormCard.vue'; |  | ||||||
| import LoadingComponent from '@/components/ui/LoadingComponent.vue'; |  | ||||||
| import AnalyticsCard from '@/components/Explorer/AnalyticsCard.vue'; |  | ||||||
| import TransactionTable from '@/components/Explorer/TransactionTable.vue'; |  | ||||||
| 
 |  | ||||||
| const user = useUser(); |  | ||||||
| const { network } = user; |  | ||||||
| 
 |  | ||||||
| const { |  | ||||||
|   searchAddress, |  | ||||||
|   selectedType, |  | ||||||
|   transactions, |  | ||||||
|   analytics, |  | ||||||
|   loading, |  | ||||||
|   error, |  | ||||||
|   analyticsLoading, |  | ||||||
|   fetchAllActivity, |  | ||||||
|   fetchUserActivity, |  | ||||||
|   fetchAnalytics, |  | ||||||
|   clearData |  | ||||||
| } = useGraphQL(network); |  | ||||||
| 
 |  | ||||||
| const transactionTypes = [ |  | ||||||
|   { key: 'all', label: 'Todas' }, |  | ||||||
|   { key: 'deposit', label: 'Depósitos' }, |  | ||||||
|   { key: 'lock', label: 'Bloqueios' }, |  | ||||||
|   { key: 'release', label: 'Liberações' }, |  | ||||||
|   { key: 'return', label: 'Retornos' } |  | ||||||
| ]; |  | ||||||
| 
 |  | ||||||
| const handleTypeFilter = (type: string) => { |  | ||||||
|   selectedType.value = type; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| watch(searchAddress, async (newAddress) => { |  | ||||||
|   if (newAddress.trim()) { |  | ||||||
|     await fetchUserActivity(newAddress.trim()); |  | ||||||
|   } else { |  | ||||||
|     await fetchAllActivity(); |  | ||||||
|   } |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| watch(network, async () => { |  | ||||||
|   clearData(); |  | ||||||
|   await Promise.all([ |  | ||||||
|     fetchAllActivity(), |  | ||||||
|     fetchAnalytics() |  | ||||||
|   ]); |  | ||||||
| }, { deep: true }); |  | ||||||
| 
 |  | ||||||
| onMounted(async () => { |  | ||||||
|   await Promise.all([ |  | ||||||
|     fetchAllActivity(), |  | ||||||
|     fetchAnalytics() |  | ||||||
|   ]); |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <template> |  | ||||||
|   <div class="min-h-screen"> |  | ||||||
|     <div class="container mx-auto px-4 py-8"> |  | ||||||
| 
 |  | ||||||
|       <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4 mb-8"> |  | ||||||
|         <AnalyticsCard |  | ||||||
|           title="Volume Total" |  | ||||||
|           :value="analytics.totalVolume" |  | ||||||
|           :loading="analyticsLoading" |  | ||||||
|         /> |  | ||||||
|          |  | ||||||
|         <AnalyticsCard |  | ||||||
|           title="Total de Transações" |  | ||||||
|           :value="analytics.totalTransactions" |  | ||||||
|           :loading="analyticsLoading" |  | ||||||
|         /> |  | ||||||
|          |  | ||||||
|         <AnalyticsCard |  | ||||||
|           title="Total de Bloqueios" |  | ||||||
|           :value="analytics.totalLocks" |  | ||||||
|           :loading="analyticsLoading" |  | ||||||
|         /> |  | ||||||
|          |  | ||||||
|         <AnalyticsCard |  | ||||||
|           title="Total de Depósitos" |  | ||||||
|           :value="analytics.totalDeposits" |  | ||||||
|           :loading="analyticsLoading" |  | ||||||
|         /> |  | ||||||
|          |  | ||||||
|         <AnalyticsCard |  | ||||||
|           title="Total de Liberações" |  | ||||||
|           :value="analytics.totalReleases" |  | ||||||
|           :loading="analyticsLoading" |  | ||||||
|         /> |  | ||||||
|       </div> |  | ||||||
| 
 |  | ||||||
|       <!-- Search and Filters --> |  | ||||||
|       <FormCard padding="lg" class="mb-6"> |  | ||||||
|         <div class="space-y-4"> |  | ||||||
|           <!-- Search Input --> |  | ||||||
|           <div class="flex-1"> |  | ||||||
|             <input |  | ||||||
|               v-model="searchAddress" |  | ||||||
|               type="text" |  | ||||||
|               placeholder="Buscar por endereço de carteira..." |  | ||||||
|               class="w-full px-4 py-3 bg-gray-50 border border-gray-300 rounded-lg text-gray-900 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-amber-400 focus:border-transparent" |  | ||||||
|             /> |  | ||||||
|           </div> |  | ||||||
| 
 |  | ||||||
|           <!-- Type Filters --> |  | ||||||
|           <div class="flex flex-wrap gap-2"> |  | ||||||
|             <button |  | ||||||
|               v-for="type in transactionTypes" |  | ||||||
|               :key="type.key" |  | ||||||
|               @click="handleTypeFilter(type.key)" |  | ||||||
|               :class="[ |  | ||||||
|                 'px-4 py-2 rounded-lg text-sm font-medium transition-colors', |  | ||||||
|                 selectedType === type.key |  | ||||||
|                   ? 'bg-amber-400 text-gray-900' |  | ||||||
|                   : 'bg-gray-100 text-gray-700 hover:bg-gray-200' |  | ||||||
|               ]" |  | ||||||
|             > |  | ||||||
|               {{ type.label }} |  | ||||||
|             </button> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </FormCard> |  | ||||||
| 
 |  | ||||||
|       <!-- Loading State --> |  | ||||||
|       <div v-if="loading" class="text-center py-12"> |  | ||||||
|         <LoadingComponent title="Carregando transações..." /> |  | ||||||
|       </div> |  | ||||||
| 
 |  | ||||||
|       <!-- Error State --> |  | ||||||
|       <div v-else-if="error" class="text-center py-12"> |  | ||||||
|         <div class="text-red-600 text-lg mb-2">⚠️</div> |  | ||||||
|         <p class="text-red-600 mb-2">Erro ao carregar transações</p> |  | ||||||
|         <p class="text-gray-600 text-sm">{{ error }}</p> |  | ||||||
|       </div> |  | ||||||
| 
 |  | ||||||
|       <!-- Transactions Table --> |  | ||||||
|       <FormCard v-else padding="lg"> |  | ||||||
|         <div class="mb-6"> |  | ||||||
|           <h2 class="text-xl font-semibold text-gray-900 mb-2">Transações Recentes</h2> |  | ||||||
|           <p class="text-gray-600">{{ transactions.length }} transações encontradas</p> |  | ||||||
|         </div> |  | ||||||
| 
 |  | ||||||
|         <TransactionTable  |  | ||||||
|           :transactions="transactions" |  | ||||||
|           :network-explorer-url="network.blockExplorers?.default.url || ''" |  | ||||||
|         /> |  | ||||||
|       </FormCard> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
| 
 |  | ||||||
| <style scoped> |  | ||||||
| .container { |  | ||||||
|   max-width: 1200px; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @ -69,7 +69,7 @@ const sendNetwork = async () => { | |||||||
|     /> |     /> | ||||||
|     <div v-if="flowStep == Step.Network"> |     <div v-if="flowStep == Step.Network"> | ||||||
|       <SendNetwork |       <SendNetwork | ||||||
|         :sellerId="String(user.sellerId.value)" |         :sellerId="Number(user.sellerId.value)" | ||||||
|         :offer="Number(user.seller.value.offer)" |         :offer="Number(user.seller.value.offer)" | ||||||
|         :selected-token="user.selectedToken.value" |         :selected-token="user.selectedToken.value" | ||||||
|         v-if="!loading" |         v-if="!loading" | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ import svgLoader from "vite-svg-loader"; | |||||||
| 
 | 
 | ||||||
| // https://vitejs.dev/config/
 | // https://vitejs.dev/config/
 | ||||||
| export default defineConfig({ | export default defineConfig({ | ||||||
|   base: "./", |  | ||||||
|   build: { |   build: { | ||||||
|     target: "esnext", |     target: "esnext", | ||||||
|   }, |   }, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user