From 872d69881fcfb098581729386df2ee9407112f61 Mon Sep 17 00:00:00 2001 From: Alex PC Date: Thu, 22 Jan 2026 17:02:56 +0100 Subject: [PATCH 1/3] Add amazing feature --- src/app/page.tsx | 11 +- src/app/properties/page.tsx | 108 ++++++++ src/components/FilterSidebar.tsx | 305 ++++++++++++++++++++++ src/components/PropertyCard.tsx | 162 ++++++++++++ src/components/PropertySearch.tsx | 214 ++++++++++++++++ src/components/SearchResults.tsx | 209 +++++++++++++++ src/config/chains.ts | 26 +- src/hooks/useDebounce.ts | 24 ++ src/hooks/usePropertySearch.ts | 132 ++++++++++ src/lib/mockData.ts | 412 ++++++++++++++++++++++++++++++ src/lib/propertyService.ts | 277 ++++++++++++++++++++ src/store/savedSearchStore.ts | 70 +++++ src/store/searchStore.ts | 145 +++++++++++ src/store/walletStore.ts | 2 +- src/types/property.ts | 169 ++++++++++++ src/utils/searchUtils.ts | 211 +++++++++++++++ 16 files changed, 2473 insertions(+), 4 deletions(-) create mode 100644 src/app/properties/page.tsx create mode 100644 src/components/FilterSidebar.tsx create mode 100644 src/components/PropertyCard.tsx create mode 100644 src/components/PropertySearch.tsx create mode 100644 src/components/SearchResults.tsx create mode 100644 src/hooks/useDebounce.ts create mode 100644 src/hooks/usePropertySearch.ts create mode 100644 src/lib/mockData.ts create mode 100644 src/lib/propertyService.ts create mode 100644 src/store/savedSearchStore.ts create mode 100644 src/store/searchStore.ts create mode 100644 src/types/property.ts create mode 100644 src/utils/searchUtils.ts diff --git a/src/app/page.tsx b/src/app/page.tsx index ff82b426..a85b96ee 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -55,9 +55,18 @@ function HomeContent() {

Multi-Chain Real Estate Platform

-

+

Experience seamless wallet connectivity across Ethereum, Polygon, and Binance Smart Chain

+ + + + + Browse Properties + setStoreViewMode(mode); + + const { + filters, + sortBy, + page, + properties, + totalResults, + totalPages, + isLoading, + error, + setFilter, + clearFilters, + setSortBy, + setPage, + } = usePropertySearch(); + + return ( +
+ {/* Header */} +
+
+
+ +
+ PC +
+

+ PropChain +

+ + +
+
+
+ + {/* Main Content */} +
+ {/* Search Bar */} +
+

+ Discover Tokenized Real Estate +

+ setFilter('query', value)} + /> +
+ + {/* Layout: Sidebar + Results */} +
+ {/* Filter Sidebar */} + + + {/* Search Results */} + +
+
+
+ ); +} + +export default function PropertiesPage() { + return ( + +
+
+

Loading properties...

+
+
+ }> + +
+ ); +} diff --git a/src/components/FilterSidebar.tsx b/src/components/FilterSidebar.tsx new file mode 100644 index 00000000..b195e55d --- /dev/null +++ b/src/components/FilterSidebar.tsx @@ -0,0 +1,305 @@ +'use client'; + +import React, { useState } from 'react'; +import type { SearchFilters, PropertyType, BlockchainNetwork } from '@/types/property'; +import { PROPERTY_TYPE_LABELS, BLOCKCHAIN_LABELS } from '@/types/property'; + +interface FilterSidebarProps { + filters: SearchFilters; + onFilterChange: (key: K, value: SearchFilters[K]) => void; + onClearFilters: () => void; +} + +export const FilterSidebar: React.FC = ({ + filters, + onFilterChange, + onClearFilters, +}) => { + const [isOpen, setIsOpen] = useState(false); + + const togglePropertyType = (type: PropertyType) => { + const current = filters.propertyTypes || []; + const updated = current.includes(type) + ? current.filter(t => t !== type) + : [...current, type]; + onFilterChange('propertyTypes', updated); + }; + + const toggleBlockchain = (chain: BlockchainNetwork) => { + const current = filters.blockchains || []; + const updated = current.includes(chain) + ? current.filter(c => c !== chain) + : [...current, chain]; + onFilterChange('blockchains', updated); + }; + + const hasActiveFilters = () => { + return ( + filters.priceRange[0] > 0 || + filters.priceRange[1] < 10000000 || + filters.propertyTypes.length > 0 || + filters.blockchains.length > 0 || + filters.roiMin > 0 || + filters.roiMax < 100 || + filters.location || + filters.bedrooms.length > 0 || + filters.bathrooms.length > 0 || + filters.squareFeetRange[0] > 0 || + filters.squareFeetRange[1] < 50000 + ); + }; + + return ( + <> + {/* Mobile Filter Button */} + + + {/* Overlay for mobile */} + {isOpen && ( +
setIsOpen(false)} + /> + )} + + {/* Sidebar */} +
+
+ {/* Header */} +
+

Filters

+
+ {hasActiveFilters() && ( + + )} + +
+
+ + {/* Price Range */} +
+ +
+
+ + onFilterChange('priceRange', [Number(e.target.value), filters.priceRange[1]])} + className="w-full mt-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white" + placeholder="$0" + /> +
+
+ + onFilterChange('priceRange', [filters.priceRange[0], Number(e.target.value)])} + className="w-full mt-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white" + placeholder="$10,000,000" + /> +
+
+
+ + {/* Property Type */} +
+ +
+ {(Object.keys(PROPERTY_TYPE_LABELS) as PropertyType[]).map((type) => ( + + ))} +
+
+ + {/* Blockchain */} +
+ +
+ {(Object.keys(BLOCKCHAIN_LABELS) as BlockchainNetwork[]).map((chain) => ( + + ))} +
+
+ + {/* ROI Range */} +
+ +
+
+ + onFilterChange('roiMin', Number(e.target.value))} + className="w-full mt-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white" + placeholder="0%" + min="0" + max="100" + /> +
+
+ + onFilterChange('roiMax', Number(e.target.value))} + className="w-full mt-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white" + placeholder="100%" + min="0" + max="100" + /> +
+
+
+ + {/* Bedrooms */} +
+ +
+ {[1, 2, 3, 4, 5].map((num) => ( + + ))} +
+
+ + {/* Bathrooms */} +
+ +
+ {[1, 2, 3, 4].map((num) => ( + + ))} +
+
+ + {/* Square Feet */} +
+ +
+
+ + onFilterChange('squareFeetRange', [Number(e.target.value), filters.squareFeetRange[1]])} + className="w-full mt-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white" + placeholder="0" + /> +
+
+ + onFilterChange('squareFeetRange', [filters.squareFeetRange[0], Number(e.target.value)])} + className="w-full mt-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white" + placeholder="50,000" + /> +
+
+
+
+
+ + ); +}; diff --git a/src/components/PropertyCard.tsx b/src/components/PropertyCard.tsx new file mode 100644 index 00000000..106e8c39 --- /dev/null +++ b/src/components/PropertyCard.tsx @@ -0,0 +1,162 @@ +'use client'; + +import React from 'react'; +import Image from 'next/image'; +import Link from 'next/link'; +import type { Property } from '@/types/property'; +import { formatPrice, formatROI, getBlockchainColor, getPropertyTypeIcon } from '@/utils/searchUtils'; +import { BLOCKCHAIN_LABELS, PROPERTY_TYPE_LABELS } from '@/types/property'; + +interface PropertyCardProps { + property: Property; + viewMode?: 'grid' | 'list'; +} + +export const PropertyCard: React.FC = ({ + property, + viewMode = 'grid' +}) => { + const isListView = viewMode === 'list'; + + return ( + + {/* Image */} +
+ {property.name} + + {/* Badges */} +
+ {property.featured && ( + + ⭐ Featured + + )} + {property.verified && ( + + ✓ Verified + + )} +
+ + {/* ROI Badge */} +
+
+ {formatROI(property.metrics.roi)} ROI +
+
+ + {/* Blockchain Badge */} +
+
+
+ {BLOCKCHAIN_LABELS[property.blockchain]} +
+
+
+ + {/* Content */} +
+ {/* Property Type */} +
+ {getPropertyTypeIcon(property.propertyType)} + + {PROPERTY_TYPE_LABELS[property.propertyType]} + +
+ + {/* Title */} +

+ {property.name} +

+ + {/* Location */} +
+ + + + + + {property.location.city}, {property.location.state} + +
+ + {/* Description */} + {isListView && ( +

+ {property.description} +

+ )} + + {/* Details */} + {property.details.bedrooms && ( +
+ {property.details.bedrooms && ( +
+ + + + {property.details.bedrooms} bed +
+ )} + {property.details.bathrooms && ( +
+ + + + {property.details.bathrooms} bath +
+ )} +
+ + + + {property.details.squareFeet.toLocaleString()} sqft +
+
+ )} + + {/* Token Info */} +
+
+

Available Tokens

+

+ {property.tokenInfo.available.toLocaleString()} / {property.tokenInfo.totalSupply.toLocaleString()} +

+
+
+

Per Token

+

+ {formatPrice(property.price.perToken)} +

+
+
+ + {/* Price and CTA */} +
+
+

Total Value

+

+ {formatPrice(property.price.total)} +

+
+ +
+
+ + ); +}; diff --git a/src/components/PropertySearch.tsx b/src/components/PropertySearch.tsx new file mode 100644 index 00000000..7efd3a55 --- /dev/null +++ b/src/components/PropertySearch.tsx @@ -0,0 +1,214 @@ +'use client'; + +import React, { useState, useRef, useEffect } from 'react'; +import { useDebounce } from '@/hooks/useDebounce'; +import { propertyService } from '@/lib/propertyService'; +import type { AutocompleteResult } from '@/types/property'; + +interface PropertySearchProps { + value: string; + onChange: (value: string) => void; + placeholder?: string; +} + +export const PropertySearch: React.FC = ({ + value, + onChange, + placeholder = 'Search properties, locations...', +}) => { + const [isFocused, setIsFocused] = useState(false); + const [suggestions, setSuggestions] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [selectedIndex, setSelectedIndex] = useState(-1); + const inputRef = useRef(null); + const dropdownRef = useRef(null); + + const debouncedValue = useDebounce(value, 300); + + // Fetch suggestions when debounced value changes + useEffect(() => { + if (debouncedValue && debouncedValue.length >= 2) { + fetchSuggestions(debouncedValue); + } else { + setSuggestions([]); + } + }, [debouncedValue]); + + // Close dropdown when clicking outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) && + inputRef.current && + !inputRef.current.contains(event.target as Node) + ) { + setIsFocused(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + const fetchSuggestions = async (query: string) => { + setIsLoading(true); + try { + const results = await propertyService.getAutocompleteSuggestions(query); + setSuggestions(results); + } catch (error) { + console.error('Failed to fetch suggestions:', error); + setSuggestions([]); + } finally { + setIsLoading(false); + } + }; + + const handleInputChange = (e: React.ChangeEvent) => { + onChange(e.target.value); + setSelectedIndex(-1); + }; + + const handleSuggestionClick = (suggestion: AutocompleteResult) => { + onChange(suggestion.value); + setSuggestions([]); + setIsFocused(false); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (!suggestions.length) return; + + switch (e.key) { + case 'ArrowDown': + e.preventDefault(); + setSelectedIndex(prev => + prev < suggestions.length - 1 ? prev + 1 : prev + ); + break; + + case 'ArrowUp': + e.preventDefault(); + setSelectedIndex(prev => (prev > 0 ? prev - 1 : -1)); + break; + + case 'Enter': + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < suggestions.length) { + handleSuggestionClick(suggestions[selectedIndex]); + } + break; + + case 'Escape': + setIsFocused(false); + setSuggestions([]); + break; + } + }; + + const handleClear = () => { + onChange(''); + setSuggestions([]); + inputRef.current?.focus(); + }; + + const showDropdown = isFocused && (suggestions.length > 0 || isLoading); + + return ( +
+ {/* Search Input */} +
+
+ + + +
+ + setIsFocused(true)} + onKeyDown={handleKeyDown} + placeholder={placeholder} + className="w-full pl-12 pr-12 py-3 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500" + /> + + {value && ( + + )} +
+ + {/* Autocomplete Dropdown */} + {showDropdown && ( +
+ {isLoading ? ( +
+
+ Searching... +
+ ) : ( +
+ {suggestions.map((suggestion, index) => ( + + ))} +
+ )} +
+ )} +
+ ); +}; diff --git a/src/components/SearchResults.tsx b/src/components/SearchResults.tsx new file mode 100644 index 00000000..e915429f --- /dev/null +++ b/src/components/SearchResults.tsx @@ -0,0 +1,209 @@ +'use client'; + +import React from 'react'; +import { PropertyCard } from './PropertyCard'; +import type { Property, ViewMode, SortOption } from '@/types/property'; +import { SORT_LABELS } from '@/types/property'; + +interface SearchResultsProps { + properties: Property[]; + totalResults: number; + isLoading: boolean; + error: string | null; + viewMode: 'grid' | 'list'; + sortBy: SortOption; + page: number; + totalPages: number; + onViewModeChange: (mode: 'grid' | 'list') => void; + onSortChange: (sort: SortOption) => void; + onPageChange: (page: number) => void; +} + +export const SearchResults: React.FC = ({ + properties, + totalResults, + isLoading, + error, + viewMode, + sortBy, + page, + totalPages, + onViewModeChange, + onSortChange, + onPageChange, +}) => { + if (error) { + return ( +
+ + + +

+ Oops! Something went wrong +

+

{error}

+
+ ); + } + + return ( +
+ {/* Header */} +
+
+

+ {isLoading ? 'Searching...' : `${totalResults} Properties Found`} +

+ {page > 1 && ( +

+ Page {page} of {totalPages} +

+ )} +
+ +
+ {/* Sort Dropdown */} + + + {/* View Mode Toggle */} +
+ + +
+
+
+ + {/* Loading State */} + {isLoading && ( +
+ {[...Array(6)].map((_, i) => ( +
+
+
+
+
+
+
+
+ ))} +
+ )} + + {/* Empty State */} + {!isLoading && properties.length === 0 && ( +
+ + + +

+ No properties found +

+

+ Try adjusting your filters or search criteria to find more properties. +

+
+ )} + + {/* Results Grid/List */} + {!isLoading && properties.length > 0 && ( + <> +
+ {properties.map((property) => ( + + ))} +
+ + {/* Pagination */} + {totalPages > 1 && ( +
+ + +
+ {[...Array(Math.min(totalPages, 5))].map((_, i) => { + let pageNum; + if (totalPages <= 5) { + pageNum = i + 1; + } else if (page <= 3) { + pageNum = i + 1; + } else if (page >= totalPages - 2) { + pageNum = totalPages - 4 + i; + } else { + pageNum = page - 2 + i; + } + + return ( + + ); + })} +
+ + +
+ )} + + )} +
+ ); +}; diff --git a/src/config/chains.ts b/src/config/chains.ts index be94e973..96452496 100644 --- a/src/config/chains.ts +++ b/src/config/chains.ts @@ -1,6 +1,28 @@ -import { Chain } from 'wagmi'; +/** + * Blockchain Network Configuration + * Supported chains for PropChain platform + */ -export const SUPPORTED_CHAINS: Chain[] = [ +export interface ChainConfig { + id: number; + name: string; + network: string; + nativeCurrency: { + decimals: number; + name: string; + symbol: string; + }; + rpcUrls: { + public: { http: string[] }; + default: { http: string[] }; + }; + blockExplorers: { + default: { name: string; url: string }; + }; + testnet: boolean; +} + +export const SUPPORTED_CHAINS: ChainConfig[] = [ { id: 1, name: 'Ethereum', diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts new file mode 100644 index 00000000..11163f1b --- /dev/null +++ b/src/hooks/useDebounce.ts @@ -0,0 +1,24 @@ +import { useEffect, useState } from 'react'; + +/** + * Custom hook for debouncing values + * Useful for search inputs to reduce API calls + */ + +export function useDebounce(value: T, delay: number = 500): T { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + // Set up the timeout + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + // Clean up the timeout if value changes before delay + return () => { + clearTimeout(handler); + }; + }, [value, delay]); + + return debouncedValue; +} diff --git a/src/hooks/usePropertySearch.ts b/src/hooks/usePropertySearch.ts new file mode 100644 index 00000000..11a8895d --- /dev/null +++ b/src/hooks/usePropertySearch.ts @@ -0,0 +1,132 @@ +import { useEffect, useState } from 'react'; +import { useSearchStore } from '@/store/searchStore'; +import { propertyService } from '@/lib/propertyService'; +import { useSearchParams, useRouter } from 'next/navigation'; +import { filtersToUrlParams, urlParamsToFilters } from '@/utils/searchUtils'; + +/** + * Custom hook for property search functionality + * Combines search store, API calls, and URL synchronization + */ + +export function usePropertySearch() { + const router = useRouter(); + const searchParams = useSearchParams(); + const [isInitialized, setIsInitialized] = useState(false); + + const { + filters, + sortBy, + page, + resultsPerPage, + properties, + totalResults, + isLoading, + error, + setFilters, + setFilter, + clearFilters, + setSortBy, + setPage, + setProperties, + setLoading, + setError, + } = useSearchStore(); + + // Initialize from URL parameters on mount + useEffect(() => { + if (!isInitialized && searchParams) { + const { filters: urlFilters, sortBy: urlSortBy } = urlParamsToFilters(searchParams); + + if (Object.keys(urlFilters).length > 0) { + setFilters(urlFilters); + } + + if (urlSortBy && urlSortBy !== sortBy) { + setSortBy(urlSortBy); + } + + setIsInitialized(true); + } + }, [searchParams, isInitialized]); + + // Sync URL with state changes + useEffect(() => { + if (isInitialized) { + const params = filtersToUrlParams(filters, sortBy); + const currentParams = searchParams?.toString() || ''; + + if (params !== currentParams) { + router.push(`/properties?${params}`, { scroll: false }); + } + } + }, [filters, sortBy, isInitialized]); + + // Fetch properties when filters, sort, or page changes + useEffect(() => { + if (isInitialized) { + fetchProperties(); + } + }, [filters, sortBy, page, resultsPerPage, isInitialized]); + + const fetchProperties = async () => { + setLoading(true); + setError(null); + + try { + const result = await propertyService.searchProperties( + filters, + sortBy, + page, + resultsPerPage + ); + + setProperties(result.properties, result.total); + } catch (err: any) { + setError(err.message || 'Failed to fetch properties'); + setProperties([], 0); + } + }; + + const handleFilterChange = ( + key: K, + value: typeof filters[K] + ) => { + setFilter(key, value); + }; + + const handleClearFilters = () => { + clearFilters(); + }; + + const handleSortChange = (newSortBy: typeof sortBy) => { + setSortBy(newSortBy); + }; + + const handlePageChange = (newPage: number) => { + setPage(newPage); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + const totalPages = Math.ceil(totalResults / resultsPerPage); + + return { + // State + filters, + sortBy, + page, + resultsPerPage, + properties, + totalResults, + totalPages, + isLoading, + error, + + // Actions + setFilter: handleFilterChange, + clearFilters: handleClearFilters, + setSortBy: handleSortChange, + setPage: handlePageChange, + refetch: fetchProperties, + }; +} diff --git a/src/lib/mockData.ts b/src/lib/mockData.ts new file mode 100644 index 00000000..d64eb63a --- /dev/null +++ b/src/lib/mockData.ts @@ -0,0 +1,412 @@ +import type { Property, BlockchainNetwork } from '@/types/property'; + +/** + * Mock Property Data + * Sample tokenized real estate properties for development and testing + */ + +export const MOCK_PROPERTIES: Property[] = [ + { + id: '1', + name: 'Luxury Downtown Penthouse', + description: 'Stunning penthouse in the heart of Manhattan with panoramic city views. Premium finishes, smart home technology, and exclusive amenities.', + location: { + address: '432 Park Avenue', + city: 'New York', + state: 'NY', + country: 'USA', + zipCode: '10022', + coordinates: { lat: 40.7614, lng: -73.9776 }, + }, + price: { + total: 5000000, + perToken: 100, + currency: 'USD', + }, + propertyType: 'residential', + blockchain: 'ethereum', + tokenInfo: { + totalSupply: 50000, + available: 25000, + sold: 25000, + contractAddress: '0x1234567890abcdef1234567890abcdef12345678', + tokenSymbol: 'PENT432', + }, + metrics: { + roi: 8.5, + annualReturn: 425000, + transactionVolume: 2500000, + appreciationRate: 5.2, + }, + details: { + bedrooms: 3, + bathrooms: 3, + squareFeet: 3200, + yearBuilt: 2020, + parking: 2, + amenities: ['Gym', 'Pool', 'Concierge', 'Rooftop Terrace'], + }, + images: [ + 'https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?w=800', + 'https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?w=800', + ], + listedDate: '2024-01-15T00:00:00Z', + status: 'active', + featured: true, + verified: true, + }, + { + id: '2', + name: 'Modern Office Complex', + description: 'Class A office building in Silicon Valley tech hub. High-speed internet, modern infrastructure, and sustainable design.', + location: { + address: '1 Market Street', + city: 'San Francisco', + state: 'CA', + country: 'USA', + zipCode: '94105', + coordinates: { lat: 37.7749, lng: -122.4194 }, + }, + price: { + total: 12000000, + perToken: 200, + currency: 'USD', + }, + propertyType: 'commercial', + blockchain: 'polygon', + tokenInfo: { + totalSupply: 60000, + available: 40000, + sold: 20000, + contractAddress: '0xabcdef1234567890abcdef1234567890abcdef12', + tokenSymbol: 'OFFC1M', + }, + metrics: { + roi: 12.3, + annualReturn: 1476000, + transactionVolume: 4000000, + appreciationRate: 7.8, + }, + details: { + squareFeet: 45000, + yearBuilt: 2019, + parking: 100, + amenities: ['Conference Rooms', 'Cafeteria', 'Fitness Center', 'EV Charging'], + }, + images: [ + 'https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=800', + 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=800', + ], + listedDate: '2024-02-01T00:00:00Z', + status: 'active', + featured: true, + verified: true, + }, + { + id: '3', + name: 'Beachfront Villa Resort', + description: 'Exclusive beachfront property in Bali with private beach access. Perfect for vacation rentals and hospitality investment.', + location: { + address: 'Jalan Pantai Seminyak', + city: 'Seminyak', + state: 'Bali', + country: 'Indonesia', + zipCode: '80361', + coordinates: { lat: -8.6905, lng: 115.1683 }, + }, + price: { + total: 2500000, + perToken: 50, + currency: 'USD', + }, + propertyType: 'residential', + blockchain: 'bsc', + tokenInfo: { + totalSupply: 50000, + available: 35000, + sold: 15000, + contractAddress: '0x9876543210fedcba9876543210fedcba98765432', + tokenSymbol: 'VILL-BALI', + }, + metrics: { + roi: 15.7, + annualReturn: 392500, + transactionVolume: 750000, + appreciationRate: 9.3, + }, + details: { + bedrooms: 5, + bathrooms: 4, + squareFeet: 4500, + lotSize: 8000, + yearBuilt: 2021, + parking: 4, + amenities: ['Private Pool', 'Beach Access', 'Garden', 'Ocean View'], + }, + images: [ + 'https://images.unsplash.com/photo-1613490493576-7fde63acd811?w=800', + 'https://images.unsplash.com/photo-1582268611958-ebfd161ef9cf?w=800', + ], + listedDate: '2024-01-20T00:00:00Z', + status: 'active', + verified: true, + }, + { + id: '4', + name: 'Industrial Warehouse Hub', + description: 'Strategic logistics center near major highways. Ideal for e-commerce fulfillment and distribution operations.', + location: { + address: '500 Industrial Parkway', + city: 'Dallas', + state: 'TX', + country: 'USA', + zipCode: '75201', + coordinates: { lat: 32.7767, lng: -96.7970 }, + }, + price: { + total: 8000000, + perToken: 160, + currency: 'USD', + }, + propertyType: 'industrial', + blockchain: 'ethereum', + tokenInfo: { + totalSupply: 50000, + available: 30000, + sold: 20000, + contractAddress: '0x5555666677778888999900001111222233334444', + tokenSymbol: 'WARE-DLS', + }, + metrics: { + roi: 10.5, + annualReturn: 840000, + transactionVolume: 3200000, + appreciationRate: 6.1, + }, + details: { + squareFeet: 85000, + yearBuilt: 2018, + parking: 50, + amenities: ['Loading Docks', 'High Ceilings', 'Climate Control', 'Security System'], + }, + images: [ + 'https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=800', + 'https://images.unsplash.com/photo-1553413077-190dd305871c?w=800', + ], + listedDate: '2024-01-10T00:00:00Z', + status: 'active', + verified: true, + }, + { + id: '5', + name: 'Mixed-Use Development', + description: 'Vibrant mixed-use property combining retail, office, and residential spaces in downtown Seattle.', + location: { + address: '1201 3rd Avenue', + city: 'Seattle', + state: 'WA', + country: 'USA', + zipCode: '98101', + coordinates: { lat: 47.6062, lng: -122.3321 }, + }, + price: { + total: 15000000, + perToken: 250, + currency: 'USD', + }, + propertyType: 'mixed-use', + blockchain: 'polygon', + tokenInfo: { + totalSupply: 60000, + available: 45000, + sold: 15000, + contractAddress: '0xaaaa1111bbbb2222cccc3333dddd4444eeee5555', + tokenSymbol: 'MIX-SEA', + }, + metrics: { + roi: 11.8, + annualReturn: 1770000, + transactionVolume: 3750000, + appreciationRate: 8.2, + }, + details: { + squareFeet: 120000, + yearBuilt: 2022, + parking: 200, + amenities: ['Retail Spaces', 'Office Floors', 'Residential Units', 'Public Plaza'], + }, + images: [ + 'https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800', + 'https://images.unsplash.com/photo-1577495508326-19a1b3cf65b7?w=800', + ], + listedDate: '2024-02-05T00:00:00Z', + status: 'active', + featured: true, + verified: true, + }, + { + id: '6', + name: 'Historic Brownstone', + description: 'Beautifully restored brownstone in Brooklyn with original architectural details and modern updates.', + location: { + address: '234 Prospect Park West', + city: 'Brooklyn', + state: 'NY', + country: 'USA', + zipCode: '11215', + coordinates: { lat: 40.6782, lng: -73.9442 }, + }, + price: { + total: 3200000, + perToken: 80, + currency: 'USD', + }, + propertyType: 'residential', + blockchain: 'ethereum', + tokenInfo: { + totalSupply: 40000, + available: 20000, + sold: 20000, + contractAddress: '0x1111aaaa2222bbbb3333cccc4444dddd5555eeee', + tokenSymbol: 'BRWN-BK', + }, + metrics: { + roi: 7.2, + annualReturn: 230400, + transactionVolume: 1600000, + appreciationRate: 4.5, + }, + details: { + bedrooms: 4, + bathrooms: 3, + squareFeet: 2800, + yearBuilt: 1890, + parking: 1, + amenities: ['Garden', 'Fireplace', 'Original Moldings', 'Updated Kitchen'], + }, + images: [ + 'https://images.unsplash.com/photo-1580587771525-78b9dba3b914?w=800', + 'https://images.unsplash.com/photo-1512917774080-9991f1c4c750?w=800', + ], + listedDate: '2024-01-25T00:00:00Z', + status: 'active', + verified: true, + }, + { + id: '7', + name: 'Tech Campus', + description: 'Modern tech campus in Austin with collaborative workspaces and innovation labs.', + location: { + address: '500 W 2nd Street', + city: 'Austin', + state: 'TX', + country: 'USA', + zipCode: '78701', + coordinates: { lat: 30.2672, lng: -97.7431 }, + }, + price: { + total: 18000000, + perToken: 300, + currency: 'USD', + }, + propertyType: 'commercial', + blockchain: 'polygon', + tokenInfo: { + totalSupply: 60000, + available: 50000, + sold: 10000, + contractAddress: '0x6666777788889999aaaabbbbccccddddeeee0000', + tokenSymbol: 'TECH-ATX', + }, + metrics: { + roi: 13.5, + annualReturn: 2430000, + transactionVolume: 3000000, + appreciationRate: 10.1, + }, + details: { + squareFeet: 95000, + yearBuilt: 2023, + parking: 250, + amenities: ['Innovation Labs', 'Cafeteria', 'Gym', 'Outdoor Spaces'], + }, + images: [ + 'https://images.unsplash.com/photo-1497366811353-6870744d04b2?w=800', + 'https://images.unsplash.com/photo-1497366754035-f200968a6e72?w=800', + ], + listedDate: '2024-02-10T00:00:00Z', + status: 'active', + featured: true, + verified: true, + }, + { + id: '8', + name: 'Mountain Chalet', + description: 'Luxury ski chalet in Aspen with ski-in/ski-out access and breathtaking mountain views.', + location: { + address: '100 Aspen Mountain Road', + city: 'Aspen', + state: 'CO', + country: 'USA', + zipCode: '81611', + coordinates: { lat: 39.1911, lng: -106.8175 }, + }, + price: { + total: 6500000, + perToken: 130, + currency: 'USD', + }, + propertyType: 'residential', + blockchain: 'bsc', + tokenInfo: { + totalSupply: 50000, + available: 38000, + sold: 12000, + contractAddress: '0x7777888899990000aaaa1111bbbb2222cccc3333', + tokenSymbol: 'CHAL-ASP', + }, + metrics: { + roi: 9.8, + annualReturn: 637000, + transactionVolume: 1560000, + appreciationRate: 6.7, + }, + details: { + bedrooms: 6, + bathrooms: 5, + squareFeet: 5500, + yearBuilt: 2020, + parking: 3, + amenities: ['Ski Access', 'Hot Tub', 'Wine Cellar', 'Home Theater'], + }, + images: [ + 'https://images.unsplash.com/photo-1542718610-a1d656d1884c?w=800', + 'https://images.unsplash.com/photo-1518780664697-55e3ad937233?w=800', + ], + listedDate: '2024-01-18T00:00:00Z', + status: 'active', + verified: true, + }, +]; + +// Helper function to get properties by blockchain +export function getPropertiesByBlockchain(blockchain: BlockchainNetwork): Property[] { + return MOCK_PROPERTIES.filter(p => p.blockchain === blockchain); +} + +// Helper function to get featured properties +export function getFeaturedProperties(): Property[] { + return MOCK_PROPERTIES.filter(p => p.featured); +} + +// Helper function to get unique locations +export function getUniqueLocations(): string[] { + const locations = MOCK_PROPERTIES.map(p => `${p.location.city}, ${p.location.state}`); + return [...new Set(locations)].sort(); +} + +// Helper function to get unique cities +export function getUniqueCities(): string[] { + const cities = MOCK_PROPERTIES.map(p => p.location.city); + return [...new Set(cities)].sort(); +} diff --git a/src/lib/propertyService.ts b/src/lib/propertyService.ts new file mode 100644 index 00000000..09ad0eb8 --- /dev/null +++ b/src/lib/propertyService.ts @@ -0,0 +1,277 @@ +import type { + Property, + SearchFilters, + PropertySearchResult, + SortOption, + AutocompleteResult, + SavedSearch, +} from '@/types/property'; +import { MOCK_PROPERTIES, getUniqueLocations } from './mockData'; + +/** + * Property Service + * Handles property search, filtering, and data operations + */ + +class PropertyService { + /** + * Search properties with filters and sorting + */ + async searchProperties( + filters: SearchFilters, + sortBy: SortOption = 'newest', + page: number = 1, + resultsPerPage: number = 12 + ): Promise { + // Simulate API delay + await this.delay(300); + + let results = [...MOCK_PROPERTIES]; + + // Apply filters + results = this.applyFilters(results, filters); + + // Apply sorting + results = this.applySorting(results, sortBy); + + // Calculate pagination + const total = results.length; + const totalPages = Math.ceil(total / resultsPerPage); + const startIndex = (page - 1) * resultsPerPage; + const endIndex = startIndex + resultsPerPage; + const paginatedResults = results.slice(startIndex, endIndex); + + return { + properties: paginatedResults, + total, + page, + totalPages, + }; + } + + /** + * Get a single property by ID + */ + async getPropertyById(id: string): Promise { + await this.delay(200); + return MOCK_PROPERTIES.find(p => p.id === id) || null; + } + + /** + * Get autocomplete suggestions + */ + async getAutocompleteSuggestions(query: string): Promise { + if (!query || query.length < 2) return []; + + await this.delay(150); + + const results: AutocompleteResult[] = []; + const lowerQuery = query.toLowerCase(); + + // Search property names + MOCK_PROPERTIES.forEach(property => { + if (property.name.toLowerCase().includes(lowerQuery)) { + results.push({ + type: 'property', + value: property.name, + label: property.name, + id: property.id, + }); + } + }); + + // Search locations + const locations = getUniqueLocations(); + locations.forEach(location => { + if (location.toLowerCase().includes(lowerQuery)) { + results.push({ + type: 'location', + value: location, + label: location, + }); + } + }); + + return results.slice(0, 8); // Limit to 8 suggestions + } + + /** + * Get saved searches for a user + */ + async getSavedSearches(userId: string): Promise { + await this.delay(200); + + // Get from localStorage + const saved = localStorage.getItem(`propchain-saved-searches-${userId}`); + return saved ? JSON.parse(saved) : []; + } + + /** + * Save a search for a user + */ + async saveSearch( + userId: string, + name: string, + filters: SearchFilters, + sortBy: SortOption + ): Promise { + await this.delay(200); + + const savedSearch: SavedSearch = { + id: this.generateId(), + name, + filters, + sortBy, + createdAt: new Date().toISOString(), + userId, + }; + + const existing = await this.getSavedSearches(userId); + const updated = [...existing, savedSearch]; + localStorage.setItem(`propchain-saved-searches-${userId}`, JSON.stringify(updated)); + + return savedSearch; + } + + /** + * Delete a saved search + */ + async deleteSavedSearch(userId: string, searchId: string): Promise { + await this.delay(200); + + const existing = await this.getSavedSearches(userId); + const updated = existing.filter(s => s.id !== searchId); + localStorage.setItem(`propchain-saved-searches-${userId}`, JSON.stringify(updated)); + } + + /** + * Apply filters to properties + */ + private applyFilters(properties: Property[], filters: SearchFilters): Property[] { + return properties.filter(property => { + // Query filter (search in name, description, location) + if (filters.query) { + const query = filters.query.toLowerCase(); + const searchableText = ` + ${property.name} + ${property.description} + ${property.location.city} + ${property.location.state} + ${property.location.address} + `.toLowerCase(); + + if (!searchableText.includes(query)) return false; + } + + // Price range filter + if (property.price.total < filters.priceRange[0] || + property.price.total > filters.priceRange[1]) { + return false; + } + + // Property type filter + if (filters.propertyTypes.length > 0 && + !filters.propertyTypes.includes(property.propertyType)) { + return false; + } + + // Blockchain filter + if (filters.blockchains.length > 0 && + !filters.blockchains.includes(property.blockchain)) { + return false; + } + + // ROI filter + if (property.metrics.roi < filters.roiMin || + property.metrics.roi > filters.roiMax) { + return false; + } + + // Location filter + if (filters.location) { + const locationQuery = filters.location.toLowerCase(); + const propertyLocation = `${property.location.city}, ${property.location.state}`.toLowerCase(); + if (!propertyLocation.includes(locationQuery)) return false; + } + + // Bedrooms filter + if (filters.bedrooms.length > 0 && property.details.bedrooms) { + if (!filters.bedrooms.includes(property.details.bedrooms)) return false; + } + + // Bathrooms filter + if (filters.bathrooms.length > 0 && property.details.bathrooms) { + if (!filters.bathrooms.includes(property.details.bathrooms)) return false; + } + + // Square feet filter + if (property.details.squareFeet < filters.squareFeetRange[0] || + property.details.squareFeet > filters.squareFeetRange[1]) { + return false; + } + + // Status filter + if (filters.status.length > 0 && !filters.status.includes(property.status)) { + return false; + } + + return true; + }); + } + + /** + * Apply sorting to properties + */ + private applySorting(properties: Property[], sortBy: SortOption): Property[] { + const sorted = [...properties]; + + switch (sortBy) { + case 'price-asc': + return sorted.sort((a, b) => a.price.total - b.price.total); + + case 'price-desc': + return sorted.sort((a, b) => b.price.total - a.price.total); + + case 'roi-desc': + return sorted.sort((a, b) => b.metrics.roi - a.metrics.roi); + + case 'roi-asc': + return sorted.sort((a, b) => a.metrics.roi - b.metrics.roi); + + case 'newest': + return sorted.sort((a, b) => + new Date(b.listedDate).getTime() - new Date(a.listedDate).getTime() + ); + + case 'oldest': + return sorted.sort((a, b) => + new Date(a.listedDate).getTime() - new Date(b.listedDate).getTime() + ); + + case 'volume-desc': + return sorted.sort((a, b) => + b.metrics.transactionVolume - a.metrics.transactionVolume + ); + + default: + return sorted; + } + } + + /** + * Simulate API delay + */ + private delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + /** + * Generate unique ID + */ + private generateId(): string { + return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + } +} + +// Export singleton instance +export const propertyService = new PropertyService(); diff --git a/src/store/savedSearchStore.ts b/src/store/savedSearchStore.ts new file mode 100644 index 00000000..33643c50 --- /dev/null +++ b/src/store/savedSearchStore.ts @@ -0,0 +1,70 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; +import type { SavedSearch } from '@/types/property'; +import { propertyService } from '@/lib/propertyService'; + +/** + * Saved Searches Store + * Manages user's saved search queries + */ + +interface SavedSearchState { + searches: SavedSearch[]; + isLoading: boolean; + error: string | null; + + // Actions + loadSearches: (userId: string) => Promise; + addSearch: (search: SavedSearch) => void; + removeSearch: (searchId: string, userId: string) => Promise; + clearSearches: () => void; +} + +export const useSavedSearchStore = create()( + persist( + (set, get) => ({ + searches: [], + isLoading: false, + error: null, + + loadSearches: async (userId: string) => { + set({ isLoading: true, error: null }); + try { + const searches = await propertyService.getSavedSearches(userId); + set({ searches, isLoading: false }); + } catch (error: any) { + set({ error: error.message, isLoading: false }); + } + }, + + addSearch: (search: SavedSearch) => { + set((state) => ({ + searches: [...state.searches, search], + })); + }, + + removeSearch: async (searchId: string, userId: string) => { + set({ isLoading: true, error: null }); + try { + await propertyService.deleteSavedSearch(userId, searchId); + set((state) => ({ + searches: state.searches.filter(s => s.id !== searchId), + isLoading: false, + })); + } catch (error: any) { + set({ error: error.message, isLoading: false }); + } + }, + + clearSearches: () => { + set({ searches: [] }); + }, + }), + { + name: 'propchain-saved-searches', + partialize: (state) => ({ + searches: state.searches, + }), + } + ) +); diff --git a/src/store/searchStore.ts b/src/store/searchStore.ts new file mode 100644 index 00000000..aa5b966b --- /dev/null +++ b/src/store/searchStore.ts @@ -0,0 +1,145 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; +import type { + SearchFilters, + SortOption, + ViewMode, + Property, + DEFAULT_FILTERS, +} from '@/types/property'; + +/** + * Search Store + * Global state management for property search and filtering + */ + +interface SearchState { + // Filters + filters: SearchFilters; + sortBy: SortOption; + viewMode: ViewMode; + + // Pagination + page: number; + resultsPerPage: number; + totalResults: number; + + // Loading states + isLoading: boolean; + error: string | null; + + // Results + properties: Property[]; + + // Actions + setFilters: (filters: Partial) => void; + setFilter: (key: K, value: SearchFilters[K]) => void; + clearFilters: () => void; + setSortBy: (sortBy: SortOption) => void; + setViewMode: (viewMode: ViewMode) => void; + setPage: (page: number) => void; + setResultsPerPage: (count: number) => void; + setProperties: (properties: Property[], total: number) => void; + setLoading: (isLoading: boolean) => void; + setError: (error: string | null) => void; + reset: () => void; +} + +const DEFAULT_STATE = { + filters: { + query: '', + priceRange: [0, 10000000] as [number, number], + propertyTypes: [], + blockchains: [], + roiMin: 0, + roiMax: 100, + location: '', + bedrooms: [], + bathrooms: [], + squareFeetRange: [0, 50000] as [number, number], + status: ['active'] as any[], + }, + sortBy: 'newest' as SortOption, + viewMode: 'grid' as ViewMode, + page: 1, + resultsPerPage: 12, + totalResults: 0, + isLoading: false, + error: null, + properties: [], +}; + +export const useSearchStore = create()( + persist( + (set, get) => ({ + ...DEFAULT_STATE, + + setFilters: (newFilters) => { + set((state) => ({ + filters: { ...state.filters, ...newFilters }, + page: 1, // Reset to first page when filters change + })); + }, + + setFilter: (key, value) => { + set((state) => ({ + filters: { ...state.filters, [key]: value }, + page: 1, + })); + }, + + clearFilters: () => { + set({ + filters: DEFAULT_STATE.filters, + page: 1, + }); + }, + + setSortBy: (sortBy) => { + set({ sortBy, page: 1 }); + }, + + setViewMode: (viewMode) => { + set({ viewMode }); + }, + + setPage: (page) => { + set({ page }); + }, + + setResultsPerPage: (resultsPerPage) => { + set({ resultsPerPage, page: 1 }); + }, + + setProperties: (properties, total) => { + set({ + properties, + totalResults: total, + isLoading: false, + error: null, + }); + }, + + setLoading: (isLoading) => { + set({ isLoading }); + }, + + setError: (error) => { + set({ error, isLoading: false }); + }, + + reset: () => { + set(DEFAULT_STATE); + }, + }), + { + name: 'propchain-search', + partialize: (state) => ({ + filters: state.filters, + sortBy: state.sortBy, + viewMode: state.viewMode, + resultsPerPage: state.resultsPerPage, + }), + } + ) +); diff --git a/src/store/walletStore.ts b/src/store/walletStore.ts index 1f0a30d8..f07347dd 100644 --- a/src/store/walletStore.ts +++ b/src/store/walletStore.ts @@ -72,7 +72,7 @@ export const useWalletStore = create()( set({ isConnecting }); }, - setSwitchingNetwork: (isSwitching: boolean) => { + setSwitchingNetwork: (isSwitchingNetwork: boolean) => { set({ isSwitchingNetwork }); }, diff --git a/src/types/property.ts b/src/types/property.ts new file mode 100644 index 00000000..2fd3528c --- /dev/null +++ b/src/types/property.ts @@ -0,0 +1,169 @@ +/** + * Property Types and Interfaces + * Core data structures for the property search and filtering system + */ + +export type PropertyType = 'residential' | 'commercial' | 'industrial' | 'mixed-use'; +export type PropertyStatus = 'active' | 'sold' | 'pending'; +export type BlockchainNetwork = 'ethereum' | 'polygon' | 'bsc'; + +export interface PropertyLocation { + address: string; + city: string; + state: string; + country: string; + zipCode: string; + coordinates: { + lat: number; + lng: number; + }; +} + +export interface PropertyPrice { + total: number; + perToken: number; + currency: string; +} + +export interface TokenInfo { + totalSupply: number; + available: number; + sold: number; + contractAddress: string; + tokenSymbol: string; +} + +export interface PropertyMetrics { + roi: number; // Annual ROI percentage + annualReturn: number; // Expected annual return in currency + transactionVolume: number; // Total transaction volume + appreciationRate: number; // Historical appreciation rate +} + +export interface PropertyDetails { + bedrooms?: number; + bathrooms?: number; + squareFeet: number; + lotSize?: number; + yearBuilt: number; + parking?: number; + amenities: string[]; +} + +export interface Property { + id: string; + name: string; + description: string; + location: PropertyLocation; + price: PropertyPrice; + propertyType: PropertyType; + blockchain: BlockchainNetwork; + tokenInfo: TokenInfo; + metrics: PropertyMetrics; + details: PropertyDetails; + images: string[]; + listedDate: string; + status: PropertyStatus; + featured?: boolean; + verified?: boolean; +} + +export interface SearchFilters { + query: string; + priceRange: [number, number]; + propertyTypes: PropertyType[]; + blockchains: BlockchainNetwork[]; + roiMin: number; + roiMax: number; + location: string; + bedrooms: number[]; + bathrooms: number[]; + squareFeetRange: [number, number]; + status: PropertyStatus[]; +} + +export type SortOption = + | 'price-asc' + | 'price-desc' + | 'roi-desc' + | 'roi-asc' + | 'newest' + | 'oldest' + | 'volume-desc'; + +export type ViewMode = 'grid' | 'list' | 'map'; + +export interface SearchState { + filters: SearchFilters; + sortBy: SortOption; + viewMode: ViewMode; + page: number; + resultsPerPage: number; + totalResults: number; + isLoading: boolean; + error: string | null; +} + +export interface SavedSearch { + id: string; + name: string; + filters: SearchFilters; + sortBy: SortOption; + createdAt: string; + userId: string; // Wallet address +} + +export interface PropertySearchResult { + properties: Property[]; + total: number; + page: number; + totalPages: number; +} + +export interface AutocompleteResult { + type: 'property' | 'location'; + value: string; + label: string; + id?: string; +} + +// Default filter values +export const DEFAULT_FILTERS: SearchFilters = { + query: '', + priceRange: [0, 10000000], + propertyTypes: [], + blockchains: [], + roiMin: 0, + roiMax: 100, + location: '', + bedrooms: [], + bathrooms: [], + squareFeetRange: [0, 50000], + status: ['active'], +}; + +// Property type labels +export const PROPERTY_TYPE_LABELS: Record = { + residential: 'Residential', + commercial: 'Commercial', + industrial: 'Industrial', + 'mixed-use': 'Mixed Use', +}; + +// Blockchain labels +export const BLOCKCHAIN_LABELS: Record = { + ethereum: 'Ethereum', + polygon: 'Polygon', + bsc: 'Binance Smart Chain', +}; + +// Sort option labels +export const SORT_LABELS: Record = { + 'price-asc': 'Price: Low to High', + 'price-desc': 'Price: High to Low', + 'roi-desc': 'ROI: High to Low', + 'roi-asc': 'ROI: Low to High', + 'newest': 'Newest First', + 'oldest': 'Oldest First', + 'volume-desc': 'Transaction Volume', +}; diff --git a/src/utils/searchUtils.ts b/src/utils/searchUtils.ts new file mode 100644 index 00000000..328631f9 --- /dev/null +++ b/src/utils/searchUtils.ts @@ -0,0 +1,211 @@ +import type { SearchFilters, SortOption } from '@/types/property'; + +/** + * Search Utility Functions + * Helper functions for search and filter operations + */ + +/** + * Convert search filters to URL parameters + */ +export function filtersToUrlParams(filters: SearchFilters, sortBy: SortOption): string { + const params = new URLSearchParams(); + + if (filters.query) params.set('q', filters.query); + if (filters.priceRange[0] > 0) params.set('minPrice', filters.priceRange[0].toString()); + if (filters.priceRange[1] < 10000000) params.set('maxPrice', filters.priceRange[1].toString()); + if (filters.propertyTypes.length > 0) params.set('types', filters.propertyTypes.join(',')); + if (filters.blockchains.length > 0) params.set('chains', filters.blockchains.join(',')); + if (filters.roiMin > 0) params.set('minRoi', filters.roiMin.toString()); + if (filters.roiMax < 100) params.set('maxRoi', filters.roiMax.toString()); + if (filters.location) params.set('location', filters.location); + if (filters.bedrooms.length > 0) params.set('bedrooms', filters.bedrooms.join(',')); + if (filters.bathrooms.length > 0) params.set('bathrooms', filters.bathrooms.join(',')); + if (filters.squareFeetRange[0] > 0) params.set('minSqft', filters.squareFeetRange[0].toString()); + if (filters.squareFeetRange[1] < 50000) params.set('maxSqft', filters.squareFeetRange[1].toString()); + if (sortBy !== 'newest') params.set('sort', sortBy); + + return params.toString(); +} + +/** + * Parse URL parameters to search filters + */ +export function urlParamsToFilters(searchParams: URLSearchParams): { + filters: Partial; + sortBy: SortOption; +} { + const filters: Partial = {}; + let sortBy: SortOption = 'newest'; + + const query = searchParams.get('q'); + if (query) filters.query = query; + + const minPrice = searchParams.get('minPrice'); + const maxPrice = searchParams.get('maxPrice'); + if (minPrice || maxPrice) { + filters.priceRange = [ + minPrice ? parseInt(minPrice) : 0, + maxPrice ? parseInt(maxPrice) : 10000000, + ]; + } + + const types = searchParams.get('types'); + if (types) filters.propertyTypes = types.split(',') as any[]; + + const chains = searchParams.get('chains'); + if (chains) filters.blockchains = chains.split(',') as any[]; + + const minRoi = searchParams.get('minRoi'); + const maxRoi = searchParams.get('maxRoi'); + if (minRoi) filters.roiMin = parseFloat(minRoi); + if (maxRoi) filters.roiMax = parseFloat(maxRoi); + + const location = searchParams.get('location'); + if (location) filters.location = location; + + const bedrooms = searchParams.get('bedrooms'); + if (bedrooms) filters.bedrooms = bedrooms.split(',').map(Number); + + const bathrooms = searchParams.get('bathrooms'); + if (bathrooms) filters.bathrooms = bathrooms.split(',').map(Number); + + const minSqft = searchParams.get('minSqft'); + const maxSqft = searchParams.get('maxSqft'); + if (minSqft || maxSqft) { + filters.squareFeetRange = [ + minSqft ? parseInt(minSqft) : 0, + maxSqft ? parseInt(maxSqft) : 50000, + ]; + } + + const sort = searchParams.get('sort'); + if (sort) sortBy = sort as SortOption; + + return { filters, sortBy }; +} + +/** + * Format price for display + */ +export function formatPrice(price: number, currency: string = 'USD'): string { + return new Intl.NumberFormat('en-US', { + style: 'currency', + currency, + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }).format(price); +} + +/** + * Format number with commas + */ +export function formatNumber(num: number): string { + return new Intl.NumberFormat('en-US').format(num); +} + +/** + * Format ROI percentage + */ +export function formatROI(roi: number): string { + return `${roi.toFixed(1)}%`; +} + +/** + * Format date for display + */ +export function formatDate(dateString: string): string { + const date = new Date(dateString); + return new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + }).format(date); +} + +/** + * Calculate time ago from date + */ +export function timeAgo(dateString: string): string { + const date = new Date(dateString); + const now = new Date(); + const seconds = Math.floor((now.getTime() - date.getTime()) / 1000); + + const intervals = { + year: 31536000, + month: 2592000, + week: 604800, + day: 86400, + hour: 3600, + minute: 60, + }; + + for (const [unit, secondsInUnit] of Object.entries(intervals)) { + const interval = Math.floor(seconds / secondsInUnit); + if (interval >= 1) { + return `${interval} ${unit}${interval > 1 ? 's' : ''} ago`; + } + } + + return 'Just now'; +} + +/** + * Truncate text with ellipsis + */ +export function truncateText(text: string, maxLength: number): string { + if (text.length <= maxLength) return text; + return text.substring(0, maxLength).trim() + '...'; +} + +/** + * Get blockchain color + */ +export function getBlockchainColor(blockchain: string): string { + const colors: Record = { + ethereum: '#627EEA', + polygon: '#8247E5', + bsc: '#F3BA2F', + }; + return colors[blockchain] || '#666666'; +} + +/** + * Get property type icon + */ +export function getPropertyTypeIcon(type: string): string { + const icons: Record = { + residential: '🏠', + commercial: '🏢', + industrial: '🏭', + 'mixed-use': '🏗️', + }; + return icons[type] || '🏘️'; +} + +/** + * Validate search query + */ +export function isValidSearchQuery(query: string): boolean { + return query.trim().length >= 2; +} + +/** + * Debounce function + */ +export function debounce any>( + func: T, + wait: number +): (...args: Parameters) => void { + let timeout: NodeJS.Timeout | null = null; + + return function executedFunction(...args: Parameters) { + const later = () => { + timeout = null; + func(...args); + }; + + if (timeout) clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} From ba15792a892c97ee84a09a0c8c6d31bb87a93cd4 Mon Sep 17 00:00:00 2001 From: Alex PC Date: Mon, 26 Jan 2026 15:47:02 +0100 Subject: [PATCH 2/3] fixed conflict --- MOBILE_FEATURES.md | 238 + components.json | 22 + next-env.d.ts | 1 + package-lock.json | 4535 +++++++++++++++-- package.json | 55 +- src/app/dashboard/page.tsx | 123 + src/app/globals.css | 154 + src/app/layout.tsx | 6 +- src/app/mobile-properties/page.tsx | 448 ++ src/app/page.tsx | 81 +- src/components/ClientProviders.tsx | 25 + src/components/GasEstimator.tsx | 83 + src/components/NotificationSystem.tsx | 93 + src/components/TransactionCard.tsx | 184 + src/components/TransactionHistory.tsx | 145 + src/components/TransactionMonitor.tsx | 39 + src/components/TransactionQueue.tsx | 116 + src/components/WalletConnector.tsx | 2 +- .../dashboard/DataRefreshWrapper.tsx | 196 + .../dashboard/DiversificationChart.tsx | 98 + src/components/dashboard/Header.tsx | 76 + src/components/dashboard/IncomeTracker.tsx | 158 + src/components/dashboard/PerformanceChart.tsx | 176 + .../dashboard/PortfolioOverview.tsx | 93 + src/components/dashboard/PortfolioReport.tsx | 255 + src/components/dashboard/PropertiesList.tsx | 99 + src/components/dashboard/PropertyCard.tsx | 139 + .../dashboard/RecentTransactions.tsx | 180 + src/components/dashboard/RiskAnalysis.tsx | 193 + src/components/dashboard/Sidebar.tsx | 140 + src/components/mobile/ARPropertyPreview.tsx | 469 ++ .../mobile/LocationBasedDiscovery.tsx | 408 ++ src/components/mobile/MobilePropertyCard.tsx | 271 + .../mobile/MobilePropertyViewer.tsx | 375 ++ .../mobile/OfflinePropertyCache.tsx | 438 ++ src/components/ui/accordion.tsx | 66 + src/components/ui/alert-dialog.tsx | 157 + src/components/ui/alert.tsx | 66 + src/components/ui/aspect-ratio.tsx | 11 + src/components/ui/avatar.tsx | 53 + src/components/ui/badge.tsx | 46 + src/components/ui/breadcrumb.tsx | 109 + src/components/ui/button.tsx | 62 + src/components/ui/calendar.tsx | 220 + src/components/ui/card.tsx | 92 + src/components/ui/carousel.tsx | 241 + src/components/ui/chart.tsx | 357 ++ src/components/ui/checkbox.tsx | 32 + src/components/ui/collapsible.tsx | 33 + src/components/ui/command.tsx | 184 + src/components/ui/context-menu.tsx | 252 + src/components/ui/dialog.tsx | 143 + src/components/ui/drawer.tsx | 135 + src/components/ui/dropdown-menu.tsx | 257 + src/components/ui/form.tsx | 167 + src/components/ui/hover-card.tsx | 44 + src/components/ui/input-otp.tsx | 77 + src/components/ui/input.tsx | 21 + src/components/ui/label.tsx | 24 + src/components/ui/menubar.tsx | 276 + src/components/ui/navigation-menu.tsx | 168 + src/components/ui/pagination.tsx | 127 + src/components/ui/popover.tsx | 48 + src/components/ui/progress.tsx | 31 + src/components/ui/radio-group.tsx | 45 + src/components/ui/resizable.tsx | 54 + src/components/ui/scroll-area.tsx | 58 + src/components/ui/select.tsx | 190 + src/components/ui/separator.tsx | 28 + src/components/ui/sheet.tsx | 139 + src/components/ui/sidebar.tsx | 726 +++ src/components/ui/skeleton.tsx | 13 + src/components/ui/slider.tsx | 63 + src/components/ui/sonner.tsx | 40 + src/components/ui/switch.tsx | 31 + src/components/ui/table.tsx | 116 + src/components/ui/tabs.tsx | 66 + src/components/ui/textarea.tsx | 18 + src/components/ui/toggle-group.tsx | 83 + src/components/ui/toggle.tsx | 47 + src/components/ui/tooltip.tsx | 61 + src/config/chains.ts | 3 + src/config/wagmi.ts | 20 + src/globals.d.ts | 5 + src/hooks/use-mobile.ts | 19 + src/hooks/useDeviceOrientation.ts | 124 + src/hooks/useGestures.ts | 162 + src/hooks/useTransaction.ts | 66 + src/lib/utils.ts | 6 + src/store/transactionStore.ts | 126 + src/store/walletStore.ts | 6 +- src/styles/mobile.css | 344 ++ src/utils/mobileDetection.ts | 178 + tsconfig.json | 24 +- 94 files changed, 16086 insertions(+), 388 deletions(-) create mode 100644 MOBILE_FEATURES.md create mode 100644 components.json create mode 100644 src/app/dashboard/page.tsx create mode 100644 src/app/mobile-properties/page.tsx create mode 100644 src/components/ClientProviders.tsx create mode 100644 src/components/GasEstimator.tsx create mode 100644 src/components/NotificationSystem.tsx create mode 100644 src/components/TransactionCard.tsx create mode 100644 src/components/TransactionHistory.tsx create mode 100644 src/components/TransactionMonitor.tsx create mode 100644 src/components/TransactionQueue.tsx create mode 100644 src/components/dashboard/DataRefreshWrapper.tsx create mode 100644 src/components/dashboard/DiversificationChart.tsx create mode 100644 src/components/dashboard/Header.tsx create mode 100644 src/components/dashboard/IncomeTracker.tsx create mode 100644 src/components/dashboard/PerformanceChart.tsx create mode 100644 src/components/dashboard/PortfolioOverview.tsx create mode 100644 src/components/dashboard/PortfolioReport.tsx create mode 100644 src/components/dashboard/PropertiesList.tsx create mode 100644 src/components/dashboard/PropertyCard.tsx create mode 100644 src/components/dashboard/RecentTransactions.tsx create mode 100644 src/components/dashboard/RiskAnalysis.tsx create mode 100644 src/components/dashboard/Sidebar.tsx create mode 100644 src/components/mobile/ARPropertyPreview.tsx create mode 100644 src/components/mobile/LocationBasedDiscovery.tsx create mode 100644 src/components/mobile/MobilePropertyCard.tsx create mode 100644 src/components/mobile/MobilePropertyViewer.tsx create mode 100644 src/components/mobile/OfflinePropertyCache.tsx create mode 100644 src/components/ui/accordion.tsx create mode 100644 src/components/ui/alert-dialog.tsx create mode 100644 src/components/ui/alert.tsx create mode 100644 src/components/ui/aspect-ratio.tsx create mode 100644 src/components/ui/avatar.tsx create mode 100644 src/components/ui/badge.tsx create mode 100644 src/components/ui/breadcrumb.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/calendar.tsx create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/carousel.tsx create mode 100644 src/components/ui/chart.tsx create mode 100644 src/components/ui/checkbox.tsx create mode 100644 src/components/ui/collapsible.tsx create mode 100644 src/components/ui/command.tsx create mode 100644 src/components/ui/context-menu.tsx create mode 100644 src/components/ui/dialog.tsx create mode 100644 src/components/ui/drawer.tsx create mode 100644 src/components/ui/dropdown-menu.tsx create mode 100644 src/components/ui/form.tsx create mode 100644 src/components/ui/hover-card.tsx create mode 100644 src/components/ui/input-otp.tsx create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/label.tsx create mode 100644 src/components/ui/menubar.tsx create mode 100644 src/components/ui/navigation-menu.tsx create mode 100644 src/components/ui/pagination.tsx create mode 100644 src/components/ui/popover.tsx create mode 100644 src/components/ui/progress.tsx create mode 100644 src/components/ui/radio-group.tsx create mode 100644 src/components/ui/resizable.tsx create mode 100644 src/components/ui/scroll-area.tsx create mode 100644 src/components/ui/select.tsx create mode 100644 src/components/ui/separator.tsx create mode 100644 src/components/ui/sheet.tsx create mode 100644 src/components/ui/sidebar.tsx create mode 100644 src/components/ui/skeleton.tsx create mode 100644 src/components/ui/slider.tsx create mode 100644 src/components/ui/sonner.tsx create mode 100644 src/components/ui/switch.tsx create mode 100644 src/components/ui/table.tsx create mode 100644 src/components/ui/tabs.tsx create mode 100644 src/components/ui/textarea.tsx create mode 100644 src/components/ui/toggle-group.tsx create mode 100644 src/components/ui/toggle.tsx create mode 100644 src/components/ui/tooltip.tsx create mode 100644 src/config/wagmi.ts create mode 100644 src/globals.d.ts create mode 100644 src/hooks/use-mobile.ts create mode 100644 src/hooks/useDeviceOrientation.ts create mode 100644 src/hooks/useGestures.ts create mode 100644 src/hooks/useTransaction.ts create mode 100644 src/lib/utils.ts create mode 100644 src/store/transactionStore.ts create mode 100644 src/styles/mobile.css create mode 100644 src/utils/mobileDetection.ts diff --git a/MOBILE_FEATURES.md b/MOBILE_FEATURES.md new file mode 100644 index 00000000..2d999540 --- /dev/null +++ b/MOBILE_FEATURES.md @@ -0,0 +1,238 @@ +# Mobile-First Property Viewing Experience + +This document outlines the comprehensive mobile-first property viewing experience implemented for PropChain, featuring touch-optimized interfaces, gesture-based navigation, and mobile-specific features. + +## 🚀 Features Implemented + +### 1. Touch-Optimized Interface + +- **Swipe Gestures**: Navigate through image galleries and property cards with natural swipe motions +- **Pinch-to-Zoom**: Zoom in/out on property images with pinch gestures +- **Double-tap to Zoom**: Quick zoom functionality for detailed image viewing +- **Long Press Actions**: Context menus and additionts meet 44px minimum touch target size + +### 2. Immersive Media Gallery + +- **Full-screen Image Viewing**: Immersive property image experience +- **Gesture Navigation**: Swipe between images, pinch to zoom, double-tap to fit +- **Image Counter**: Visual indicator of current image position +- **Thumbnail Strip**: Quick navigation between property images +- **Video Support**: Ready for property video integration +- **Smooth Transitions**: Fluid animations between gallery states + +### 3. Mobile Property Cards + +- **Compact Design**: Information-rich cards optimized for small screens +- **Quick Actions**: One-tap save, share, and contact functionality +- **Visual Hierarchy**: Clear information layout with proper typography scaling +- **Performance Indicators**: ROI badges and financial metrics prominently displayed +- **Property Details**: Bedrooms, bathrooms, square footage, and amenities +- **Touch Feedback**: Visual and haptic feedback for interactions + +### 4. Location-Based Discovery + +- **GPS Integration**: Automatic location detection for nearby properties +- **Distance Calculation**: Real-time distance calculation to properties +- **Location Permissions**: Proper handling of location permission requests +- **Offline Fallback**: Graceful degradation when location is unavailable +- **Search & Filter**: Location-based search with property type filters +- **Sort Options**: Sort by distance, price, or ROI + +### 5. AR Property Preview + +- **WebXR Integration**: Augmented reality property visualization +- **Camera Access**: Real-time camera feed for AR overlay +- **3D Model Support**: Ready for 3D property model integration +- **AR Controls**: Zoom, rotate, and placement controls +- **Property Information Overlay**: Contextual property details in AR view +- **Capture & Share**: Screenshot and share AR previews +- **Device Compatibility**: Proper fallbacks for non-AR devices + +### 6. Offline Mode + +- **Property Caching**: Download properties for offline viewing +- **Image Storage**: Cache property images locally using IndexedDB +- **Storage Management**: Monitor and manage local storage usage +- **Sync Status**: Clear online/offline status indicators +- **Background Sync**: Automatic sync when connection is restored +- **Storage Quota**: Respect device storage limitations + +### 7. Mobile-Specific Actions + +- **One-tap Contact**: Direct phone dialer integration +- **Native Sharing**: Web Share API for native sharing experience +- **Save to Favorites**: Local storage of favorite properties +- **Schedule Tours**: Quick tour scheduling functionality +- **Push Notifications**: Ready for property update notifications + +## 📱 Technical Implementation + +### Components Structure + +``` +src/components/mobile/ +├── MobilePropertyViewer.tsx # Full-screen property viewer +├── MobilePropertyCard.tsx # Compact property cards +├── LocationBasedDiscovery.tsx # GPS-based property discovery +├── ARPropertyPreview.tsx # Augmented reality preview +└── OfflinePropertyCache.tsx # Offline storage management +``` + +### Custom Hooks + +``` +src/hooks/ +├── useGestures.ts # Touch gesture handling +├── useDeviceOrientation.ts # Device orientation detection +└── use-mobile.ts # Mobile device detection +``` + +### Utilities + +``` +src/utils/ +├── mobileDetection.ts # Device capability detection +└── src/styles/mobile.css # Mobile-specific styles +``` + +### Key Technologies Used + +- **Framer Motion**: Smooth animations and gesture handling +- **Web APIs**: Geolocation, Device Orientation, Web Share, Camera +- **IndexedDB**: Local storage for offline functionality +- **WebXR**: Augmented reality capabilities +- **Service Workers**: Background sync and caching (ready for implementation) + +## 🎯 User Experience Features + +### Gesture Support + +- **Swipe Navigation**: Left/right swipes for image galleries +- **Pinch Zoom**: Multi-touch zoom with momentum +- **Double Tap**: Quick zoom toggle +- **Long Press**: Context menus and additional options +- **Pull to Refresh**: Refresh property listings + +### Visual Feedback + +- **Touch Ripples**: Visual feedback for touch interactions +- **Loading States**: Skeleton screens and progress indicators +- **Haptic Feedback**: Vibration feedback for actions (where supported) +- **Smooth Transitions**: 60fps animations and transitions + +### Accessibility + +- **Screen Reader Support**: Proper ARIA labels and semantic HTML +- **High Contrast**: Support for high contrast mode +- **Reduced Motion**: Respect for reduced motion preferences +- **Keyboard Navigation**: Full keyboard accessibility +- **Focus Management**: Proper focus handling for modal dialogs + +## 📊 Performance Optimizations + +### Image Handling + +- **Lazy Loading**: Images load as needed +- **Responsive Images**: Multiple image sizes for different screen densities +- **WebP Support**: Modern image formats with fallbacks +- **Image Compression**: Optimized image sizes for mobile + +### Network Optimization + +- **Progressive Loading**: Content loads progressively +- **Offline First**: Cached content loads instantly +- **Background Sync**: Updates sync in background +- **Compression**: Gzip/Brotli compression for all assets + +### Memory Management + +- **Component Cleanup**: Proper cleanup of event listeners and timers +- **Image Recycling**: Efficient image memory management +- **State Management**: Optimized state updates and re-renders + +## 🔧 Configuration + +### Environment Variables + +```env +NEXT_PUBLIC_ENABLE_AR=true +NEXT_PUBLIC_ENABLE_GEOLOCATION=true +NEXT_PUBLIC_ENABLE_OFFLINE=true +``` + +### Feature Flags + +The mobile experience includes feature flags for: + +- AR functionality +- Location services +- Offline caching +- Push notifications + +## 🚀 Getting Started + +1. **Navigate to Mobile Experience**: + + ``` + /mobile-properties + ``` + +2. **Enable Location Services** (optional): + - Allow location access for nearby property discovery + - Location is used only for distance calculations + +3. **Try AR Preview** (on supported devices): + - Tap the AR button on any property card + - Allow camera access for AR functionality + +4. **Download for Offline**: + - Go to the "Offline" tab + - Download properties for offline viewing + +## 🔮 Future Enhancements + +### Planned Features + +- **3D Property Tours**: Virtual reality property walkthroughs +- **AI Property Recommendations**: Machine learning-based suggestions +- **Social Features**: Share and discuss properties with others +- **Advanced Filters**: More sophisticated property filtering +- **Property Comparison**: Side-by-side property comparisons +- **Mortgage Calculator**: Integrated financing calculations + +### Technical Improvements + +- **Service Worker**: Full offline functionality with background sync +- **Push Notifications**: Real-time property updates +- **WebRTC**: Video calls with property agents +- **Machine Learning**: On-device property analysis +- **Progressive Web App**: Full PWA capabilities + +## 📱 Device Support + +### Minimum Requirements + +- **iOS**: Safari 14+ on iOS 14+ +- **Android**: Chrome 88+ on Android 8+ +- **Screen Size**: 320px minimum width +- **Touch**: Touch-enabled device + +### Optimal Experience + +- **iOS**: Safari 15+ on iOS 15+ +- **Android**: Chrome 100+ on Android 10+ +- **Screen Size**: 375px+ width +- **Features**: Camera, GPS, Gyroscope for full AR experience + +## 🐛 Known Limitations + +1. **AR Support**: Limited to modern devices with WebXR support +2. **iOS Permissions**: iOS requires user gesture for camera/location access +3. **Storage Limits**: Offline storage limited by device capabilities +4. **Network Dependency**: Some features require internet connection + +## 📞 Support + +For technical issues or feature requests related to the mobile experience, please refer to the main project documentation or create an issue in the project repository.al options via long press + +- **Touch-friendly Targets**: All interactive elemen diff --git a/components.json b/components.json new file mode 100644 index 00000000..edcaef26 --- /dev/null +++ b/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/next-env.d.ts b/next-env.d.ts index 1b3be084..9edff1c7 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/package-lock.json b/package-lock.json index 33f20485..8f34a11b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,26 +9,75 @@ "version": "0.1.0", "dependencies": { "@coinbase/wallet-sdk": "^4.3.7", + "@hookform/resolvers": "^5.2.2", + "@metamask/sdk": "^0.33.1", + "@radix-ui/react-accordion": "^1.2.12", + "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-aspect-ratio": "^1.1.8", + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-context-menu": "^2.2.16", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-hover-card": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-menubar": "^1.1.16", + "@radix-ui/react-navigation-menu": "^1.2.14", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-progress": "^1.1.8", + "@radix-ui/react-radio-group": "^1.3.8", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slider": "^1.3.6", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-toggle": "^1.1.10", + "@radix-ui/react-toggle-group": "^1.1.11", + "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-query": "^5.90.19", "@wagmi/connectors": "^7.1.2", "@wagmi/core": "^3.2.2", "@walletconnect/web3-provider": "^1.8.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", + "embla-carousel-react": "^8.6.0", "ethers": "^6.16.0", - "next": "15.3.1", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "framer-motion": "^12.29.0", + "input-otp": "^1.4.2", + "jspdf": "^4.0.0", + "jspdf-autotable": "^5.0.7", + "lucide-react": "^0.562.0", + "next": "^16.1.4", + "next-themes": "^0.4.6", + "react": "^19.2.3", + "react-day-picker": "^9.13.0", + "react-dom": "^19.2.3", + "react-hook-form": "^7.71.1", + "react-resizable-panels": "^4.4.1", + "recharts": "^2.15.4", + "sonner": "^2.0.7", + "tailwind-merge": "^3.4.0", + "vaul": "^1.1.2", "viem": "^2.44.4", "wagmi": "^3.3.4", + "zod": "^4.3.6", "zustand": "^5.0.10" }, "devDependencies": { "@tailwindcss/postcss": "^4", + "@types/jspdf": "^1.3.3", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", "autoprefixer": "^10.4.21", "postcss": "^8.5.3", "tailwindcss": "^4.1.4", + "tw-animate-css": "^1.4.0", "typescript": "^5" } }, @@ -109,7 +158,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" } @@ -198,7 +246,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", @@ -252,7 +299,6 @@ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" @@ -364,6 +410,7 @@ "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-4.3.7.tgz", "integrity": "sha512-z6e5XDw6EF06RqkeyEa+qD0dZ2ZbLci99vx3zwDY//XO8X7166tqKJrR2XlQnzVmtcUuJtCd5fCvr9Cu6zzX7w==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@noble/hashes": "^1.4.0", "clsx": "^1.2.1", @@ -372,22 +419,308 @@ "viem": "^2.27.2" } }, + "node_modules/@coinbase/wallet-sdk/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@date-fns/tz": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", + "integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==", + "license": "MIT" + }, + "node_modules/@ecies/ciphers": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.5.tgz", + "integrity": "sha512-GalEZH4JgOMHYYcYmVqnFirFsjZHeoGMDt9IxEnM9F7GRUUyUksJ7Ou53L83WHJq3RWKD3AcBpo0iQh0oMpf8A==", + "license": "MIT", + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + }, + "peerDependencies": { + "@noble/ciphers": "^1.0.0" + } + }, "node_modules/@emnapi/runtime": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", - "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", "optional": true, "dependencies": { "tslib": "^2.4.0" } }, + "node_modules/@ethereumjs/common": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz", + "integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==", + "license": "MIT", + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "crc-32": "^1.2.0" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz", + "integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==", + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/common": "^3.2.0", + "@ethereumjs/rlp": "^4.0.1", + "@ethereumjs/util": "^8.1.0", + "ethereum-cryptography": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@hookform/resolvers": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.2.2.tgz", + "integrity": "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.1.tgz", - "integrity": "sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", "cpu": [ "arm64" ], + "license": "Apache-2.0", "optional": true, "os": [ "darwin" @@ -399,16 +732,17 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.1.0" + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.1.tgz", - "integrity": "sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", "cpu": [ "x64" ], + "license": "Apache-2.0", "optional": true, "os": [ "darwin" @@ -420,16 +754,17 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.1.0" + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz", - "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", "cpu": [ "arm64" ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "darwin" @@ -439,12 +774,13 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz", - "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", "cpu": [ "x64" ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "darwin" @@ -454,12 +790,13 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz", - "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", "cpu": [ "arm" ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -469,12 +806,13 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz", - "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", "cpu": [ "arm64" ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -484,12 +822,29 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz", - "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", "cpu": [ "ppc64" ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -499,12 +854,13 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz", - "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", "cpu": [ "s390x" ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -514,12 +870,13 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz", - "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", "cpu": [ "x64" ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -529,12 +886,13 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz", - "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", "cpu": [ "arm64" ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -544,12 +902,13 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz", - "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", "cpu": [ "x64" ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -559,12 +918,13 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.1.tgz", - "integrity": "sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", "cpu": [ "arm" ], + "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -576,16 +936,61 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.1.0" + "@img/sharp-libvips-linux-arm": "1.2.4" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.1.tgz", - "integrity": "sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", "cpu": [ "arm64" ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -597,16 +1002,17 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.1.0" + "@img/sharp-libvips-linux-riscv64": "1.2.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.1.tgz", - "integrity": "sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", "cpu": [ "s390x" ], + "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -618,16 +1024,17 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.1.0" + "@img/sharp-libvips-linux-s390x": "1.2.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.1.tgz", - "integrity": "sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", "cpu": [ "x64" ], + "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -639,16 +1046,17 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.1.0" + "@img/sharp-libvips-linux-x64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.1.tgz", - "integrity": "sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", "cpu": [ "arm64" ], + "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -660,16 +1068,17 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.1.tgz", - "integrity": "sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", "cpu": [ "x64" ], + "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -681,20 +1090,40 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.1.0" + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.1.tgz", - "integrity": "sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", "cpu": [ "wasm32" ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.4.0" + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -703,12 +1132,13 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.1.tgz", - "integrity": "sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", "cpu": [ "ia32" ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" @@ -721,12 +1151,13 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.1.tgz", - "integrity": "sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", "cpu": [ "x64" ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" @@ -753,7 +1184,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -784,24 +1214,404 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@metamask/safe-event-emitter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz", - "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==", - "license": "ISC" + "node_modules/@metamask/json-rpc-engine": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@metamask/json-rpc-engine/-/json-rpc-engine-8.0.2.tgz", + "integrity": "sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA==", + "license": "ISC", + "dependencies": { + "@metamask/rpc-errors": "^6.2.1", + "@metamask/safe-event-emitter": "^3.0.0", + "@metamask/utils": "^8.3.0" + }, + "engines": { + "node": ">=16.0.0" + } }, - "node_modules/@next/env": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.1.tgz", - "integrity": "sha512-cwK27QdzrMblHSn9DZRV+DQscHXRuJv6MydlJRpFSqJWZrTYMLzKDeyueJNN9MGd8NNiUKzDQADAf+dMLXX7YQ==" + "node_modules/@metamask/json-rpc-engine/node_modules/@metamask/safe-event-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.2.tgz", + "integrity": "sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==", + "license": "ISC", + "engines": { + "node": ">=12.0.0" + } }, - "node_modules/@next/swc-darwin-arm64": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.1.tgz", - "integrity": "sha512-hjDw4f4/nla+6wysBL07z52Gs55Gttp5Bsk5/8AncQLJoisvTBP0pRIBK/B16/KqQyH+uN4Ww8KkcAqJODYH3w==", - "cpu": [ - "arm64" + "node_modules/@metamask/json-rpc-middleware-stream": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@metamask/json-rpc-middleware-stream/-/json-rpc-middleware-stream-7.0.2.tgz", + "integrity": "sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg==", + "license": "ISC", + "dependencies": { + "@metamask/json-rpc-engine": "^8.0.2", + "@metamask/safe-event-emitter": "^3.0.0", + "@metamask/utils": "^8.3.0", + "readable-stream": "^3.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/json-rpc-middleware-stream/node_modules/@metamask/safe-event-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.2.tgz", + "integrity": "sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==", + "license": "ISC", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/json-rpc-middleware-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@metamask/object-multiplex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-2.1.0.tgz", + "integrity": "sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA==", + "license": "ISC", + "dependencies": { + "once": "^1.4.0", + "readable-stream": "^3.6.2" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@metamask/object-multiplex/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@metamask/onboarding": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@metamask/onboarding/-/onboarding-1.0.1.tgz", + "integrity": "sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==", + "license": "MIT", + "dependencies": { + "bowser": "^2.9.0" + } + }, + "node_modules/@metamask/providers": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-16.1.0.tgz", + "integrity": "sha512-znVCvux30+3SaUwcUGaSf+pUckzT5ukPRpcBmy+muBLC0yaWnBcvDqGfcsw6CBIenUdFrVoAFa8B6jsuCY/a+g==", + "license": "MIT", + "dependencies": { + "@metamask/json-rpc-engine": "^8.0.1", + "@metamask/json-rpc-middleware-stream": "^7.0.1", + "@metamask/object-multiplex": "^2.0.0", + "@metamask/rpc-errors": "^6.2.1", + "@metamask/safe-event-emitter": "^3.1.1", + "@metamask/utils": "^8.3.0", + "detect-browser": "^5.2.0", + "extension-port-stream": "^3.0.0", + "fast-deep-equal": "^3.1.3", + "is-stream": "^2.0.0", + "readable-stream": "^3.6.2", + "webextension-polyfill": "^0.10.0" + }, + "engines": { + "node": "^18.18 || >=20" + } + }, + "node_modules/@metamask/providers/node_modules/@metamask/safe-event-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.2.tgz", + "integrity": "sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==", + "license": "ISC", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/providers/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@metamask/rpc-errors": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@metamask/rpc-errors/-/rpc-errors-6.4.0.tgz", + "integrity": "sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==", + "license": "MIT", + "dependencies": { + "@metamask/utils": "^9.0.0", + "fast-safe-stringify": "^2.0.6" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/rpc-errors/node_modules/@metamask/utils": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", + "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", + "license": "ISC", + "dependencies": { + "@ethereumjs/tx": "^4.2.0", + "@metamask/superstruct": "^3.1.0", + "@noble/hashes": "^1.3.1", + "@scure/base": "^1.1.3", + "@types/debug": "^4.1.7", + "debug": "^4.3.4", + "pony-cause": "^2.1.10", + "semver": "^7.5.4", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/rpc-errors/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@metamask/safe-event-emitter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz", + "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==", + "license": "ISC" + }, + "node_modules/@metamask/sdk": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@metamask/sdk/-/sdk-0.33.1.tgz", + "integrity": "sha512-1mcOQVGr9rSrVcbKPNVzbZ8eCl1K0FATsYH3WJ/MH4WcZDWGECWrXJPNMZoEAkLxWiMe8jOQBumg2pmcDa9zpQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.26.0", + "@metamask/onboarding": "^1.0.1", + "@metamask/providers": "16.1.0", + "@metamask/sdk-analytics": "0.0.5", + "@metamask/sdk-communication-layer": "0.33.1", + "@metamask/sdk-install-modal-web": "0.32.1", + "@paulmillr/qr": "^0.2.1", + "bowser": "^2.9.0", + "cross-fetch": "^4.0.0", + "debug": "4.3.4", + "eciesjs": "^0.4.11", + "eth-rpc-errors": "^4.0.3", + "eventemitter2": "^6.4.9", + "obj-multiplex": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^3.6.2", + "socket.io-client": "^4.5.1", + "tslib": "^2.6.0", + "util": "^0.12.4", + "uuid": "^8.3.2" + } + }, + "node_modules/@metamask/sdk-analytics": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@metamask/sdk-analytics/-/sdk-analytics-0.0.5.tgz", + "integrity": "sha512-fDah+keS1RjSUlC8GmYXvx6Y26s3Ax1U9hGpWb6GSY5SAdmTSIqp2CvYy6yW0WgLhnYhW+6xERuD0eVqV63QIQ==", + "license": "MIT", + "dependencies": { + "openapi-fetch": "^0.13.5" + } + }, + "node_modules/@metamask/sdk-install-modal-web": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/@metamask/sdk-install-modal-web/-/sdk-install-modal-web-0.32.1.tgz", + "integrity": "sha512-MGmAo6qSjf1tuYXhCu2EZLftq+DSt5Z7fsIKr2P+lDgdTPWgLfZB1tJKzNcwKKOdf6q9Qmmxn7lJuI/gq5LrKw==", + "dependencies": { + "@paulmillr/qr": "^0.2.1" + } + }, + "node_modules/@metamask/sdk/node_modules/@metamask/sdk-communication-layer": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.33.1.tgz", + "integrity": "sha512-0bI9hkysxcfbZ/lk0T2+aKVo1j0ynQVTuB3sJ5ssPWlz+Z3VwveCkP1O7EVu1tsVVCb0YV5WxK9zmURu2FIiaA==", + "dependencies": { + "@metamask/sdk-analytics": "0.0.5", + "bufferutil": "^4.0.8", + "date-fns": "^2.29.3", + "debug": "4.3.4", + "utf-8-validate": "^5.0.2", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "cross-fetch": "^4.0.0", + "eciesjs": "*", + "eventemitter2": "^6.4.9", + "readable-stream": "^3.6.2", + "socket.io-client": "^4.5.1" + } + }, + "node_modules/@metamask/sdk/node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", + "peer": true, + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/@metamask/sdk/node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/@metamask/sdk/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@metamask/sdk/node_modules/eth-rpc-errors": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", + "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", + "license": "MIT", + "dependencies": { + "fast-safe-stringify": "^2.0.6" + } + }, + "node_modules/@metamask/sdk/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/@metamask/sdk/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@metamask/sdk/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@metamask/superstruct": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@metamask/superstruct/-/superstruct-3.2.1.tgz", + "integrity": "sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/utils": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", + "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", + "license": "ISC", + "dependencies": { + "@ethereumjs/tx": "^4.2.0", + "@metamask/superstruct": "^3.0.0", + "@noble/hashes": "^1.3.1", + "@scure/base": "^1.1.3", + "@types/debug": "^4.1.7", + "debug": "^4.3.4", + "pony-cause": "^2.1.10", + "semver": "^7.5.4", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/utils/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@next/env": { + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.4.tgz", + "integrity": "sha512-gkrXnZyxPUy0Gg6SrPQPccbNVLSP3vmW8LU5dwEttEEC1RwDivk8w4O+sZIjFvPrSICXyhQDCG+y3VmjlJf+9A==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.4.tgz", + "integrity": "sha512-T8atLKuvk13XQUdVLCv1ZzMPgLPW0+DWWbHSQXs0/3TjPrKNxTmUIhOEaoEyl3Z82k8h/gEtqyuoZGv6+Ugawg==", + "cpu": [ + "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -811,12 +1621,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.1.tgz", - "integrity": "sha512-q+aw+cJ2ooVYdCEqZVk+T4Ni10jF6Fo5DfpEV51OupMaV5XL6pf3GCzrk6kSSZBsMKZtVC1Zm/xaNBFpA6bJ2g==", + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.4.tgz", + "integrity": "sha512-AKC/qVjUGUQDSPI6gESTx0xOnOPQ5gttogNS3o6bA83yiaSZJek0Am5yXy82F1KcZCx3DdOwdGPZpQCluonuxg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -826,12 +1637,13 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.1.tgz", - "integrity": "sha512-wBQ+jGUI3N0QZyWmmvRHjXjTWFy8o+zPFLSOyAyGFI94oJi+kK/LIZFJXeykvgXUk1NLDAEFDZw/NVINhdk9FQ==", + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.4.tgz", + "integrity": "sha512-POQ65+pnYOkZNdngWfMEt7r53bzWiKkVNbjpmCt1Zb3V6lxJNXSsjwRuTQ8P/kguxDC8LRkqaL3vvsFrce4dMQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -841,12 +1653,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.1.tgz", - "integrity": "sha512-IIxXEXRti/AulO9lWRHiCpUUR8AR/ZYLPALgiIg/9ENzMzLn3l0NSxVdva7R/VDcuSEBo0eGVCe3evSIHNz0Hg==", + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.4.tgz", + "integrity": "sha512-3Wm0zGYVCs6qDFAiSSDL+Z+r46EdtCv/2l+UlIdMbAq9hPJBvGu/rZOeuvCaIUjbArkmXac8HnTyQPJFzFWA0Q==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -856,12 +1669,29 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.1.tgz", - "integrity": "sha512-bfI4AMhySJbyXQIKH5rmLJ5/BP7bPwuxauTvVEiJ/ADoddaA9fgyNNCcsbu9SlqfHDoZmfI6g2EjzLwbsVTr5A==", + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.4.tgz", + "integrity": "sha512-lWAYAezFinaJiD5Gv8HDidtsZdT3CDaCeqoPoJjeB57OqzvMajpIhlZFce5sCAH6VuX4mdkxCRqecCJFwfm2nQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.4.tgz", + "integrity": "sha512-fHaIpT7x4gA6VQbdEpYUXRGyge/YbRrkG6DXM60XiBqDM2g2NcrsQaIuj375egnGFkJow4RHacgBOEsHfGbiUw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -870,99 +1700,1715 @@ "node": ">= 10" } }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.1.tgz", - "integrity": "sha512-FeAbR7FYMWR+Z+M5iSGytVryKHiAsc0x3Nc3J+FD5NVbD5Mqz7fTSy8CYliXinn7T26nDMbpExRUI/4ekTvoiA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.4.tgz", + "integrity": "sha512-MCrXxrTSE7jPN1NyXJr39E+aNFBrQZtO154LoCz7n99FuKqJDekgxipoodLNWdQP7/DZ5tKMc/efybx1l159hw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.4.tgz", + "integrity": "sha512-JSVlm9MDhmTXw/sO2PE/MRj+G6XOSMZB+BcZ0a7d6KwVFZVpkHcb2okyoYFBaco6LeiL53BBklRlOrDDbOeE5w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.0.tgz", + "integrity": "sha512-YGdEUzYEd+82jeaVbSKKVp1jFZb8LwaNMIIzHFkihGvYdd/KKAr7KaJHdEdSYGredE3ssSravXIa0Jxg28Sv5w==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@paulmillr/qr": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@paulmillr/qr/-/qr-0.2.1.tgz", + "integrity": "sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==", + "deprecated": "The package is now available as \"qr\": npm install qr", + "license": "(MIT OR Apache-2.0)", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.8.tgz", + "integrity": "sha512-5nZrJTF7gH+e0nZS7/QxFz6tJV4VimhQb1avEgtsJxvvIp5JilL+c58HICsKzPxghdwaDt48hEfPM1au4zGy+w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", + "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", + "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", + "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz", + "integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", + "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", + "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", + "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", + "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.1.tgz", - "integrity": "sha512-yP7FueWjphQEPpJQ2oKmshk/ppOt+0/bB8JC8svPUZNy0Pi3KbPx2Llkzv1p8CoQa+D2wknINlJpHf3vtChVBw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" + "node_modules/@radix-ui/react-use-is-hydrated/node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.1.tgz", - "integrity": "sha512-3PMvF2zRJAifcRNni9uMk/gulWfWS+qVI/pagd+4yLF5bcXPZPPH2xlYRYOsUjmCJOXSTAC2PjRzbhsRzR2fDQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@noble/ciphers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.0.tgz", - "integrity": "sha512-YGdEUzYEd+82jeaVbSKKVp1jFZb8LwaNMIIzHFkihGvYdd/KKAr7KaJHdEdSYGredE3ssSravXIa0Jxg28Sv5w==", + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", "license": "MIT", "dependencies": { - "@noble/hashes": "1.3.2" + "@radix-ui/rect": "1.1.1" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", "license": "MIT", - "engines": { - "node": ">= 16" + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, "node_modules/@scure/base": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", @@ -1014,10 +3460,17 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" }, "node_modules/@swc/helpers": { "version": "0.5.15", @@ -1285,6 +3738,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.19.tgz", "integrity": "sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" @@ -1295,6 +3749,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.19.tgz", "integrity": "sha512-qTZRZ4QyTzQc+M0IzrbKHxSeISUmRB3RPGmao5bT+sI6ayxSRhn0FXEnT5Hg3as8SBFcRosrXXRFB+yAcxVxJQ==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/query-core": "5.90.19" }, @@ -1315,6 +3770,91 @@ "@types/node": "*" } }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/jspdf": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/jspdf/-/jspdf-1.3.3.tgz", + "integrity": "sha512-DqwyAKpVuv+7DniCp2Deq1xGvfdnKSNgl9Agun2w6dFvR5UKamiv4VfYUgcypd8S9ojUyARFIlZqBrYrBMQlew==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.17.32", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.32.tgz", @@ -1323,6 +3863,12 @@ "undici-types": "~6.19.2" } }, + "node_modules/@types/pako": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz", + "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==", + "license": "MIT" + }, "node_modules/@types/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -1332,11 +3878,19 @@ "@types/node": "*" } }, + "node_modules/@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/react": { "version": "19.1.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz", "integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==", "devOptional": true, + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1345,7 +3899,8 @@ "version": "19.1.2", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz", "integrity": "sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==", - "dev": true, + "devOptional": true, + "peer": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -1359,6 +3914,13 @@ "@types/node": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@wagmi/connectors": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@wagmi/connectors/-/connectors-7.1.2.tgz", @@ -1415,6 +3977,7 @@ "resolved": "https://registry.npmjs.org/@wagmi/core/-/core-3.2.2.tgz", "integrity": "sha512-nCCza85tmE/lNorZemv0ah0OwOewMRiNJbSkIkGPr/mSH6mAy+/D/GbP8Gb3j2Nw85LuF5wxgG1fFiU6mB3CyQ==", "license": "MIT", + "peer": true, "dependencies": { "eventemitter3": "5.0.1", "mipd": "0.0.7", @@ -1785,6 +4348,18 @@ } } }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/abstract-leveldown": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz", @@ -1853,6 +4428,18 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "license": "MIT" }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -2046,6 +4633,16 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2096,6 +4693,12 @@ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", "license": "MIT" }, + "node_modules/bowser": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz", + "integrity": "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==", + "license": "MIT" + }, "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", @@ -2135,6 +4738,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2239,15 +4843,18 @@ "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "license": "MIT" }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "node_modules/bufferutil": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", + "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, "dependencies": { - "streamsearch": "^1.1.0" + "node-gyp-build": "^4.3.0" }, "engines": { - "node": ">=10.16.0" + "node": ">=6.14.2" } }, "node_modules/call-bind": { @@ -2326,6 +4933,26 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canvg": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz", + "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -2355,6 +4982,18 @@ "node": ">= 0.10" } }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -2381,53 +5020,28 @@ } }, "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "optional": true, + "node_modules/cmdk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@radix-ui/react-compose-refs": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.2" }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "optional": true - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "optional": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "node_modules/combined-stream": { @@ -2446,8 +5060,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/cookiejar": { "version": "2.1.4", @@ -2464,6 +5077,18 @@ "toggle-selection": "^1.0.6" } }, + "node_modules/core-js": { + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", + "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-js-compat": { "version": "3.47.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", @@ -2483,6 +5108,18 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -2520,11 +5157,141 @@ "whatwg-fetch": "^2.0.4" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, "node_modules/dashdash": { "version": "1.14.1", @@ -2538,6 +5305,22 @@ "node": ">=0.10" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/date-fns-jalali": { + "version": "4.1.0-0", + "resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz", + "integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -2564,6 +5347,12 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, "node_modules/decode-uri-component": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", @@ -2616,25 +5405,52 @@ "license": "MIT" }, "node_modules/detect-libc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", - "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "devOptional": true, + "license": "Apache-2.0", "engines": { "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/dijkstrajs": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", "license": "MIT" }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-walk": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" }, + "node_modules/dompurify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", + "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optional": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2659,6 +5475,50 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/eciesjs": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.16.tgz", + "integrity": "sha512-dS5cbA9rA2VR4Ybuvhg6jvdmp46ubLn3E+px8cG/35aEDNclrqoCjg6mt0HYZ/M+OoESS3jSkCrqk1kWAEhWAw==", + "license": "MIT", + "dependencies": { + "@ecies/ciphers": "^0.2.4", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0" + }, + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + } + }, + "node_modules/eciesjs/node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/eciesjs/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.267", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", @@ -2686,12 +5546,93 @@ "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "license": "MIT" }, + "node_modules/embla-carousel": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", + "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", + "license": "MIT", + "peer": true + }, + "node_modules/embla-carousel-react": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-react/-/embla-carousel-react-8.6.0.tgz", + "integrity": "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==", + "license": "MIT", + "dependencies": { + "embla-carousel": "8.6.0", + "embla-carousel-reactive-utils": "8.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/embla-carousel-reactive-utils": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-reactive-utils/-/embla-carousel-reactive-utils-8.6.0.tgz", + "integrity": "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A==", + "license": "MIT", + "peerDependencies": { + "embla-carousel": "8.6.0" + } + }, "node_modules/emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "license": "MIT" }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz", + "integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", @@ -3160,6 +6101,22 @@ "npm": ">=3" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", + "license": "MIT", + "peer": true + }, "node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", @@ -3191,6 +6148,68 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/extension-port-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-3.0.0.tgz", + "integrity": "sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==", + "license": "ISC", + "dependencies": { + "readable-stream": "^3.6.2 || ^4.4.2", + "webextension-polyfill": ">=0.10.0 <1.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/extension-port-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/extension-port-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/extension-port-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -3215,18 +6234,44 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT" }, + "node_modules/fast-png": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz", + "integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==", + "license": "MIT", + "dependencies": { + "@types/pako": "^2.0.3", + "iobuffer": "^5.3.2", + "pako": "^2.1.0" + } + }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "license": "MIT" }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, "node_modules/find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -3290,6 +6335,33 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "12.29.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.29.0.tgz", + "integrity": "sha512-1gEFGXHYV2BD42ZPTFmSU9buehppU+bCuOnHU0AD18DKh9j4DuTx47MvqY5ax+NNWRtK32qIcJf1UxKo1WwjWg==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.29.0", + "motion-utils": "^12.27.2", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -3305,12 +6377,20 @@ "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "license": "MIT" }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -3348,6 +6428,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -3508,6 +6597,20 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "optional": true, + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -3555,11 +6658,46 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "optional": true + "node_modules/input-otp": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.2.tgz", + "integrity": "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/iobuffer": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz", + "integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==", + "license": "MIT" + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-callable": { "version": "1.2.7", @@ -3612,6 +6750,25 @@ "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", "license": "MIT" }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-hex-prefixed": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", @@ -3622,6 +6779,36 @@ "npm": ">=3" } }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", @@ -3779,7 +6966,6 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "license": "MIT", - "peer": true, "bin": { "json5": "lib/cli.js" }, @@ -3796,6 +6982,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/jspdf": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.0.0.tgz", + "integrity": "sha512-w12U97Z6edKd2tXDn3LzTLg7C7QLJlx0BPfM3ecjK2BckUl9/81vZ+r5gK4/3KQdhAcEZhENUxRhtgYBj75MqQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "fast-png": "^6.2.0", + "fflate": "^0.8.1" + }, + "optionalDependencies": { + "canvg": "^3.0.11", + "core-js": "^3.6.0", + "dompurify": "^3.2.4", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/jspdf-autotable": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-5.0.7.tgz", + "integrity": "sha512-2wr7H6liNDBYNwt25hMQwXkEWFOEopgKIvR1Eukuw6Zmprm/ZcnmLTQEjW7Xx3FCbD3v7pflLcnMAv/h1jFDQw==", + "license": "MIT", + "peerDependencies": { + "jspdf": "^2 || ^3 || ^4" + } + }, "node_modules/jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -4228,6 +7441,18 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4243,6 +7468,15 @@ "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==", "license": "MIT" }, + "node_modules/lucide-react": { + "version": "0.562.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.562.0.tgz", + "integrity": "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -4316,6 +7550,12 @@ "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", "license": "MIT" }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", + "license": "MIT" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -4378,6 +7618,21 @@ } } }, + "node_modules/motion-dom": { + "version": "12.29.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.29.0.tgz", + "integrity": "sha512-3eiz9bb32yvY8Q6XNM4AwkSOBPgU//EIKTZwsSWgA9uzbPBhZJeScCVcBuwwYVqhfamewpv7ZNmVKTGp5qnzkA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.27.2" + } + }, + "node_modules/motion-utils": { + "version": "12.27.2", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.27.2.tgz", + "integrity": "sha512-B55gcoL85Mcdt2IEStY5EEAsrMSVE2sI14xQ/uAdPL+mfQxhKKFaEag9JmfxedJOR4vZpBGoPeC/Gm13I/4g5Q==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4402,14 +7657,14 @@ } }, "node_modules/next": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/next/-/next-15.3.1.tgz", - "integrity": "sha512-8+dDV0xNLOgHlyBxP1GwHGVaNXsmp+2NhZEYrXr24GWLHtt27YrBPbPuHvzlhi7kZNYjeJNR93IF5zfFu5UL0g==", + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.4.tgz", + "integrity": "sha512-gKSecROqisnV7Buen5BfjmXAm7Xlpx9o2ueVQRo5DxQcjC8d330dOM1xiGWc2k3Dcnz0In3VybyRPOsudwgiqQ==", + "license": "MIT", "dependencies": { - "@next/env": "15.3.1", - "@swc/counter": "0.1.3", + "@next/env": "16.1.4", "@swc/helpers": "0.5.15", - "busboy": "1.6.0", + "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -4418,22 +7673,22 @@ "next": "dist/bin/next" }, "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.3.1", - "@next/swc-darwin-x64": "15.3.1", - "@next/swc-linux-arm64-gnu": "15.3.1", - "@next/swc-linux-arm64-musl": "15.3.1", - "@next/swc-linux-x64-gnu": "15.3.1", - "@next/swc-linux-x64-musl": "15.3.1", - "@next/swc-win32-arm64-msvc": "15.3.1", - "@next/swc-win32-x64-msvc": "15.3.1", - "sharp": "^0.34.1" + "@next/swc-darwin-arm64": "16.1.4", + "@next/swc-darwin-x64": "16.1.4", + "@next/swc-linux-arm64-gnu": "16.1.4", + "@next/swc-linux-arm64-musl": "16.1.4", + "@next/swc-linux-x64-gnu": "16.1.4", + "@next/swc-linux-x64-musl": "16.1.4", + "@next/swc-win32-arm64-msvc": "16.1.4", + "@next/swc-win32-x64-msvc": "16.1.4", + "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.41.2", + "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", @@ -4454,6 +7709,16 @@ } } }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -4542,6 +7807,26 @@ "node": "*" } }, + "node_modules/obj-multiplex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/obj-multiplex/-/obj-multiplex-1.0.0.tgz", + "integrity": "sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==", + "license": "ISC", + "dependencies": { + "end-of-stream": "^1.4.0", + "once": "^1.4.0", + "readable-stream": "^2.3.3" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -4551,6 +7836,30 @@ "node": ">= 0.4" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openapi-fetch": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.13.8.tgz", + "integrity": "sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==", + "license": "MIT", + "dependencies": { + "openapi-typescript-helpers": "^0.0.15" + } + }, + "node_modules/openapi-typescript-helpers": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.15.tgz", + "integrity": "sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==", + "license": "MIT" + }, "node_modules/ox": { "version": "0.11.3", "resolved": "https://registry.npmjs.org/ox/-/ox-0.11.3.tgz", @@ -4562,6 +7871,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", @@ -4656,6 +7966,12 @@ "node": ">=6" } }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, "node_modules/parse-headers": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz", @@ -4723,6 +8039,15 @@ "node": ">=4.0.0" } }, + "node_modules/pony-cause": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", + "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", + "license": "0BSD", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -4751,6 +8076,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -4812,6 +8138,23 @@ "node": ">=0.10.0" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -4830,6 +8173,16 @@ "url": "https://github.com/sponsors/lupomontero" } }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -4839,79 +8192,247 @@ "node": ">=6" } }, - "node_modules/qrcode": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.4.4.tgz", - "integrity": "sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==", + "node_modules/qrcode": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.4.4.tgz", + "integrity": "sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==", + "license": "MIT", + "dependencies": { + "buffer": "^5.4.3", + "buffer-alloc": "^1.2.0", + "buffer-from": "^1.1.1", + "dijkstrajs": "^1.0.1", + "isarray": "^2.0.1", + "pngjs": "^3.3.0", + "yargs": "^13.2.4" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-string": { + "version": "6.13.5", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.13.5.tgz", + "integrity": "sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", + "optional": true, + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-day-picker": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.13.0.tgz", + "integrity": "sha512-euzj5Hlq+lOHqI53NiuNhCP8HWgsPf/bBAVijR50hNaY1XwjKjShAnIe8jm8RD2W9IJUvihDIZ+KrmqfFzNhFQ==", + "license": "MIT", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "date-fns": "^4.1.0", + "date-fns-jalali": "^4.1.0-0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.3" + } + }, + "node_modules/react-hook-form": { + "version": "7.71.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.1.tgz", + "integrity": "sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "license": "MIT", "dependencies": { - "buffer": "^5.4.3", - "buffer-alloc": "^1.2.0", - "buffer-from": "^1.1.1", - "dijkstrajs": "^1.0.1", - "isarray": "^2.0.1", - "pngjs": "^3.3.0", - "yargs": "^13.2.4" + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" }, - "bin": { - "qrcode": "bin/qrcode" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "license": "BSD-3-Clause", "engines": { - "node": ">=0.6" + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/query-string": { - "version": "6.13.5", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.13.5.tgz", - "integrity": "sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q==", + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", "license": "MIT", "dependencies": { - "decode-uri-component": "^0.2.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/react-resizable-panels": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.4.1.tgz", + "integrity": "sha512-dpM9oI6rGlAq7VYDeafSRA1JmkJv8aNuKySR+tZLQQLfaeqTnQLSM52EcoI/QdowzsjVUCk6jViKS0xHWITVRQ==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", "license": "MIT", "dependencies": { - "safe-buffer": "^5.1.0" + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/react": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", - "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/react-dom": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", - "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", "dependencies": { - "scheduler": "^0.26.0" + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" }, "peerDependencies": { - "react": "^19.1.0" + "react": ">=16.6.0", + "react-dom": ">=16.6.0" } }, "node_modules/readable-stream": { @@ -4941,6 +8462,51 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, + "node_modules/recharts": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.4", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT", + "optional": true + }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -5008,6 +8574,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "license": "MIT OR SEE LICENSE IN FEEL-FREE.md", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, "node_modules/ripemd160": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", @@ -5075,6 +8651,23 @@ "events": "^3.0.0" } }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5082,9 +8675,10 @@ "license": "MIT" }, "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==" + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/scrypt-js": { "version": "3.0.1", @@ -5122,10 +8716,10 @@ } }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "optional": true, + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -5192,15 +8786,16 @@ } }, "node_modules/sharp": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.1.tgz", - "integrity": "sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", "hasInstallScript": true, + "license": "Apache-2.0", "optional": true, "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.7.1" + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -5209,35 +8804,69 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.1", - "@img/sharp-darwin-x64": "0.34.1", - "@img/sharp-libvips-darwin-arm64": "1.1.0", - "@img/sharp-libvips-darwin-x64": "1.1.0", - "@img/sharp-libvips-linux-arm": "1.1.0", - "@img/sharp-libvips-linux-arm64": "1.1.0", - "@img/sharp-libvips-linux-ppc64": "1.1.0", - "@img/sharp-libvips-linux-s390x": "1.1.0", - "@img/sharp-libvips-linux-x64": "1.1.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", - "@img/sharp-libvips-linuxmusl-x64": "1.1.0", - "@img/sharp-linux-arm": "0.34.1", - "@img/sharp-linux-arm64": "0.34.1", - "@img/sharp-linux-s390x": "0.34.1", - "@img/sharp-linux-x64": "0.34.1", - "@img/sharp-linuxmusl-arm64": "0.34.1", - "@img/sharp-linuxmusl-x64": "0.34.1", - "@img/sharp-wasm32": "0.34.1", - "@img/sharp-win32-ia32": "0.34.1", - "@img/sharp-win32-x64": "0.34.1" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "optional": true, + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/socket.io-client": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", + "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", + "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", + "license": "MIT", "dependencies": { - "is-arrayish": "^0.3.1" + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sonner": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", + "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "node_modules/source-map-js": { @@ -5282,12 +8911,14 @@ "node": ">=0.10.0" } }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "node_modules/stackblur-canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz", + "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==", + "license": "MIT", + "optional": true, "engines": { - "node": ">=10.0.0" + "node": ">=0.1.14" } }, "node_modules/strict-uri-encode": { @@ -5387,6 +9018,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tailwind-merge": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", + "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.4.tgz", @@ -5402,6 +9053,22 @@ "node": ">=6" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, "node_modules/to-buffer": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", @@ -5458,6 +9125,16 @@ "node": "*" } }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", @@ -5492,6 +9169,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "devOptional": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5544,21 +9222,102 @@ "punycode": "^2.1.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sync-external-store": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", "license": "MIT", + "peer": true, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -5569,6 +9328,19 @@ "uuid": "bin/uuid" } }, + "node_modules/vaul": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", + "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -5589,6 +9361,28 @@ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "license": "MIT" }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/viem": { "version": "2.44.4", "resolved": "https://registry.npmjs.org/viem/-/viem-2.44.4.tgz", @@ -5600,6 +9394,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", @@ -5736,6 +9531,7 @@ "resolved": "https://registry.npmjs.org/@wagmi/core/-/core-3.2.3.tgz", "integrity": "sha512-5PpalEdyHA2DkIl/ultwZ8GqRj6wpkZK80i3q6ve+auJQZmLokK3oysKxVuqMvgEGRBHorrnfMszPkx6j0xHng==", "license": "MIT", + "peer": true, "dependencies": { "eventemitter3": "5.0.1", "mipd": "0.0.7", @@ -5837,6 +9633,12 @@ "async-limiter": "~1.0.0" } }, + "node_modules/webextension-polyfill": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", + "license": "MPL-2.0" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -5900,11 +9702,18 @@ "node": ">=6" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, "node_modules/ws": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", "license": "MIT", + "peer": true, "engines": { "node": ">=8.3.0" }, @@ -5942,6 +9751,14 @@ "cookiejar": "^2.1.1" } }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -5991,6 +9808,16 @@ "decamelize": "^1.2.0" } }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/zustand": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.10.tgz", diff --git a/package.json b/package.json index bdf96759..5e9c8bfd 100644 --- a/package.json +++ b/package.json @@ -10,26 +10,75 @@ }, "dependencies": { "@coinbase/wallet-sdk": "^4.3.7", + "@hookform/resolvers": "^5.2.2", + "@metamask/sdk": "^0.33.1", + "@radix-ui/react-accordion": "^1.2.12", + "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-aspect-ratio": "^1.1.8", + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-context-menu": "^2.2.16", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-hover-card": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-menubar": "^1.1.16", + "@radix-ui/react-navigation-menu": "^1.2.14", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-progress": "^1.1.8", + "@radix-ui/react-radio-group": "^1.3.8", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slider": "^1.3.6", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-toggle": "^1.1.10", + "@radix-ui/react-toggle-group": "^1.1.11", + "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-query": "^5.90.19", "@wagmi/connectors": "^7.1.2", "@wagmi/core": "^3.2.2", "@walletconnect/web3-provider": "^1.8.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", + "embla-carousel-react": "^8.6.0", "ethers": "^6.16.0", - "next": "15.3.1", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "framer-motion": "^12.29.0", + "input-otp": "^1.4.2", + "jspdf": "^4.0.0", + "jspdf-autotable": "^5.0.7", + "lucide-react": "^0.562.0", + "next": "^16.1.4", + "next-themes": "^0.4.6", + "react": "^19.2.3", + "react-day-picker": "^9.13.0", + "react-dom": "^19.2.3", + "react-hook-form": "^7.71.1", + "react-resizable-panels": "^4.4.1", + "recharts": "^2.15.4", + "sonner": "^2.0.7", + "tailwind-merge": "^3.4.0", + "vaul": "^1.1.2", "viem": "^2.44.4", "wagmi": "^3.3.4", + "zod": "^4.3.6", "zustand": "^5.0.10" }, "devDependencies": { "@tailwindcss/postcss": "^4", + "@types/jspdf": "^1.3.3", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", "autoprefixer": "^10.4.21", "postcss": "^8.5.3", "tailwindcss": "^4.1.4", + "tw-animate-css": "^1.4.0", "typescript": "^5" } } diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx new file mode 100644 index 00000000..fded20f2 --- /dev/null +++ b/src/app/dashboard/page.tsx @@ -0,0 +1,123 @@ +"use client"; + +import { useState } from "react"; +// import { Header } from "@/components/dashboard/Header"; +// import { Sidebar } from "@/components/dashboard/Sidebar"; +import { PortfolioOverview } from "@/components/dashboard/PortfolioOverview"; +import { PerformanceChart } from "@/components/dashboard/PerformanceChart"; +import { DiversificationChart } from "@/components/dashboard/DiversificationChart"; +import { PropertiesList } from "@/components/dashboard/PropertiesList"; +import { RecentTransactions } from "@/components/dashboard/RecentTransactions"; +import { IncomeTracker } from "@/components/dashboard/IncomeTracker"; + +import { RiskAnalysis } from "@/components/dashboard/RiskAnalysis"; +import { PortfolioReport } from "@/components/dashboard/PortfolioReport"; +import { DataRefreshWrapper } from "@/components/dashboard/DataRefreshWrapper"; +import { WalletConnector } from "@/components/WalletConnector"; +import { TransactionQueue } from "@/components/TransactionQueue"; +import { TransactionHistory } from "@/components/TransactionHistory"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; + +const Index = () => { + const [sidebarOpen, setSidebarOpen] = useState(false); + const [activeItem, setActiveItem] = useState("dashboard"); + + return ( +
+ {/* setSidebarOpen(false)} + activeItem={activeItem} + onItemClick={(item) => { + setActiveItem(item); + setSidebarOpen(false); + }} + /> */} + +
+ {/*
setSidebarOpen(true)} /> */} +
+
+
+
+
+
+ PC +
+

+ PropChain +

+
+ +
+
+
+ +
+ {/* Welcome section */} +
+

+ Welcome back, John +

+

+ Here's an overview of your real estate token portfolio +

+
+ + {/* KPI Overview */} + {/* */} + + {/* Data Refresh Wrapper for KPIs */} + + + + + {/* Charts row */} +
+
+ +
+
+ +
+
+ + {/* Income Tracker */} + + + {/* Risk Analysis */} + + + {/* Export Reports */} + + + {/* Properties */} + + + {/* Transaction Management */} +
+

Transaction Management

+ + + Transaction Queue + Transaction History + + + + + + + + +
+ + {/* Transactions */} + +
+
+
+
+ ); +}; + +export default Index; diff --git a/src/app/globals.css b/src/app/globals.css index a2dc41ec..deb4bbf9 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,3 +1,4 @@ +/* @import "tailwindcss"; :root { @@ -23,4 +24,157 @@ body { background: var(--background); color: var(--foreground); font-family: Arial, Helvetica, sans-serif; +} */ + +@import "tailwindcss"; +@import "tw-animate-css"; +@import "../styles/mobile.css"; + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --color-success: var(--success); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --radius-2xl: calc(var(--radius) + 8px); + --radius-3xl: calc(var(--radius) + 12px); + --radius-4xl: calc(var(--radius) + 16px); +} + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.5 0.2 250); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --success: oklch(0.627 0.194 142.495); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.6 0.25 250); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --success: oklch(0.647 0.169 142.495); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} + +/* Glass card effect */ +.glass-card { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.2); + box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); +} + +.dark .glass-card { + background: rgba(0, 0, 0, 0.2); + border: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); +} + +/* Gradient text effect */ +.gradient-text { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b2195875..3c32f336 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import "@/utils/earlyErrorSuppression"; +import { ClientProviders } from "@/components/ClientProviders"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -15,7 +16,8 @@ const geistMono = Geist_Mono({ export const metadata: Metadata = { title: "PropChain - Multi-Chain Real Estate Platform", - description: "Seamless multi-chain wallet connectivity for real estate tokenization on Ethereum, Polygon, and BSC", + description: + "Seamless multi-chain wallet connectivity for real estate tokenization on Ethereum, Polygon, and BSC", }; export default function RootLayout({ @@ -28,7 +30,7 @@ export default function RootLayout({ - {children} + {children} ); diff --git a/src/app/mobile-properties/page.tsx b/src/app/mobile-properties/page.tsx new file mode 100644 index 00000000..42287c45 --- /dev/null +++ b/src/app/mobile-properties/page.tsx @@ -0,0 +1,448 @@ +"use client"; + +import React, { useState, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { + Search, + Filter, + MapPin, + Camera, + Download, + Grid3X3, + List, + ScanLine, + Wifi, + WifiOff, +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Badge } from "@/components/ui/badge"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { MobilePropertyCard } from "@/components/mobile/MobilePropertyCard"; +import { LocationBasedDiscovery } from "@/components/mobile/LocationBasedDiscovery"; +import { ARPropertyPreview } from "@/components/mobile/ARPropertyPreview"; +import { OfflinePropertyCache } from "@/components/mobile/OfflinePropertyCache"; + +// Enhanced property data with mobile-specific features +const properties = [ + { + id: "1", + name: "Manhattan Tower Suite", + location: "New York, NY", + type: "Commercial", + value: 524000, + tokens: 1048, + roi: 14.2, + monthlyIncome: 3280, + images: [ + "https://images.unsplash.com/photo-1486325212027-8081e485255e?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1497366216548-37526070297c?w=800&auto=format&fit=crop&q=80", + ], + description: + "Premium commercial space in the heart of Manhattan with excellent foot traffic and modern amenities. Perfect for retail or office use.", + sqft: 2500, + yearBuilt: 2018, + amenities: [ + "Parking", + "Security", + "Elevator", + "AC", + "High-speed Internet", + "Conference Room", + ], + coordinates: { lat: 40.7589, lng: -73.9851 }, + }, + { + id: "2", + name: "Sunset Beach Villa", + location: "Miami, FL", + type: "Residential", + value: 389000, + tokens: 778, + roi: 11.8, + monthlyIncome: 2450, + images: [ + "https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1613490493576-7fde63acd811?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1512917774080-9991f1c4c750?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?w=800&auto=format&fit=crop&q=80", + ], + description: + "Beautiful beachfront villa with stunning ocean views and private beach access. Fully furnished with modern amenities.", + bedrooms: 4, + bathrooms: 3, + sqft: 3200, + yearBuilt: 2020, + amenities: [ + "Pool", + "Beach Access", + "Garage", + "Garden", + "Ocean View", + "Smart Home", + ], + coordinates: { lat: 25.7617, lng: -80.1918 }, + }, + { + id: "3", + name: "Tech Hub Office Complex", + location: "San Francisco, CA", + type: "Commercial", + value: 892000, + tokens: 1784, + roi: 9.5, + monthlyIncome: 5620, + images: [ + "https://images.unsplash.com/photo-1497366216548-37526070297c?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1497366811353-6870744d04b2?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=800&auto=format&fit=crop&q=80", + ], + description: + "Modern office complex in the heart of Silicon Valley, perfect for tech companies. Features state-of-the-art facilities.", + sqft: 5000, + yearBuilt: 2019, + amenities: [ + "Parking", + "Cafeteria", + "Gym", + "Conference Rooms", + "Rooftop Terrace", + "EV Charging", + ], + coordinates: { lat: 37.7749, lng: -122.4194 }, + }, + { + id: "4", + name: "Industrial Logistics Park", + location: "Dallas, TX", + type: "Industrial", + value: 456000, + tokens: 912, + roi: 8.3, + monthlyIncome: 2890, + images: [ + "https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1565008447742-97f6f38c985c?w=800&auto=format&fit=crop&q=80", + ], + description: + "Strategic industrial facility with excellent logistics access and modern warehouse capabilities.", + sqft: 15000, + yearBuilt: 2017, + amenities: [ + "Loading Docks", + "Security", + "Rail Access", + "Truck Parking", + "Office Space", + ], + coordinates: { lat: 32.7767, lng: -96.797 }, + }, + { + id: "5", + name: "Downtown Luxury Lofts", + location: "Chicago, IL", + type: "Residential", + value: 312000, + tokens: 624, + roi: -2.1, + monthlyIncome: 1980, + images: [ + "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?w=800&auto=format&fit=crop&q=80", + ], + description: + "Stylish urban lofts in downtown Chicago with exposed brick and modern finishes. Great city views.", + bedrooms: 2, + bathrooms: 2, + sqft: 1800, + yearBuilt: 2015, + amenities: [ + "Gym", + "Rooftop Deck", + "Concierge", + "Pet Friendly", + "City Views", + ], + coordinates: { lat: 41.8781, lng: -87.6298 }, + }, + { + id: "6", + name: "Mixed-Use Development", + location: "Austin, TX", + type: "Mixed-Use", + value: 274520, + tokens: 549, + roi: 16.7, + monthlyIncome: 2020, + images: [ + "https://images.unsplash.com/photo-1512917774080-9991f1c4c750?w=800&auto=format&fit=crop&q=80", + "https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?w=800&auto=format&fit=crop&q=80", + ], + description: + "Innovative mixed-use development combining residential and commercial spaces in vibrant Austin.", + bedrooms: 3, + bathrooms: 2, + sqft: 2200, + yearBuilt: 2021, + amenities: [ + "Retail Space", + "Parking", + "Community Garden", + "Co-working Space", + "Event Space", + ], + coordinates: { lat: 30.2672, lng: -97.7431 }, + }, +]; + +export default function MobilePropertiesPage() { + const [activeTab, setActiveTab] = useState("browse"); + const [searchQuery, setSearchQuery] = useState(""); + const [viewMode, setViewMode] = useState<"grid" | "list">("grid"); + const [selectedProperty, setSelectedProperty] = useState(null); + const [showARPreview, setShowARPreview] = useState(false); + const [isOnline, setIsOnline] = useState(true); + + useEffect(() => { + // Set initial online status after component mounts + setIsOnline(navigator.onLine); + + const handleOnline = () => setIsOnline(true); + const handleOffline = () => setIsOnline(false); + + window.addEventListener("online", handleOnline); + window.addEventListener("offline", handleOffline); + + return () => { + window.removeEventListener("online", handleOnline); + window.removeEventListener("offline", handleOffline); + }; + }, []); + + const filteredProperties = properties.filter( + (property) => + property.name.toLowerCase().includes(searchQuery.toLowerCase()) || + property.location.toLowerCase().includes(searchQuery.toLowerCase()) || + property.type.toLowerCase().includes(searchQuery.toLowerCase()), + ); + + const handlePropertyView = (property: any) => { + setSelectedProperty(property); + }; + + const handleARPreview = (property: any) => { + setSelectedProperty(property); + setShowARPreview(true); + }; + + return ( +
+ {/* Header */} +
+
+
+
+
+ PC +
+
+

+ Mobile Properties +

+
+ {isOnline ? ( + + ) : ( + + )} + + {isOnline ? "Online" : "Offline"} + +
+
+
+ +
+ +
+
+ + {/* Search */} +
+ + setSearchQuery(e.target.value)} + className="pl-10" + /> +
+ + {/* Tabs */} + + + + + Browse + + + + Nearby + + + + AR View + + + + Offline + + + +
+
+ + {/* Content */} +
+ + {/* Browse Properties */} + +
+

+ {filteredProperties.length} properties found +

+
+ All Types + All Locations +
+
+ +
+ {filteredProperties.map((property, index) => ( +
+ + + {/* AR Button Overlay */} + +
+ ))} +
+
+ + {/* Location-Based Discovery */} + + + + + {/* AR Preview */} + +
+
+ +

+ AR Property Preview +

+

+ Select a property to view in augmented reality +

+
+ +
+ {properties.slice(0, 3).map((property) => ( +
handleARPreview(property)} + className="bg-white dark:bg-gray-800 rounded-lg p-4 cursor-pointer hover:shadow-md transition-shadow" + > +
+ {property.name} +
+

{property.name}

+

+ {property.location} +

+
+ +
+
+ ))} +
+
+
+ + {/* Offline Cache */} + + + +
+
+ + {/* AR Property Preview Modal */} + {selectedProperty && showARPreview && ( + { + setShowARPreview(false); + setSelectedProperty(null); + }} + /> + )} + + {/* Bottom Navigation Hint */} +
+
+
+
+ + Swipe for more + +
+
+
+
+ ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index a85b96ee..c20e2019 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,15 +1,27 @@ -'use client'; +"use client"; -import React, { useEffect } from 'react'; -import { ChainAwareProvider } from '@/providers/ChainAwareProvider'; -import { useWalletPersistence } from '@/utils/walletPersistence'; -import { setupExtensionErrorHandling } from '@/utils/extensionDetection'; -import { setupConsoleOverride, suppressExtensionErrors } from '@/utils/consoleOverride'; -import { ManualErrorSuppressor, globalErrorSuppressor } from '@/utils/manualErrorSuppressor'; -import { WalletConnector } from '@/components/WalletConnector'; -import { ChainAware, ChainSpecific, MultiChainBadge, GasEstimation, TransactionButton } from '@/components/ChainAwareProps'; -import { LoadingState } from '@/components/LoadingSpinner'; -import { ErrorBoundary } from '@/components/ErrorBoundary'; +import React, { useEffect } from "react"; +import { ChainAwareProvider } from "@/providers/ChainAwareProvider"; +import { useWalletPersistence } from "@/utils/walletPersistence"; +import { setupExtensionErrorHandling } from "@/utils/extensionDetection"; +import { + setupConsoleOverride, + suppressExtensionErrors, +} from "@/utils/consoleOverride"; +import { + ManualErrorSuppressor, + globalErrorSuppressor, +} from "@/utils/manualErrorSuppressor"; +import { WalletConnector } from "@/components/WalletConnector"; +import { + ChainAware, + ChainSpecific, + MultiChainBadge, + GasEstimation, + TransactionButton, +} from "@/components/ChainAwareProps"; +import { LoadingState } from "@/components/LoadingSpinner"; +import { ErrorBoundary } from "@/components/ErrorBoundary"; function HomeContent() { useWalletPersistence(); @@ -20,16 +32,16 @@ function HomeContent() { suppressExtensionErrors(); ManualErrorSuppressor(); globalErrorSuppressor(); - + // Make manual suppressor available globally (window as any).suppressErrors = () => { console.clear(); - console.log('🔧 Manual error suppression activated'); + console.log("🔧 Manual error suppression activated"); }; }, []); const handleSampleTransaction = async () => { - console.log('Sample transaction executed'); + console.log("Sample transaction executed"); }; return ( @@ -77,7 +89,8 @@ function HomeContent() { Connect Your Wallet

- Connect your Web3 wallet to access multi-chain real estate features + Connect your Web3 wallet to access multi-chain real estate + features

@@ -92,19 +105,25 @@ function HomeContent() {
-

Address

+

+ Address +

{address?.slice(0, 8)}...{address?.slice(-6)}

-

Balance

+

+ Balance +

{balance} {chainSymbol}

-

Network

+

+ Network +

{chainName} @@ -120,7 +139,9 @@ function HomeContent() {
- Ethereum Mainnet + + Ethereum Mainnet +

High security, extensive DeFi ecosystem @@ -175,7 +196,7 @@ function HomeContent() {

Multi-Chain Features

-
+
🔗

@@ -204,6 +225,26 @@ function HomeContent() {

+ + {/* Mobile Properties Link */} +
+
+

+ 📱 Mobile-First Property Experience +

+

+ Experience our touch-optimized property viewing with AR + preview, location discovery, and offline support +

+ + 📱 + View Mobile Properties + +
+
)} diff --git a/src/components/ClientProviders.tsx b/src/components/ClientProviders.tsx new file mode 100644 index 00000000..448cf798 --- /dev/null +++ b/src/components/ClientProviders.tsx @@ -0,0 +1,25 @@ +'use client'; + +import { WagmiProvider } from 'wagmi'; +import { config } from '@/config/wagmi'; +import { ChainAwareProvider } from '@/providers/ChainAwareProvider'; +import { TransactionMonitor } from '@/components/TransactionMonitor'; +import { NotificationSystem } from '@/components/NotificationSystem'; +import { Toaster } from '@/components/ui/sonner'; + +interface ClientProvidersProps { + children: React.ReactNode; +} + +export function ClientProviders({ children }: ClientProvidersProps) { + return ( + + + {children} + + + + + + ); +} \ No newline at end of file diff --git a/src/components/GasEstimator.tsx b/src/components/GasEstimator.tsx new file mode 100644 index 00000000..9373885b --- /dev/null +++ b/src/components/GasEstimator.tsx @@ -0,0 +1,83 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; +import { useEstimateGas, useGasPrice } from 'wagmi'; +import { formatEther } from 'viem'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Badge } from '@/components/ui/badge'; +import { Loader2 } from 'lucide-react'; + +interface GasEstimatorProps { + to?: string; + value?: string; + data?: string; + enabled?: boolean; +} + +export const GasEstimator: React.FC = ({ + to, + value, + data, + enabled = true, +}) => { + const [estimatedGas, setEstimatedGas] = useState(null); + const [estimatedCost, setEstimatedCost] = useState(null); + + const { data: gasPrice } = useGasPrice(); + const { data: gasEstimate } = useEstimateGas({ + to: to as `0x${string}`, + value: value ? BigInt(value) : undefined, + data: data as `0x${string}`, + }); + + useEffect(() => { + if (gasEstimate && gasPrice) { + const gasCost = gasEstimate * gasPrice; + setEstimatedGas(gasEstimate.toString()); + setEstimatedCost(formatEther(gasCost)); + } + }, [gasEstimate, gasPrice]); + + if (!enabled || !to) { + return null; + } + + const isLoading = !gasEstimate || !gasPrice; + + return ( + + + Gas Estimation + + + {isLoading ? ( +
+ + Estimating gas... +
+ ) : ( + <> +
+ Gas Limit: + {estimatedGas || 'N/A'} +
+
+ Estimated Cost: + + {estimatedCost ? `${parseFloat(estimatedCost).toFixed(6)} ETH` : 'N/A'} + +
+ {gasPrice && ( +
+ Gas Price: + + {formatEther(gasPrice)} ETH + +
+ )} + + )} +
+
+ ); +}; \ No newline at end of file diff --git a/src/components/NotificationSystem.tsx b/src/components/NotificationSystem.tsx new file mode 100644 index 00000000..6e643f68 --- /dev/null +++ b/src/components/NotificationSystem.tsx @@ -0,0 +1,93 @@ +'use client'; + +import React, { useEffect } from 'react'; +import { toast } from 'sonner'; +import { useTransactionStore, Transaction } from '@/store/transactionStore'; +import { CheckCircle, XCircle, AlertCircle, Clock } from 'lucide-react'; + +export const NotificationSystem: React.FC = () => { + const { transactions } = useTransactionStore(); + + useEffect(() => { + const handleTransactionUpdate = (transaction: Transaction) => { + const { status, type, hash, description } = transaction; + + const title = `${type.charAt(0).toUpperCase() + type.slice(1)} Transaction`; + const shortHash = `${hash.slice(0, 6)}...${hash.slice(-4)}`; + + switch (status) { + case 'confirmed': + toast.success(`${title} Confirmed`, { + description: `${description || 'Transaction'} ${shortHash} has been confirmed`, + icon: , + duration: 5000, + }); + + // Browser notification + if ('Notification' in window && Notification.permission === 'granted') { + new Notification(`${title} Confirmed`, { + body: `${description || 'Transaction'} ${shortHash} has been confirmed`, + icon: '/favicon.ico', + }); + } + break; + + case 'failed': + toast.error(`${title} Failed`, { + description: `${description || 'Transaction'} ${shortHash} has failed`, + icon: , + duration: 7000, + }); + + // Browser notification + if ('Notification' in window && Notification.permission === 'granted') { + new Notification(`${title} Failed`, { + body: `${description || 'Transaction'} ${shortHash} has failed`, + icon: '/favicon.ico', + }); + } + break; + + case 'processing': + toast.info(`${title} Processing`, { + description: `${description || 'Transaction'} ${shortHash} is being processed`, + icon: , + duration: 3000, + }); + break; + + case 'cancelled': + toast.warning(`${title} Cancelled`, { + description: `${description || 'Transaction'} ${shortHash} has been cancelled`, + icon: , + duration: 5000, + }); + break; + + default: + break; + } + }; + + // Request notification permission on mount + if ('Notification' in window && Notification.permission === 'default') { + Notification.requestPermission(); + } + + // Monitor transaction changes + transactions.forEach((transaction) => { + // This is a simplified approach. In a real app, you'd track previous states + // For now, we'll show notifications for all transactions with final states + if (transaction.status === 'confirmed' || transaction.status === 'failed' || transaction.status === 'cancelled') { + // Check if we haven't notified about this transaction yet + const notifiedKey = `notified_${transaction.id}`; + if (!localStorage.getItem(notifiedKey)) { + handleTransactionUpdate(transaction); + localStorage.setItem(notifiedKey, 'true'); + } + } + }); + }, [transactions]); + + return null; +}; \ No newline at end of file diff --git a/src/components/TransactionCard.tsx b/src/components/TransactionCard.tsx new file mode 100644 index 00000000..73009592 --- /dev/null +++ b/src/components/TransactionCard.tsx @@ -0,0 +1,184 @@ +'use client'; + +import React from 'react'; +import { formatDistanceToNow } from 'date-fns'; +import { Card, CardContent, CardHeader } from '@/components/ui/card'; +import { Badge } from '@/components/ui/badge'; +import { Progress } from '@/components/ui/progress'; +import { Button } from '@/components/ui/button'; +import { + CheckCircle, + Clock, + XCircle, + AlertCircle, + ExternalLink, + RotateCcw, + X, +} from 'lucide-react'; +import { Transaction, TransactionStatus } from '@/store/transactionStore'; +import { useChain } from '@/providers/ChainAwareProvider'; + +interface TransactionCardProps { + transaction: Transaction; + onRetry?: (transaction: Transaction) => void; + onCancel?: (transaction: Transaction) => void; +} + +const statusConfig = { + pending: { + icon: Clock, + color: 'text-yellow-500', + bgColor: 'bg-yellow-50', + borderColor: 'border-yellow-200', + }, + processing: { + icon: AlertCircle, + color: 'text-blue-500', + bgColor: 'bg-blue-50', + borderColor: 'border-blue-200', + }, + confirmed: { + icon: CheckCircle, + color: 'text-green-500', + bgColor: 'bg-green-50', + borderColor: 'border-green-200', + }, + failed: { + icon: XCircle, + color: 'text-red-500', + bgColor: 'bg-red-50', + borderColor: 'border-red-200', + }, + cancelled: { + icon: X, + color: 'text-gray-500', + bgColor: 'bg-gray-50', + borderColor: 'border-gray-200', + }, +}; + +export const TransactionCard: React.FC = ({ + transaction, + onRetry, + onCancel, +}) => { + const { getChainName, chainConfig } = useChain(); + const statusInfo = statusConfig[transaction.status]; + const StatusIcon = statusInfo.icon; + + const progress = transaction.requiredConfirmations + ? (transaction.confirmations / transaction.requiredConfirmations) * 100 + : transaction.status === 'confirmed' + ? 100 + : 0; + + const handleViewOnExplorer = () => { + const explorerUrl = `${chainConfig.blockExplorer}/tx/${transaction.hash}`; + window.open(explorerUrl, '_blank'); + }; + + return ( + + +
+
+ + {transaction.type} + + {getChainName(transaction.chainId)} + +
+ + {formatDistanceToNow(new Date(transaction.timestamp), { addSuffix: true })} + +
+
+ +
+
+ Transaction Hash: + + {transaction.hash.slice(0, 10)}...{transaction.hash.slice(-8)} + +
+ + {transaction.description && ( +
+ Description: + {transaction.description} +
+ )} + + {transaction.value && ( +
+ Value: + {transaction.value} ETH +
+ )} + + {transaction.gasUsed && ( +
+ Gas Used: + {transaction.gasUsed} +
+ )} +
+ + {(transaction.status === 'pending' || transaction.status === 'processing') && ( +
+
+ Confirmations + + {transaction.confirmations}/{transaction.requiredConfirmations || 1} + +
+ +
+ )} + + {transaction.error && ( +
+ {transaction.error} +
+ )} + +
+ + + {transaction.status === 'failed' && onRetry && ( + + )} + + {(transaction.status === 'pending' || transaction.status === 'processing') && + onCancel && ( + + )} +
+
+
+ ); +}; \ No newline at end of file diff --git a/src/components/TransactionHistory.tsx b/src/components/TransactionHistory.tsx new file mode 100644 index 00000000..134cc1c4 --- /dev/null +++ b/src/components/TransactionHistory.tsx @@ -0,0 +1,145 @@ +'use client'; + +import React, { useState, useMemo } from 'react'; +import { format } from 'date-fns'; +import { useTransactionStore, TransactionType, TransactionStatus } from '@/store/transactionStore'; +import { TransactionCard } from './TransactionCard'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Input } from '@/components/ui/input'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; +import { Search, Filter, Download } from 'lucide-react'; +import { toast } from 'sonner'; + +export const TransactionHistory: React.FC = () => { + const { transactions, getTransactionsByType, getTransactionsByStatus } = useTransactionStore(); + + const [searchTerm, setSearchTerm] = useState(''); + const [typeFilter, setTypeFilter] = useState('all'); + const [statusFilter, setStatusFilter] = useState('all'); + + const filteredTransactions = useMemo(() => { + let filtered = transactions; + + if (typeFilter !== 'all') { + filtered = getTransactionsByType(typeFilter); + } + + if (statusFilter !== 'all') { + filtered = filtered.filter(tx => tx.status === statusFilter); + } + + if (searchTerm) { + filtered = filtered.filter(tx => + tx.hash.toLowerCase().includes(searchTerm.toLowerCase()) || + tx.description?.toLowerCase().includes(searchTerm.toLowerCase()) || + tx.from.toLowerCase().includes(searchTerm.toLowerCase()) || + tx.to?.toLowerCase().includes(searchTerm.toLowerCase()) + ); + } + + return filtered.sort((a, b) => b.timestamp - a.timestamp); + }, [transactions, typeFilter, statusFilter, searchTerm, getTransactionsByType]); + + const handleExport = () => { + // Implement export functionality + toast.info('Export functionality not yet implemented'); + }; + + const handleRetry = async (transaction: any) => { + // Implement retry logic + toast.info('Retry functionality not yet implemented'); + }; + + return ( + + +
+ + Transaction History + {filteredTransactions.length} + + +
+
+ + {/* Filters */} +
+
+ + setSearchTerm(e.target.value)} + className="pl-10" + /> +
+ + + + +
+ + {/* Transaction List */} +
+ {filteredTransactions.length === 0 ? ( +
+ {searchTerm || typeFilter !== 'all' || statusFilter !== 'all' + ? 'No transactions match your filters' + : 'No transactions found' + } +
+ ) : ( + filteredTransactions.map((transaction) => ( + + )) + )} +
+ + {/* Summary */} + {filteredTransactions.length > 0 && ( +
+
+ Total Transactions: {filteredTransactions.length} + + Confirmed: {filteredTransactions.filter(tx => tx.status === 'confirmed').length} | + Failed: {filteredTransactions.filter(tx => tx.status === 'failed').length} + +
+
+ )} +
+
+ ); +}; \ No newline at end of file diff --git a/src/components/TransactionMonitor.tsx b/src/components/TransactionMonitor.tsx new file mode 100644 index 00000000..d0f1ac40 --- /dev/null +++ b/src/components/TransactionMonitor.tsx @@ -0,0 +1,39 @@ +'use client'; + +import React from 'react'; +import { useTransactionStore } from '@/store/transactionStore'; + +const TransactionWatcher = ({ transaction }: { transaction: any }) => { + const { updateTransaction } = useTransactionStore(); + + // For demo purposes, we'll simulate transaction monitoring + // In a real app, you'd use wagmi's useWaitForTransactionReceipt here + React.useEffect(() => { + if (transaction.status === 'pending') { + // Simulate confirmation after 5 seconds for demo + const timer = setTimeout(() => { + updateTransaction(transaction.id, { + status: 'confirmed', + gasUsed: '21000', + confirmations: 1, + }); + }, 5000); + + return () => clearTimeout(timer); + } + }, [transaction.id, transaction.status, updateTransaction]); + + return null; +}; + +export const TransactionMonitor = () => { + const { pendingTransactions } = useTransactionStore(); + + return ( + <> + {pendingTransactions.map((transaction) => ( + + ))} + + ); +}; \ No newline at end of file diff --git a/src/components/TransactionQueue.tsx b/src/components/TransactionQueue.tsx new file mode 100644 index 00000000..a7f989fc --- /dev/null +++ b/src/components/TransactionQueue.tsx @@ -0,0 +1,116 @@ +'use client'; + +import React, { useState } from 'react'; +import { useTransactionStore, Transaction } from '@/store/transactionStore'; +import { TransactionCard } from './TransactionCard'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { RefreshCw, Filter } from 'lucide-react'; +import { toast } from 'sonner'; + +export const TransactionQueue: React.FC = () => { + const { + pendingTransactions, + recentTransactions, + isLoading, + setLoading, + } = useTransactionStore(); + + const [activeTab, setActiveTab] = useState('pending'); + + const handleRetry = async (transaction: Transaction) => { + // Implement retry logic here + toast.info('Retry functionality not yet implemented'); + }; + + const handleCancel = async (transaction: Transaction) => { + // Implement cancel logic here + toast.info('Cancel functionality not yet implemented'); + }; + + const handleRefresh = () => { + setLoading(true); + // Implement refresh logic here + setTimeout(() => setLoading(false), 1000); + }; + + return ( + + +
+ + Transaction Queue + + {pendingTransactions.length + recentTransactions.length} + + + +
+
+ + + + + Pending + {pendingTransactions.length > 0 && ( + + {pendingTransactions.length} + + )} + + + Recent + {recentTransactions.length > 0 && ( + + {recentTransactions.length} + + )} + + + + + {pendingTransactions.length === 0 ? ( +
+ No pending transactions +
+ ) : ( + pendingTransactions.map((transaction) => ( + + )) + )} +
+ + + {recentTransactions.length === 0 ? ( +
+ No recent transactions +
+ ) : ( + recentTransactions.map((transaction) => ( + + )) + )} +
+
+
+
+ ); +}; \ No newline at end of file diff --git a/src/components/WalletConnector.tsx b/src/components/WalletConnector.tsx index 6c3115cc..688d714a 100644 --- a/src/components/WalletConnector.tsx +++ b/src/components/WalletConnector.tsx @@ -92,7 +92,7 @@ export const WalletConnector: React.FC = () => { } return ( -
+
+
+ + {/* Status Notifications */} + + {refreshState === "success" && ( + + + Data refreshed successfully + + )} + + {refreshState === "error" && ( + + + {error} + + + )} + + + {/* Loading Overlay */} + + {refreshState === "loading" && ( + +
+
+
+
+
+

Fetching latest data...

+
+ + )} + + + {/* Content */} +
+ {children} +
+
+ ); +}; + +// Skeleton components for loading states +export const MetricCardSkeleton = () => ( +
+
+
+
+
+
+
+
+
+
+); + +export const ChartSkeleton = () => ( +
+
+
+
+
+ {[1, 2, 3, 4].map((i) => ( +
+ ))} +
+
+
+
+
+); + +export const TableSkeleton = () => ( +
+
+ {[1, 2, 3, 4, 5].map((i) => ( +
+
+
+
+
+ ))} +
+); \ No newline at end of file diff --git a/src/components/dashboard/DiversificationChart.tsx b/src/components/dashboard/DiversificationChart.tsx new file mode 100644 index 00000000..ee7567e2 --- /dev/null +++ b/src/components/dashboard/DiversificationChart.tsx @@ -0,0 +1,98 @@ +'use client'; + +import { motion } from "framer-motion"; +import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from "recharts"; + +const propertyTypeData = [ + { name: "Residential", value: 45, color: "hsl(160, 84%, 39%)" }, + { name: "Commercial", value: 30, color: "hsl(199, 89%, 48%)" }, + { name: "Industrial", value: 15, color: "hsl(38, 92%, 50%)" }, + { name: "Mixed-Use", value: 10, color: "hsl(280, 65%, 60%)" }, +]; + +const geographicData = [ + { name: "North America", value: 50, color: "hsl(160, 84%, 39%)" }, + { name: "Europe", value: 25, color: "hsl(199, 89%, 48%)" }, + { name: "Asia Pacific", value: 15, color: "hsl(38, 92%, 50%)" }, + { name: "Other", value: 10, color: "hsl(280, 65%, 60%)" }, +]; + +const CustomTooltip = ({ active, payload }: any) => { + if (active && payload && payload.length) { + return ( +
+

{payload[0].name}

+

+ {payload[0].value}% +

+
+ ); + } + return null; +}; + +interface DiversificationPieProps { + data: typeof propertyTypeData; + title: string; +} + +const DiversificationPie = ({ data, title }: DiversificationPieProps) => { + return ( +
+

{title}

+
+ + + + {data.map((entry, index) => ( + + ))} + + } /> + + +
+
+ {data.map((item) => ( +
+
+ {item.name} +
+ ))} +
+
+ ); +}; + +export const DiversificationChart = () => { + return ( + +
+

Portfolio Diversification

+

Asset allocation breakdown

+
+ +
+ +
+ +
+ + ); +}; diff --git a/src/components/dashboard/Header.tsx b/src/components/dashboard/Header.tsx new file mode 100644 index 00000000..d0804f00 --- /dev/null +++ b/src/components/dashboard/Header.tsx @@ -0,0 +1,76 @@ +// 'use client'; + +// import { motion } from "framer-motion"; +// import { Bell, Search, Wallet, ChevronDown, Menu } from "lucide-react"; + +// interface HeaderProps { +// onMenuToggle?: () => void; +// } + +// export const Header = ({ onMenuToggle }: HeaderProps) => { +// return ( +// +//
+// {/* Left section */} +//
+// + +//
+//
+// M +//
+//
+//

MettaChain

+//

PropChain Analytics

+//
+//
+//
+ +// {/* Search bar - hidden on mobile */} +//
+//
+// +// +//
+//
+ +// {/* Right section */} +//
+// + +//
+//
+// +//
+//
+//

Connected

+//

0x7a3...8f2d

+//
+// +//
+ +//
+// JD +//
+//
+//
+//
+// ); +// }; diff --git a/src/components/dashboard/IncomeTracker.tsx b/src/components/dashboard/IncomeTracker.tsx new file mode 100644 index 00000000..e8da579c --- /dev/null +++ b/src/components/dashboard/IncomeTracker.tsx @@ -0,0 +1,158 @@ +"use client"; + +import { motion } from "framer-motion"; +import { + BarChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, +} from "recharts"; +import { TrendingUp, DollarSign } from "lucide-react"; + +const incomeData = [ + { month: "Aug", income: 15200, projected: 16000 }, + { month: "Sep", income: 16800, projected: 16500 }, + { month: "Oct", income: 17500, projected: 17000 }, + { month: "Nov", income: 16200, projected: 17500 }, + { month: "Dec", income: 18900, projected: 18000 }, + { month: "Jan", income: 18240, projected: 18500 }, +]; + +const CustomTooltip = ({ active, payload, label }: any) => { + if (active && payload && payload.length) { + return ( +
+

{label}

+
+

+ Actual: + + ${payload[0].value.toLocaleString()} + +

+

+ Projected: + + ${payload[1]?.value?.toLocaleString()} + +

+
+
+ ); + } + return null; +}; + +export const IncomeTracker = () => { + const totalIncome = incomeData.reduce((sum, d) => sum + d.income, 0); + const averageIncome = Math.round(totalIncome / incomeData.length); + const latestIncome = incomeData[incomeData.length - 1].income; + const previousIncome = incomeData[incomeData.length - 2].income; + const changePercent = ( + ((latestIncome - previousIncome) / previousIncome) * + 100 + ).toFixed(1); + + return ( + +
+
+

Rental Income

+

+ Monthly income from all properties +

+
+
+
+

This Month

+

+ ${latestIncome.toLocaleString()} +

+
+ +{changePercent}% +
+
+
+
+

6-Mo Average

+

+ ${averageIncome.toLocaleString()} +

+
+ + per month +
+
+
+
+ +
+ + + + + `$${(value / 1000).toFixed(0)}k`} + /> + } + cursor={{ fill: "hsl(222, 30%, 16%, 0.5)" }} + /> + + + + +
+ +
+
+
+ Actual Income +
+
+
+ Projected +
+
+ + ); +}; diff --git a/src/components/dashboard/PerformanceChart.tsx b/src/components/dashboard/PerformanceChart.tsx new file mode 100644 index 00000000..975aab00 --- /dev/null +++ b/src/components/dashboard/PerformanceChart.tsx @@ -0,0 +1,176 @@ +"use client"; + +import { useState } from "react"; +import { motion } from "framer-motion"; +import { + AreaChart, + Area, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, +} from "recharts"; + +const generateData = (months: number) => { + const data = []; + let value = 2000000; + const now = new Date(); + + for (let i = months; i >= 0; i--) { + const date = new Date(now); + date.setMonth(date.getMonth() - i); + + // Add some realistic variation + const change = (Math.random() - 0.4) * 100000; + value = Math.max(value + change, 1500000); + + data.push({ + date: date.toLocaleDateString("en-US", { + month: "short", + year: "2-digit", + }), + value: Math.round(value), + projected: Math.round(value * 1.08), + }); + } + return data; +}; + +const timeframes = [ + { label: "1M", months: 1 }, + { label: "3M", months: 3 }, + { label: "6M", months: 6 }, + { label: "1Y", months: 12 }, + { label: "All", months: 24 }, +]; + +const CustomTooltip = ({ active, payload, label }: any) => { + if (active && payload && payload.length) { + return ( +
+

{label}

+

+ ${payload[0].value.toLocaleString()} +

+

+ Projected: ${payload[1]?.value?.toLocaleString()} +

+
+ ); + } + return null; +}; + +export const PerformanceChart = () => { + const [activeTimeframe, setActiveTimeframe] = useState("1Y"); + const selectedTimeframe = timeframes.find((t) => t.label === activeTimeframe); + const data = generateData(selectedTimeframe?.months || 12); + + return ( + +
+
+

Portfolio Performance

+

+ Track your investment growth over time +

+
+
+ {timeframes.map((tf) => ( + + ))} +
+
+ +
+ + + + + + + + + + + + + + + `$${(value / 1000000).toFixed(1)}M`} + dx={-10} + /> + } /> + + + + +
+ +
+
+
+ Actual Value +
+
+
+ Projected +
+
+ + ); +}; diff --git a/src/components/dashboard/PortfolioOverview.tsx b/src/components/dashboard/PortfolioOverview.tsx new file mode 100644 index 00000000..3da66cb4 --- /dev/null +++ b/src/components/dashboard/PortfolioOverview.tsx @@ -0,0 +1,93 @@ +'use client'; + +import { motion } from "framer-motion"; +import { TrendingUp, TrendingDown, Wallet, Building2, DollarSign, Percent } from "lucide-react"; + +interface MetricCardProps { + title: string; + value: string; + change?: string; + changeType?: "positive" | "negative" | "neutral"; + icon: React.ReactNode; + delay?: number; +} + +const MetricCard = ({ title, value, change, changeType = "neutral", icon, delay = 0 }: MetricCardProps) => { + return ( + +
+
+

{title}

+

{value}

+ {change && ( +
+ {changeType === "positive" ? ( + + ) : changeType === "negative" ? ( + + ) : null} + {change} +
+ )} +
+
+ {icon} +
+
+
+ ); +}; + +export const PortfolioOverview = () => { + const metrics = [ + { + title: "Total Portfolio Value", + value: "$2,847,520", + change: "+12.5% this month", + changeType: "positive" as const, + icon: , + }, + { + title: "Total Properties", + value: "12", + change: "+2 this quarter", + changeType: "positive" as const, + icon: , + }, + { + title: "Annual Yield", + value: "8.4%", + change: "+0.6% vs last year", + changeType: "positive" as const, + icon: , + }, + { + title: "Monthly Income", + value: "$18,240", + change: "-2.1% vs last month", + changeType: "negative" as const, + icon: , + }, + ]; + + return ( +
+ {metrics.map((metric, index) => ( + + ))} +
+ ); +}; diff --git a/src/components/dashboard/PortfolioReport.tsx b/src/components/dashboard/PortfolioReport.tsx new file mode 100644 index 00000000..67eae1bd --- /dev/null +++ b/src/components/dashboard/PortfolioReport.tsx @@ -0,0 +1,255 @@ +import { useState } from "react"; +import { motion } from "framer-motion"; +import { FileText, Download, Calendar, Loader2, CheckCircle } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import jsPDF from "jspdf"; +import autoTable from "jspdf-autotable"; + +interface ReportData { + portfolioValue: number; + totalProperties: number; + annualYield: number; + monthlyIncome: number; + properties: { + name: string; + type: string; + value: number; + tokens: number; + roi: number; + monthlyIncome: number; + }[]; + transactions: { + date: string; + type: string; + property: string; + amount: number; + }[]; +} + +const mockReportData: ReportData = { + portfolioValue: 2847520, + totalProperties: 12, + annualYield: 8.4, + monthlyIncome: 18240, + properties: [ + { name: "Manhattan Luxury Condo", type: "Residential", value: 850000, tokens: 1200, roi: 12.5, monthlyIncome: 4200 }, + { name: "Miami Beach Resort", type: "Commercial", value: 620000, tokens: 800, roi: 9.8, monthlyIncome: 3100 }, + { name: "Austin Tech Hub Office", type: "Commercial", value: 480000, tokens: 600, roi: 11.2, monthlyIncome: 2800 }, + { name: "Denver Mixed-Use Complex", type: "Mixed-Use", value: 420000, tokens: 500, roi: 8.7, monthlyIncome: 2400 }, + { name: "Seattle Waterfront", type: "Residential", value: 380000, tokens: 450, roi: 7.9, monthlyIncome: 2100 }, + { name: "Chicago Industrial", type: "Industrial", value: 97520, tokens: 150, roi: 6.5, monthlyIncome: 1640 }, + ], + transactions: [ + { date: "2024-01-15", type: "Dividend", property: "Manhattan Luxury Condo", amount: 4200 }, + { date: "2024-01-12", type: "Purchase", property: "Seattle Waterfront", amount: -25000 }, + { date: "2024-01-10", type: "Dividend", property: "Miami Beach Resort", amount: 3100 }, + { date: "2024-01-08", type: "Sale", property: "Portland Retail", amount: 15000 }, + { date: "2024-01-05", type: "Dividend", property: "Austin Tech Hub", amount: 2800 }, + ], +}; + +export const PortfolioReport = () => { + const [reportType, setReportType] = useState("full"); + const [year, setYear] = useState("2024"); + const [isGenerating, setIsGenerating] = useState(false); + const [isGenerated, setIsGenerated] = useState(false); + + const generatePDF = async () => { + setIsGenerating(true); + setIsGenerated(false); + + // Simulate processing time + await new Promise((resolve) => setTimeout(resolve, 1500)); + + const doc = new jsPDF(); + const data = mockReportData; + + // Header + doc.setFillColor(16, 185, 129); // Emerald + doc.rect(0, 0, 210, 40, "F"); + doc.setTextColor(255, 255, 255); + doc.setFontSize(24); + doc.text("MettaChain Portfolio Report", 20, 25); + doc.setFontSize(10); + doc.text(`Generated: ${new Date().toLocaleDateString()}`, 20, 35); + + // Reset text color + doc.setTextColor(0, 0, 0); + + // Portfolio Summary + doc.setFontSize(16); + doc.text("Portfolio Summary", 20, 55); + doc.setFontSize(10); + doc.text(`Total Portfolio Value: $${data.portfolioValue.toLocaleString()}`, 20, 65); + doc.text(`Total Properties: ${data.totalProperties}`, 20, 72); + doc.text(`Annual Yield: ${data.annualYield}%`, 20, 79); + doc.text(`Monthly Income: $${data.monthlyIncome.toLocaleString()}`, 20, 86); + + // Properties Table + doc.setFontSize(16); + doc.text("Property Holdings", 20, 100); + + autoTable(doc, { + startY: 105, + head: [["Property", "Type", "Value", "Tokens", "ROI", "Monthly Income"]], + body: data.properties.map((p) => [ + p.name, + p.type, + `$${p.value.toLocaleString()}`, + p.tokens.toString(), + `${p.roi}%`, + `$${p.monthlyIncome.toLocaleString()}`, + ]), + theme: "striped", + headStyles: { fillColor: [16, 185, 129] }, + }); + + // Transactions Table + const finalY = (doc as any).lastAutoTable.finalY || 105; + doc.setFontSize(16); + doc.text("Recent Transactions", 20, finalY + 15); + + autoTable(doc, { + startY: finalY + 20, + head: [["Date", "Type", "Property", "Amount"]], + body: data.transactions.map((t) => [ + t.date, + t.type, + t.property, + `${t.amount >= 0 ? "+" : ""}$${t.amount.toLocaleString()}`, + ]), + theme: "striped", + headStyles: { fillColor: [16, 185, 129] }, + }); + + // Tax Summary (if full report) + if (reportType === "full" || reportType === "tax") { + doc.addPage(); + doc.setFillColor(16, 185, 129); + doc.rect(0, 0, 210, 30, "F"); + doc.setTextColor(255, 255, 255); + doc.setFontSize(20); + doc.text("Tax Summary", 20, 20); + + doc.setTextColor(0, 0, 0); + doc.setFontSize(12); + doc.text(`Tax Year: ${year}`, 20, 45); + doc.text("Total Rental Income: $218,880", 20, 55); + doc.text("Capital Gains: $45,230", 20, 65); + doc.text("Estimated Tax Liability: $52,822", 20, 75); + doc.text("Cost Basis: $2,547,290", 20, 85); + + doc.setFontSize(10); + doc.setTextColor(100, 100, 100); + doc.text("Note: This is an estimate. Consult a tax professional for accurate calculations.", 20, 100); + } + + // Footer + const pageCount = (doc as any).internal.getNumberOfPages(); + for (let i = 1; i <= pageCount; i++) { + doc.setPage(i); + doc.setFontSize(8); + doc.setTextColor(150, 150, 150); + doc.text(`Page ${i} of ${pageCount} | MettaChain Portfolio Report`, 105, 290, { align: "center" }); + } + + doc.save(`mettachain-portfolio-report-${year}.pdf`); + setIsGenerating(false); + setIsGenerated(true); + + setTimeout(() => setIsGenerated(false), 3000); + }; + + return ( + +
+
+

Export Reports

+

Generate PDF reports for tax and analysis

+
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+ +
+
+ +
+ {[ + { label: "Full Report", icon: FileText, desc: "Complete portfolio overview" }, + { label: "Tax Summary", icon: Calendar, desc: "IRS-ready tax documents" }, + { label: "Performance", icon: Calendar, desc: "ROI and yield analysis" }, + { label: "Transactions", icon: Calendar, desc: "Detailed activity log" }, + ].map((item, index) => ( +
setReportType(item.label.toLowerCase().replace(" ", ""))} + > + +

{item.label}

+

{item.desc}

+
+ ))} +
+
+ ); +}; \ No newline at end of file diff --git a/src/components/dashboard/PropertiesList.tsx b/src/components/dashboard/PropertiesList.tsx new file mode 100644 index 00000000..b7970a45 --- /dev/null +++ b/src/components/dashboard/PropertiesList.tsx @@ -0,0 +1,99 @@ +'use client'; + +import { motion } from "framer-motion"; +import { PropertyCard } from "./PropertyCard"; + +const properties = [ + { + id: "1", + name: "Manhattan Tower Suite", + location: "New York, NY", + type: "Commercial", + value: 524000, + tokens: 1048, + roi: 14.2, + monthlyIncome: 3280, + image: "https://images.unsplash.com/photo-1486325212027-8081e485255e?w=800&auto=format&fit=crop&q=80", + }, + { + id: "2", + name: "Sunset Beach Villa", + location: "Miami, FL", + type: "Residential", + value: 389000, + tokens: 778, + roi: 11.8, + monthlyIncome: 2450, + image: "https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?w=800&auto=format&fit=crop&q=80", + }, + { + id: "3", + name: "Tech Hub Office Complex", + location: "San Francisco, CA", + type: "Commercial", + value: 892000, + tokens: 1784, + roi: 9.5, + monthlyIncome: 5620, + image: "https://images.unsplash.com/photo-1497366216548-37526070297c?w=800&auto=format&fit=crop&q=80", + }, + { + id: "4", + name: "Industrial Logistics Park", + location: "Dallas, TX", + type: "Industrial", + value: 456000, + tokens: 912, + roi: 8.3, + monthlyIncome: 2890, + image: "https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=800&auto=format&fit=crop&q=80", + }, + { + id: "5", + name: "Downtown Luxury Lofts", + location: "Chicago, IL", + type: "Residential", + value: 312000, + tokens: 624, + roi: -2.1, + monthlyIncome: 1980, + image: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800&auto=format&fit=crop&q=80", + }, + { + id: "6", + name: "Mixed-Use Development", + location: "Austin, TX", + type: "Mixed-Use", + value: 274520, + tokens: 549, + roi: 16.7, + monthlyIncome: 2020, + image: "https://images.unsplash.com/photo-1512917774080-9991f1c4c750?w=800&auto=format&fit=crop&q=80", + }, +]; + +export const PropertiesList = () => { + return ( + +
+
+

Your Properties

+

Tokenized real estate holdings

+
+ +
+ +
+ {properties.map((property, index) => ( + + ))} +
+
+ ); +}; diff --git a/src/components/dashboard/PropertyCard.tsx b/src/components/dashboard/PropertyCard.tsx new file mode 100644 index 00000000..0aae24c2 --- /dev/null +++ b/src/components/dashboard/PropertyCard.tsx @@ -0,0 +1,139 @@ +'use client'; + +import { motion } from "framer-motion"; +import { MapPin, TrendingUp, TrendingDown, Building2, ShoppingCart } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { useTransaction } from "@/hooks/useTransaction"; +import { GasEstimator } from "@/components/GasEstimator"; +import { useState } from "react"; + +interface Property { + id: string; + name: string; + location: string; + type: string; + value: number; + tokens: number; + roi: number; + monthlyIncome: number; + image: string; +} + +interface PropertyCardProps { + property: Property; + index: number; +} + +export const PropertyCard = ({ property, index }: PropertyCardProps) => { + const { addTransactionToQueue } = useTransaction(); + const [showGasEstimator, setShowGasEstimator] = useState(false); + const isPositiveROI = property.roi >= 0; + + const handlePurchase = () => { + // Simulate a transaction hash for demo purposes + const mockTxHash = `0x${Math.random().toString(16).substr(2, 64)}`; + + addTransactionToQueue({ + hash: mockTxHash, + type: 'purchase', + description: `Purchase tokens for ${property.name}`, + propertyId: property.id, + value: (property.value * 0.1).toString(), // 10% purchase for demo + requiredConfirmations: 2, + }); + }; + + return ( + +
+ {property.name} +
+
+ + + {property.type} + +
+
+ +
+
+

+ {property.name} +

+
+ + {property.location} +
+
+ +
+
+

Value

+

+ ${property.value.toLocaleString()} +

+
+
+

Tokens Held

+

+ {property.tokens.toLocaleString()} +

+
+
+

ROI

+
+ {isPositiveROI ? ( + + ) : ( + + )} + {isPositiveROI ? "+" : ""}{property.roi}% +
+
+
+

Monthly Income

+

+ ${property.monthlyIncome.toLocaleString()} +

+
+
+ +
+ + + {showGasEstimator && ( + + )} + + +
+
+ + ); +}; diff --git a/src/components/dashboard/RecentTransactions.tsx b/src/components/dashboard/RecentTransactions.tsx new file mode 100644 index 00000000..67b8f9b1 --- /dev/null +++ b/src/components/dashboard/RecentTransactions.tsx @@ -0,0 +1,180 @@ +'use client'; + +import { motion } from "framer-motion"; +import { ArrowUpRight, ArrowDownLeft, Clock, ExternalLink } from "lucide-react"; + +interface Transaction { + id: string; + type: "buy" | "sell" | "income"; + property: string; + amount: number; + tokens?: number; + date: string; + status: "completed" | "pending"; + txHash: string; +} + +const transactions: Transaction[] = [ + { + id: "1", + type: "income", + property: "Manhattan Tower Suite", + amount: 3280, + date: "2024-01-20", + status: "completed", + txHash: "0x1a2b...3c4d", + }, + { + id: "2", + type: "buy", + property: "Tech Hub Office Complex", + amount: 45000, + tokens: 90, + date: "2024-01-18", + status: "completed", + txHash: "0x5e6f...7g8h", + }, + { + id: "3", + type: "sell", + property: "Downtown Luxury Lofts", + amount: 12500, + tokens: 25, + date: "2024-01-15", + status: "completed", + txHash: "0x9i0j...1k2l", + }, + { + id: "4", + type: "income", + property: "Sunset Beach Villa", + amount: 2450, + date: "2024-01-12", + status: "pending", + txHash: "0x3m4n...5o6p", + }, + { + id: "5", + type: "buy", + property: "Mixed-Use Development", + amount: 27500, + tokens: 55, + date: "2024-01-10", + status: "completed", + txHash: "0x7q8r...9s0t", + }, +]; + +const TransactionRow = ({ transaction, index }: { transaction: Transaction; index: number }) => { + const getTypeIcon = () => { + switch (transaction.type) { + case "buy": + return ; + case "sell": + return ; + case "income": + return ; + } + }; + + const getTypeColor = () => { + switch (transaction.type) { + case "buy": + return "bg-accent/10 text-accent"; + case "sell": + return "bg-warning/10 text-warning"; + case "income": + return "bg-success/10 text-success"; + } + }; + + const getTypeLabel = () => { + switch (transaction.type) { + case "buy": + return "Purchase"; + case "sell": + return "Sale"; + case "income": + return "Rental Income"; + } + }; + + return ( + +
+
+ {getTypeIcon()} +
+
+

{transaction.property}

+

{getTypeLabel()}

+
+
+ +
+
+

+ {transaction.type === "sell" ? "-" : "+"}${transaction.amount.toLocaleString()} +

+ {transaction.tokens && ( +

{transaction.tokens} tokens

+ )} +
+ +
+
+ + {new Date(transaction.date).toLocaleDateString('en-US', { + month: 'short', + day: 'numeric' + })} +
+ + {transaction.status === "completed" ? "✓ Completed" : "⏳ Pending"} + +
+ + +
+
+ ); +}; + +export const RecentTransactions = () => { + return ( + +
+
+

Recent Activity

+

Latest transactions and income

+
+ +
+ +
+ {transactions.map((transaction, index) => ( + + ))} +
+
+ ); +}; diff --git a/src/components/dashboard/RiskAnalysis.tsx b/src/components/dashboard/RiskAnalysis.tsx new file mode 100644 index 00000000..ba65a6fd --- /dev/null +++ b/src/components/dashboard/RiskAnalysis.tsx @@ -0,0 +1,193 @@ +import { motion } from "framer-motion"; +import { AlertTriangle, Shield, TrendingUp, PieChart, Info } from "lucide-react"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; + +interface RiskMetric { + label: string; + value: number; + maxValue: number; + status: "low" | "medium" | "high"; + description: string; +} + +const RiskMeter = ({ metric }: { metric: RiskMetric }) => { + const percentage = (metric.value / metric.maxValue) * 100; + const statusColors = { + low: "bg-success", + medium: "bg-warning", + high: "bg-destructive", + }; + const statusTextColors = { + low: "text-success", + medium: "text-warning", + high: "text-destructive", + }; + + return ( +
+
+
+ {metric.label} + + + + + + +

{metric.description}

+
+
+
+
+ + {metric.value.toFixed(1)}% + +
+
+ +
+
+ ); +}; + +const ConcentrationItem = ({ name, percentage, color }: { name: string; percentage: number; color: string }) => ( +
+
+
+ {name} +
+ {percentage}% +
+); + +export const RiskAnalysis = () => { + const riskMetrics: RiskMetric[] = [ + { + label: "Portfolio Volatility", + value: 12.4, + maxValue: 50, + status: "low", + description: "Measures how much your portfolio value fluctuates. Lower is generally better for stable investments.", + }, + { + label: "Concentration Risk", + value: 34.2, + maxValue: 100, + status: "medium", + description: "Indicates how much of your portfolio is concentrated in a few assets. High concentration increases risk.", + }, + { + label: "Liquidity Risk", + value: 18.5, + maxValue: 100, + status: "low", + description: "Measures how easily you can sell your assets without significant price impact.", + }, + { + label: "Market Correlation", + value: 45.8, + maxValue: 100, + status: "medium", + description: "Shows how closely your portfolio moves with the overall real estate market.", + }, + ]; + + const concentrationData = [ + { name: "Manhattan Luxury", percentage: 28, color: "bg-primary" }, + { name: "Miami Beach Resort", percentage: 22, color: "bg-accent" }, + { name: "Austin Tech Hub", percentage: 18, color: "bg-chart-3" }, + { name: "Denver Mixed-Use", percentage: 15, color: "bg-chart-4" }, + { name: "Others", percentage: 17, color: "bg-muted-foreground" }, + ]; + + const overallRiskScore = 32; + const getRiskLevel = (score: number) => { + if (score < 30) return { level: "Low", color: "text-success", bgColor: "bg-success/10" }; + if (score < 60) return { level: "Medium", color: "text-warning", bgColor: "bg-warning/10" }; + return { level: "High", color: "text-destructive", bgColor: "bg-destructive/10" }; + }; + const riskLevel = getRiskLevel(overallRiskScore); + + return ( + +
+
+

Risk Analysis

+

Portfolio risk metrics and concentration

+
+
+ + + {riskLevel.level} Risk + +
+
+ +
+ {/* Risk Metrics */} +
+
+ +

Risk Metrics

+
+ {riskMetrics.map((metric, index) => ( + + ))} +
+ + {/* Concentration Analysis */} +
+
+ +

Top Holdings Concentration

+
+
+ {concentrationData.map((item, index) => ( + + ))} +
+
+
+ +
+

Concentration Alert

+

+ Top 2 properties represent 50% of your portfolio. Consider diversifying. +

+
+
+
+
+
+ + {/* Overall Risk Score */} +
+
+
+

Overall Risk Score

+

{overallRiskScore}/100

+
+
+ +
+
+
+
+ ); +}; \ No newline at end of file diff --git a/src/components/dashboard/Sidebar.tsx b/src/components/dashboard/Sidebar.tsx new file mode 100644 index 00000000..3a2cc5ef --- /dev/null +++ b/src/components/dashboard/Sidebar.tsx @@ -0,0 +1,140 @@ +// 'use client'; + +// import { motion, AnimatePresence } from "framer-motion"; +// import { +// LayoutDashboard, +// Building2, +// BarChart3, +// Wallet, +// FileText, +// Settings, +// HelpCircle, +// ChevronLeft, +// X +// } from "lucide-react"; + +// interface SidebarProps { +// isOpen: boolean; +// onClose: () => void; +// activeItem?: string; +// onItemClick?: (item: string) => void; +// } + +// const menuItems = [ +// { id: "dashboard", label: "Dashboard", icon: LayoutDashboard }, +// { id: "properties", label: "Properties", icon: Building2 }, +// { id: "analytics", label: "Analytics", icon: BarChart3 }, +// { id: "wallet", label: "Wallet", icon: Wallet }, +// { id: "reports", label: "Reports", icon: FileText }, +// ]; + +// const bottomItems = [ +// { id: "settings", label: "Settings", icon: Settings }, +// { id: "help", label: "Help & Support", icon: HelpCircle }, +// ]; + +// export const Sidebar = ({ isOpen, onClose, activeItem = "dashboard", onItemClick }: SidebarProps) => { +// const SidebarContent = () => ( +//
+// {/* Logo section for mobile */} +//
+//
+//
+// M +//
+//
+//

MettaChain

+//
+//
+// +//
+ +// {/* Navigation */} +// + +// {/* Bottom section */} +//
+// {bottomItems.map((item) => ( +// +// ))} +//
+ +// {/* Upgrade card */} +//
+//
+//

Upgrade to Pro

+//

Unlock advanced analytics and premium features

+// +//
+//
+//
+// ); + +// return ( +// <> +// {/* Desktop sidebar */} +// + +// {/* Mobile sidebar overlay */} +// +// {isOpen && ( +// <> +// +// +// +// +// +// )} +// +// +// ); +// }; diff --git a/src/components/mobile/ARPropertyPreview.tsx b/src/components/mobile/ARPropertyPreview.tsx new file mode 100644 index 00000000..81c10225 --- /dev/null +++ b/src/components/mobile/ARPropertyPreview.tsx @@ -0,0 +1,469 @@ +"use client"; + +import React, { useState, useRef, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { + Camera, + X, + RotateCcw, + ZoomIn, + ZoomOut, + Move3D, + Info, + Share2, + Download, + Loader2, + AlertTriangle, +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Card } from "@/components/ui/card"; + +interface Property { + id: string; + name: string; + location: string; + type: string; + value: number; + sqft?: number; + bedrooms?: number; + bathrooms?: number; + description: string; + arModel?: string; // URL to 3D model +} + +interface ARPropertyPreviewProps { + property: Property; + isOpen: boolean; + onClose: () => void; +} + +export const ARPropertyPreview = ({ + property, + isOpen, + onClose, +}: ARPropertyPreviewProps) => { + const [isARSupported, setIsARSupported] = useState(false); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const [cameraStream, setCameraStream] = useState(null); + const [isModelLoaded, setIsModelLoaded] = useState(false); + const [showInfo, setShowInfo] = useState(false); + + const videoRef = useRef(null); + const canvasRef = useRef(null); + + useEffect(() => { + if (isOpen) { + checkARSupport(); + startCamera(); + } else { + stopCamera(); + } + + return () => { + stopCamera(); + }; + }, [isOpen]); + + const checkARSupport = () => { + // Check for WebXR AR support + if ("xr" in navigator) { + (navigator as any).xr + .isSessionSupported("immersive-ar") + .then((supported: boolean) => { + setIsARSupported(supported); + if (!supported) { + setError("AR is not supported on this device"); + } + setIsLoading(false); + }) + .catch(() => { + setIsARSupported(false); + setError("Unable to check AR support"); + setIsLoading(false); + }); + } else { + setIsARSupported(false); + setError("WebXR is not supported on this browser"); + setIsLoading(false); + } + }; + + const startCamera = async () => { + try { + const stream = await navigator.mediaDevices.getUserMedia({ + video: { + facingMode: "environment", // Use back camera + width: { ideal: 1280 }, + height: { ideal: 720 }, + }, + }); + + setCameraStream(stream); + + if (videoRef.current) { + videoRef.current.srcObject = stream; + videoRef.current.play(); + } + } catch (error) { + console.error("Error accessing camera:", error); + setError("Unable to access camera"); + } + }; + + const stopCamera = () => { + if (cameraStream) { + cameraStream.getTracks().forEach((track) => track.stop()); + setCameraStream(null); + } + }; + + const handleARSession = async () => { + if (!isARSupported) return; + + try { + // This is a simplified AR implementation + // In a real app, you would use WebXR or a library like AR.js or 8th Wall + const session = await (navigator as any).xr.requestSession( + "immersive-ar", + { + requiredFeatures: ["local", "hit-test"], + }, + ); + + // Handle AR session + console.log("AR session started:", session); + } catch (error) { + console.error("Error starting AR session:", error); + setError("Failed to start AR session"); + } + }; + + const handleCapture = () => { + if (!canvasRef.current || !videoRef.current) return; + + const canvas = canvasRef.current; + const video = videoRef.current; + const ctx = canvas.getContext("2d"); + + if (ctx) { + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + ctx.drawImage(video, 0, 0); + + // Convert to blob and trigger download + canvas.toBlob((blob) => { + if (blob) { + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `${property.name}-ar-preview.png`; + a.click(); + URL.revokeObjectURL(url); + } + }); + } + }; + + const handleShare = async () => { + if (!canvasRef.current || !videoRef.current) return; + + const canvas = canvasRef.current; + const video = videoRef.current; + const ctx = canvas.getContext("2d"); + + if (ctx) { + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + ctx.drawImage(video, 0, 0); + + canvas.toBlob(async (blob) => { + if (blob && navigator.share) { + try { + const file = new File([blob], `${property.name}-ar-preview.png`, { + type: "image/png", + }); + await navigator.share({ + title: `AR Preview: ${property.name}`, + text: `Check out this AR preview of ${property.name}`, + files: [file], + }); + } catch (error) { + console.log("Error sharing:", error); + } + } + }); + } + }; + + if (!isOpen) return null; + + return ( + + + {/* Header */} + +
+ + +
+ + AR Preview + +
+ +
+ +
+
+
+ + {/* Camera View */} +
+ {isLoading ? ( +
+
+ +

Initializing AR...

+
+
+ ) : error ? ( +
+
+ +

AR Not Available

+

{error}

+

+ AR features require a compatible device and browser. Try using + Chrome on Android or Safari on iOS. +

+
+
+ ) : ( + <> + {/* Video Stream */} +