diff --git a/packages/core/app/history/page.tsx b/packages/core/app/history/page.tsx index 59b9041f..fea02571 100644 --- a/packages/core/app/history/page.tsx +++ b/packages/core/app/history/page.tsx @@ -14,16 +14,24 @@ import { import { API, constants, TradeAPi } from "@phoenix-protocol/utils"; import { fetchAllTrades, scaToToken } from "@phoenix-protocol/utils"; import { motion } from "framer-motion"; +import { + cardStyles, + colors, + spacing, + borderRadius, + typography, +} from "@phoenix-protocol/ui/src/Theme/styleConstants"; import { PriceHistoryResponse, TradingVolumeResponse, } from "@phoenix-protocol/utils/build/api/types"; -import { useEffect, useState, useCallback } from "react"; +import { useEffect, useState, useCallback, useRef } from "react"; export default function Page() { const appStore = useAppStore(); const appStorePersist = usePersistStore(); + const isSorting = useRef(false); const tradeApi = new TradeAPi.API(constants.TRADING_API_URL); @@ -36,6 +44,7 @@ export default function Page() { const [data, setData] = useState<{ timestamp: string; volume: number }[]>([]); const [totalVolume, setTotalVolume] = useState(0); const [period, setPeriod] = useState<"W" | "M" | "Y">("W"); + const [volumeTimeframe, setVolumeTimeframe] = useState<"D" | "M" | "A">("D"); // Independent state for volume chart const [history, setHistory] = useState([]); const [historyLoading, setHistoryLoading] = useState(true); const [historicalPrices, setHistoricalPrices] = @@ -52,9 +61,6 @@ export default function Page() { | undefined >("date"); const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc"); - const [selectedTimeEpoch, setSelectedTimeEpoch] = useState<"D" | "M" | "A">( - "D" - ); const [activeView, setActiveView] = useState<"personal" | "all">("all"); const [pools, setPools] = useState([]); const [activeFilters, setActiveFilters] = useState({ @@ -66,29 +72,128 @@ export default function Page() { string | undefined >(); - const applyFilters = useCallback((newFilters: ActiveFilters) => { - setActiveFilters(newFilters); - loadAllTrades(newFilters); - }, []); + const loadAllTrades = useCallback( + async (newFilters: ActiveFilters = activeFilters) => { + setHistoryLoading(true); + + try { + let from, to; + if (newFilters.dateRange.from) { + from = (newFilters.dateRange.from.getTime() / 1000).toFixed(0); + } + if (newFilters.dateRange.to) { + to = (newFilters.dateRange.to.getTime() / 1000).toFixed(0); + } + + const trades = await fetchAllTrades( + appStore, + pageSize, + undefined, + from, + to, + activeView === "personal" + ? appStorePersist.wallet.address + : undefined, + sortBy, + sortOrder + ); + + // Apply client-side filtering for tradeSize and tradeValue + let filteredTrades = trades; + + if ( + newFilters.tradeSize.from !== undefined || + newFilters.tradeSize.to !== undefined + ) { + filteredTrades = filteredTrades.filter((trade) => { + // Use fromAmount as the trade size + const size = trade.fromAmount; + if ( + newFilters.tradeSize.from !== undefined && + newFilters.tradeSize.to !== undefined + ) { + return ( + size >= newFilters.tradeSize.from && + size <= newFilters.tradeSize.to + ); + } else if (newFilters.tradeSize.from !== undefined) { + return size >= newFilters.tradeSize.from; + } else if (newFilters.tradeSize.to !== undefined) { + return size <= newFilters.tradeSize.to; + } + return true; + }); + } + + if ( + newFilters.tradeValue.from !== undefined || + newFilters.tradeValue.to !== undefined + ) { + filteredTrades = filteredTrades.filter((trade) => { + const value = parseFloat(trade.tradeValue); + if ( + newFilters.tradeValue.from !== undefined && + newFilters.tradeValue.to !== undefined + ) { + return ( + value >= newFilters.tradeValue.from && + value <= newFilters.tradeValue.to + ); + } else if (newFilters.tradeValue.from !== undefined) { + return value >= newFilters.tradeValue.from; + } else if (newFilters.tradeValue.to !== undefined) { + return value <= newFilters.tradeValue.to; + } + return true; + }); + } + + // Server-side sorting applied, no need for client-side sorting + setHistory(filteredTrades); + } catch (error) { + console.error("Error loading trades:", error); + } finally { + setHistoryLoading(false); + } + }, + [ + pageSize, + activeView, + appStorePersist.wallet.address, + activeFilters, + sortBy, + sortOrder, + ] + ); + + const applyFilters = useCallback( + (newFilters: ActiveFilters) => { + setActiveFilters(newFilters); + loadAllTrades(newFilters); + }, + [loadAllTrades] + ); const loadMore = () => { setPageSize((prev) => prev + 10); }; - const handleSortChange = ( - newSortBy: - | "tradeType" - | "asset" - | "tradeSize" - | "tradeValue" - | "date" - | "actions" - | undefined, - newSortOrder: "asc" | "desc" - ) => { - setSortBy(newSortBy); + const handleSortChange = (column: string) => { + let newSortOrder: "asc" | "desc"; + + // If clicking the same column, toggle the sort order + if (sortBy === column) { + newSortOrder = sortOrder === "asc" ? "desc" : "asc"; + } else { + // If clicking a different column, start with descending order (except for date which should start with desc to show newest first) + newSortOrder = column === "date" ? "desc" : "asc"; + } + + // Update sort state + setSortBy(column as any); setSortOrder(newSortOrder); - applyFilters(activeFilters); + + // The loadAllTrades function will be automatically called due to dependency array including sortBy and sortOrder }; const loadVolumeData = async (timeEpoch: "D" | "M" | "A") => { @@ -288,84 +393,13 @@ export default function Page() { setHistoricalPrices(graph); }; - const loadAllTrades = async (newFilters: ActiveFilters = activeFilters) => { - let from, to; - if (newFilters.dateRange.from) { - from = (newFilters.dateRange.from.getTime() / 1000).toFixed(0); - } - if (newFilters.dateRange.to) { - to = (newFilters.dateRange.to.getTime() / 1000).toFixed(0); - } - - const trades = await fetchAllTrades( - appStore, - pageSize, - undefined, - from, - to, - activeView === "personal" ? appStorePersist.wallet.address : undefined - ); - - // Apply client-side filtering for tradeSize and tradeValue - let filteredTrades = trades; - - if ( - newFilters.tradeSize.from !== undefined || - newFilters.tradeSize.to !== undefined - ) { - filteredTrades = filteredTrades.filter((trade) => { - // Use fromAmount as the trade size - const size = trade.fromAmount; - if ( - newFilters.tradeSize.from !== undefined && - newFilters.tradeSize.to !== undefined - ) { - return ( - size >= newFilters.tradeSize.from && size <= newFilters.tradeSize.to - ); - } else if (newFilters.tradeSize.from !== undefined) { - return size >= newFilters.tradeSize.from; - } else if (newFilters.tradeSize.to !== undefined) { - return size <= newFilters.tradeSize.to; - } - return true; - }); - } - - if ( - newFilters.tradeValue.from !== undefined || - newFilters.tradeValue.to !== undefined - ) { - filteredTrades = filteredTrades.filter((trade) => { - const value = parseFloat(trade.tradeValue); - if ( - newFilters.tradeValue.from !== undefined && - newFilters.tradeValue.to !== undefined - ) { - return ( - value >= newFilters.tradeValue.from && - value <= newFilters.tradeValue.to - ); - } else if (newFilters.tradeValue.from !== undefined) { - return value >= newFilters.tradeValue.from; - } else if (newFilters.tradeValue.to !== undefined) { - return value <= newFilters.tradeValue.to; - } - return true; - }); - } - - setHistory(filteredTrades); - setHistoryLoading(false); - }; - useEffect(() => { loadAllTrades(); - }, [pageSize, activeView]); + }, [loadAllTrades]); useEffect(() => { - loadVolumeData(selectedTimeEpoch); - }, [selectedTimeEpoch, selectedPoolForVolume]); + loadVolumeData(volumeTimeframe); // Use independent volume timeframe + }, [volumeTimeframe, selectedPoolForVolume]); useEffect(() => { loadPriceData(period); @@ -379,10 +413,10 @@ export default function Page() { return ( Volume ( - {selectedTimeEpoch === "D" + {volumeTimeframe === "D" ? "24h" - : selectedTimeEpoch === "M" + : volumeTimeframe === "M" ? "30d" : "1y"} ) @@ -539,45 +573,50 @@ export default function Page() { - - {/* Charts Section */} - - + + {/* Charts Section */} + + + + {" "} + {/* Increased spacing between charts */} - setSelectedTimeEpoch(e)} - selectedTab={selectedTimeEpoch} - totalVolume={totalVolume} - /> + {data.length > 0 && ( + + )} - + {historicalPrices.length > 0 && ( - - - + )} - - + + + + {/* Transactions Section */} + + {!historyLoading ? ( applyFilters(newFilters) } - handleSort={(column) => - handleSortChange( - column as any, - sortOrder === "asc" ? "desc" : "asc" - ) - } + handleSort={(column) => handleSortChange(column)} /> ) : ( )} + + {/* Load More Button */} - - Load More Transactions - + + + Load More Transactions + + - + ); } diff --git a/packages/core/app/pools/page.tsx b/packages/core/app/pools/page.tsx index 597ff9b2..d3c8efd3 100644 --- a/packages/core/app/pools/page.tsx +++ b/packages/core/app/pools/page.tsx @@ -250,14 +250,10 @@ export default function Page() { return ( {/* Hacky Title Injector - Waiting for Next Helmet for Next15 */} diff --git a/packages/ui/src/Earn/FilterBar/FilterBar.tsx b/packages/ui/src/Earn/FilterBar/FilterBar.tsx index 6abf720d..eefe8d9a 100644 --- a/packages/ui/src/Earn/FilterBar/FilterBar.tsx +++ b/packages/ui/src/Earn/FilterBar/FilterBar.tsx @@ -11,6 +11,7 @@ import { useMediaQuery, useTheme, SelectChangeEvent, + FormControl, } from "@mui/material"; import { motion } from "framer-motion"; import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; @@ -19,6 +20,7 @@ import { typography, spacing, borderRadius, + cardStyles, } from "../../Theme/styleConstants"; interface FilterBarProps { @@ -59,9 +61,9 @@ export const FilterBar = ({ return ( {/* Assets Filter */} @@ -99,50 +103,46 @@ export const FilterBar = ({ gap: spacing.xs, flexShrink: 0, position: "relative", - zIndex: 1, + zIndex: 2, + background: `linear-gradient(135deg, ${colors.neutral[800]}40 0%, ${colors.neutral[900]}60 100%)`, + borderRadius: borderRadius.md, + p: spacing.xs, + border: `1px solid ${colors.neutral[700]}`, }} > + + + ) : ( - - - ) : ( - - )} - - ) : ( - /* Desktop Layout */ - - {/* Assets Column */} - - - {assets.map((asset, idx) => ( - + )} + + ) : ( + /* Desktop Layout */ + + {/* Assets Column */} + + + {assets.map((asset, idx) => ( - - {asset.name} - - - ))} - - - - {/* Strategy Name */} - - - - {name} - - - - - {/* TVL */} - - - {formatCurrencyStatic.format(tvl)} - - - - {/* APR */} - - - Up to {(apr * 100).toFixed(1)}% - - + + + + + {asset.name} + + + ))} + + - {/* Reward Token */} - - - - {rewardToken.name} - - + {/* Strategy Name */} + + + + {name} + + + - {/* Your Stake - only show if joined */} - {hasJoined && ( + {/* TVL */} - Your Stake + {formatCurrencyStatic.format(tvl)} + + + {/* APR */} + - {formatCurrencyStatic.format(userStake)} + Up to {((apr * 100) / 2).toFixed(1)}% - )} - {/* Claimable rewards - only show if joined */} - {hasJoined && ( - - + - Claimable - - - 0 - ? colors.success[300] - : colors.neutral[300], - }} - > - {userRewards.toFixed(2)} {rewardToken.name} - - - )} - - {/* Unbond Time - only show if not joined */} - {!hasJoined && ( - - {formatUnbondTime(unbondTime)} + {rewardToken.name} - )} - {/* Action Button Column - Updated for desktop */} - - {hasJoined ? ( - - - - - ) : ( - - - + Claimable + + + + + + 0 + ? colors.success[300] + : colors.neutral[300], + }} + > + {userRewards.toFixed(2)} {rewardToken.name} + + + + )} + + {/* Unbond Time - only show if not joined */} + {!hasJoined && ( + + + {formatUnbondTime(unbondTime)} + + )} + + {/* Action Button Column - Updated for desktop */} + + {hasJoined ? ( + + + + + ) : ( + + + + )} + - - )} + )} + - + ); }; diff --git a/packages/ui/src/Transactions/FinancialChart/FinancialChart.tsx b/packages/ui/src/Transactions/FinancialChart/FinancialChart.tsx index d84daffc..e4c6d542 100644 --- a/packages/ui/src/Transactions/FinancialChart/FinancialChart.tsx +++ b/packages/ui/src/Transactions/FinancialChart/FinancialChart.tsx @@ -8,6 +8,7 @@ import { YAxis, } from "recharts"; import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { motion } from "framer-motion"; import { format } from "date-fns"; import { PriceHistoryResponse } from "@phoenix-protocol/utils"; import { @@ -29,23 +30,33 @@ type DataPoint = { const tabUnselectedStyles = { display: "flex", - width: "2.75rem", - height: "2.3125rem", - padding: "1.125rem 1.5rem", + minWidth: "44px", + height: "40px", + padding: `${spacing.sm} ${spacing.md}`, justifyContent: "center", alignItems: "center", - gap: "0.625rem", - borderRadius: "1rem", + borderRadius: borderRadius.md, cursor: "pointer", - color: "var(--neutral-300, #D4D4D4)", - background: "var(--neutral-900, #171717)", - border: "1px solid var(--neutral-700, #404040)", + fontFamily: typography.fontFamily, + fontSize: typography.fontSize.sm, + fontWeight: typography.fontWeights.medium, + transition: "all 0.3s ease", + color: colors.neutral[300], + background: `linear-gradient(145deg, ${colors.neutral[850]} 0%, ${colors.neutral[800]} 100%)`, + border: `1px solid ${colors.neutral[700]}`, + "&:hover": { + background: `linear-gradient(135deg, ${colors.primary.main}15 0%, ${colors.primary.dark}08 100%)`, + border: `1px solid ${colors.primary.main}30`, + color: colors.neutral[100], + transform: "translateY(-1px)", + }, }; const tabSelectedStyles = { - borderRadius: "1rem", - background: "rgba(226, 73, 26, 0.10)", - color: "var(--neutral-50, #FAFAFA)", + background: `linear-gradient(135deg, ${colors.primary.main}25 0%, ${colors.primary.dark}15 100%)`, + border: `1px solid ${colors.primary.main}80`, + color: colors.neutral[50], + boxShadow: `0 0 20px ${colors.primary.main}40`, }; // Helper function to format data @@ -84,9 +95,22 @@ const GlowingChart = ({ alignItems: "flex-start", gap: spacing.lg, borderRadius: borderRadius.lg, - background: colors.neutral[900], + background: `linear-gradient(145deg, ${colors.neutral[850]} 0%, ${colors.neutral[800]} 100%)`, border: `1px solid ${colors.neutral[700]}`, height: "100%", + position: "relative", + overflow: "hidden", + "&::before": { + content: '""', + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0, + background: `linear-gradient(135deg, ${colors.primary.main}03 0%, ${colors.primary.dark}02 100%)`, + borderRadius: borderRadius.lg, + pointerEvents: "none", + }, }} > @@ -152,90 +178,98 @@ const GlowingChart = ({ - setSelected("W")} - > - W - - setSelected("M")} - > - M - - + setSelected("W")} + > + W + + + + setSelected("M")} + > + M + + + + setSelected("Y")} + > + A + + + + + + + setSelected("Y")} > - A - - + + + + + + + tick.toFixed(2)} + tick={{ fontSize: isMobile ? 10 : 12 }} + width={isMobile ? 35 : 45} + /> + format(new Date(tick), "MM/dd/yy")} + tick={{ fontSize: isMobile ? 10 : 12 }} + tickMargin={isMobile ? 5 : 10} + /> + + } /> + + - - - - - - - - - tick.toFixed(2)} - tick={{ fontSize: isMobile ? 10 : 12 }} - width={isMobile ? 35 : 45} - /> - format(new Date(tick), "MM/dd/yy")} - tick={{ fontSize: isMobile ? 10 : 12 }} - tickMargin={isMobile ? 5 : 10} - /> - - } /> - - ); }; diff --git a/packages/ui/src/Transactions/TransactionsTable/FilterMenu.tsx b/packages/ui/src/Transactions/TransactionsTable/FilterMenu.tsx index a67fe04a..74b41316 100644 --- a/packages/ui/src/Transactions/TransactionsTable/FilterMenu.tsx +++ b/packages/ui/src/Transactions/TransactionsTable/FilterMenu.tsx @@ -107,15 +107,39 @@ const FilterMenu = ({ activeFilters, applyFilters }: FilterMenuProps) => { return (
-
diff --git a/packages/ui/src/Transactions/TransactionsTable/TransactionEntry.tsx b/packages/ui/src/Transactions/TransactionsTable/TransactionEntry.tsx index 1ff1a3cc..793289f1 100644 --- a/packages/ui/src/Transactions/TransactionsTable/TransactionEntry.tsx +++ b/packages/ui/src/Transactions/TransactionsTable/TransactionEntry.tsx @@ -2,259 +2,398 @@ import React from "react"; import { Box, Grid, Typography, useMediaQuery } from "@mui/material"; import { ArrowForward } from "@mui/icons-material"; import LaunchIcon from "@mui/icons-material/Launch"; +import { motion } from "framer-motion"; import { TransactionTableEntryProps } from "@phoenix-protocol/types"; +import { + colors, + typography, + spacing, + borderRadius, + cardStyles, +} from "../../Theme/styleConstants"; const TransactionEntry = ( props: TransactionTableEntryProps & { isMobile: boolean } ) => { - const { isMobile } = props; // Destructure isMobile - const BoxStyle = { - p: 3, - borderRadius: "12px", // Adjusted border radius - background: "var(--neutral-900, #171717)", // Adjusted background - border: "1px solid var(--neutral-700, #404040)", // Adjusted border - position: "relative", - overflow: "hidden", - boxShadow: "2px 2px 4px rgba(0, 0, 0, 0.3)", + const { isMobile } = props; + + // Format date with time + const formatDateTime = (timestamp: number) => { + const date = new Date(timestamp); + return { + date: date.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + }), + time: date.toLocaleTimeString("en-US", { + hour: "2-digit", + minute: "2-digit", + hour12: false, + }), + }; }; - return ( - - { + if (hash.length <= 16) return hash; + return `${hash.slice(0, 8)}...${hash.slice(-8)}`; + }; - width: "20%", - height: "auto", - opacity: 0.1, - transform: "translateY(-50%)", - ...(isMobile ? { right: 80 } : { left: -40 }), - }} - /> + // Format amount for better display + const formatAmount = (amount: number | string) => { + const num = typeof amount === "string" ? parseFloat(amount) : amount; + if (isNaN(num)) return amount; + + if (num >= 1000000) { + return `${(num / 1000000).toFixed(1)}M`; + } else if (num >= 1000) { + return `${(num / 1000).toFixed(1)}K`; + } + return num.toLocaleString("en-US", { maximumFractionDigits: 2 }); + }; + const { date, time } = formatDateTime(props.date); + + return ( + - - - - {isMobile && ( - - Date - - )} - - {new Date(props.date).toLocaleString()} - - + + {/* Date/Time Column */} + + {isMobile && ( + + Date & Time + + )} + + + {date} + + + {time} + + + - - {isMobile && ( - - Swap Details - - )} - + {/* Swap Details Column */} + + {isMobile && ( + + Swap Details + + )} + {/* From Asset */} + + + + + + {formatAmount(props.fromAmount)} + + + {props.fromAsset.name} + + + + + {/* Arrow */} + - - {props.fromAmount} - + + + + + + {formatAmount(props.toAmount)} + + + {props.toAsset.name} + + + + + + + {/* Trade Value Column */} + + {isMobile && ( - {props.fromAsset.name} + Trade Value (USD) - - + )} - - {props.toAmount} + ${formatAmount(props.tradeValue)} + + + + {/* Transaction ID Column */} + + {isMobile && ( - {props.toAsset.name} + Transaction ID - - - - - {isMobile && ( - - Trade Value (USD) - - )} - - ${props.tradeValue} - - - - {isMobile && ( - + window.open( + `https://stellar.expert/explorer/public/tx/${props.txHash}`, + "_blank" + ) + } > - Transaction ID - - )} - - window.open( - `https://stellar.expert/explorer/public/tx/${props.txHash}`, - "_blank" - ) - } - sx={{ - display: "flex", - alignItems: "center", - fontSize: isMobile ? "12px" : "14px", - fontWeight: "400", - textDecoration: "underline", - textDecorationStyle: "dotted", - color: "var(--neutral-300, #D4D4D4)", // Adjusted color - "&:hover": { - textDecoration: "underline", - cursor: "pointer", - }, - }} - > - - {props.txHash} - + + + {formatTxHash(props.txHash)} + + + - - + + ); }; diff --git a/packages/ui/src/Transactions/TransactionsTable/TransactionsHeader.tsx b/packages/ui/src/Transactions/TransactionsTable/TransactionsHeader.tsx index 466b02d4..7cb97392 100644 --- a/packages/ui/src/Transactions/TransactionsTable/TransactionsHeader.tsx +++ b/packages/ui/src/Transactions/TransactionsTable/TransactionsHeader.tsx @@ -1,12 +1,21 @@ import React from "react"; import { Box, Typography } from "@mui/material"; import { ArrowDownward, SwapVert } from "@mui/icons-material"; -import { colors, typography } from "../../Theme/styleConstants"; +import { colors, typography, spacing } from "../../Theme/styleConstants"; -function convertToCamelCase(input: string): string { - return input - .toLowerCase() - .replace(/\s+(\w)/g, (_, match) => match.toUpperCase()); +function mapLabelToColumn(label: string): string { + switch (label) { + case "Date & Time": + return "date"; + case "Swap Details": + return "asset"; + case "Trade Value (USD)": + return "tradeValue"; + case "Transaction ID": + return "actions"; // This should not be sortable, but keeping for consistency + default: + return label.toLowerCase().replace(/\s+/g, ""); + } } const TransactionHeader = ({ @@ -22,42 +31,67 @@ const TransactionHeader = ({ sx={{ display: "flex", alignItems: "center", - cursor: label !== "Actions" ? "pointer" : "default", + cursor: + label !== "Actions" && label !== "Transaction ID" + ? "pointer" + : "default", + p: spacing.xs, + borderRadius: "6px", + transition: "all 0.2s ease", + "&:hover": + label !== "Actions" && label !== "Transaction ID" + ? { + background: `linear-gradient(135deg, ${colors.primary.main}10 0%, ${colors.primary.dark}05 100%)`, + "& .header-text": { + color: colors.neutral[100], + }, + "& .header-icon": { + color: colors.primary.main, + }, + } + : {}, }} onClick={() => { - if (label !== "Actions") { - handleSort(convertToCamelCase(label)); + if (label !== "Actions" && label !== "Transaction ID") { + handleSort(mapLabelToColumn(label)); } }} > {label} {label !== "Actions" && + label !== "Transaction ID" && (active ? ( ) : ( ))} diff --git a/packages/ui/src/Transactions/TransactionsTable/TransactionsTable.tsx b/packages/ui/src/Transactions/TransactionsTable/TransactionsTable.tsx index 24f7dc3f..b9b44c3b 100644 --- a/packages/ui/src/Transactions/TransactionsTable/TransactionsTable.tsx +++ b/packages/ui/src/Transactions/TransactionsTable/TransactionsTable.tsx @@ -1,16 +1,16 @@ import React from "react"; -import { Box, Grid, Tooltip, Typography, useMediaQuery } from "@mui/material"; // Import useMediaQuery -import { motion } from "framer-motion"; // Import Framer Motion +import { Box, Grid, Tooltip, Typography, useMediaQuery } from "@mui/material"; +import { motion } from "framer-motion"; import FilterMenu from "./FilterMenu"; import { TransactionsTableProps } from "@phoenix-protocol/types"; import TransactionEntry from "./TransactionEntry"; import TransactionHeader from "./TransactionsHeader"; -import { maxWidth } from "@mui/system"; import { colors, typography, spacing, borderRadius, + cardStyles, } from "../../Theme/styleConstants"; const customSpacing = { @@ -19,104 +19,6 @@ const customSpacing = { md: spacing.md, }; -const classes = { - root: { - marginTop: customSpacing.md, - padding: `${customSpacing.md} ${customSpacing.md}`, - borderRadius: "20px", - background: ` - linear-gradient(135deg, rgba(23, 23, 23, 0.95) 0%, rgba(38, 38, 38, 0.85) 100%) - `, - backdropFilter: "blur(20px)", - border: "1px solid rgba(249, 115, 22, 0.2)", - overflowX: "auto", - boxShadow: - "0 20px 40px rgba(0, 0, 0, 0.4), 0 0 30px rgba(249, 115, 22, 0.1)", - position: "relative", - "&::before": { - content: '""', - position: "absolute", - top: 0, - left: 0, - right: 0, - bottom: 0, - background: - "linear-gradient(135deg, rgba(249, 115, 22, 0.03) 0%, rgba(234, 88, 12, 0.02) 100%)", - borderRadius: "20px", - pointerEvents: "none", - }, - }, - tabUnselected: { - display: "flex", - width: "auto", - minWidth: "80px", - height: "40px", - padding: `12px 20px`, - justifyContent: "center", - alignItems: "center", - gap: "0.625rem", - borderRadius: "12px", - cursor: "pointer", - color: "rgba(255, 255, 255, 0.7)", - background: "rgba(23, 23, 23, 0.8)", - backdropFilter: "blur(10px)", - opacity: 0.9, - textAlign: "center", - fontFeatureSettings: "'clig' off, 'liga' off", - fontFamily: typography.fontFamily, - fontSize: "14px", - fontStyle: "normal", - fontWeight: typography.fontWeights.medium, - lineHeight: "1.25rem", - border: "1px solid rgba(255, 255, 255, 0.1)", - transition: "all 0.3s ease", - "&:hover": { - background: "rgba(249, 115, 22, 0.15)", - border: "1px solid rgba(249, 115, 22, 0.3)", - color: "rgba(255, 255, 255, 0.9)", - transform: "translateY(-1px)", - boxShadow: "0 4px 12px rgba(249, 115, 22, 0.2)", - }, - }, - tabSelected: { - display: "flex", - minWidth: "80px", - height: "40px", - padding: `12px 20px`, - justifyContent: "center", - alignItems: "center", - gap: "0.625rem", - flex: "1 0 0", - borderRadius: "12px", - border: "1px solid rgba(249, 115, 22, 0.8)", - background: ` - linear-gradient(135deg, rgba(249, 115, 22, 0.25) 0%, rgba(234, 88, 12, 0.15) 100%) - `, - backdropFilter: "blur(10px)", - color: "#FAFAFA", - textAlign: "center", - fontFeatureSettings: "'clig' off, 'liga' off", - fontFamily: typography.fontFamily, - fontSize: "14px", - fontStyle: "normal", - fontWeight: typography.fontWeights.bold, - lineHeight: "1.25rem", - boxShadow: - "0 0 20px rgba(249, 115, 22, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1)", - animation: "glow 2s ease-in-out infinite alternate", - "@keyframes glow": { - "0%": { - boxShadow: - "0 0 20px rgba(249, 115, 22, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1)", - }, - "100%": { - boxShadow: - "0 0 30px rgba(249, 115, 22, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.2)", - }, - }, - }, -}; - const TransactionsTable = ({ activeView, setActiveView, @@ -128,7 +30,7 @@ const TransactionsTable = ({ entries, }: TransactionsTableProps) => { const [renderedEntries, setRenderedEntries] = React.useState(0); - const isMobile = useMediaQuery((theme) => theme.breakpoints.down("md")); // Check if the device is mobile + const isMobile = useMediaQuery((theme) => theme.breakpoints.down("md")); // Render entries one by one with a delay React.useEffect(() => { @@ -137,7 +39,7 @@ const TransactionsTable = ({ setRenderedEntries((prevCount) => prevCount < entries.length ? prevCount + 1 : prevCount ); - }, 200); // Adjust the delay between each entry here (in milliseconds) + }, 200); return () => clearInterval(interval); } @@ -145,77 +47,160 @@ const TransactionsTable = ({ return ( - {/* @ts-ignore */} - + + {/* Header with Tabs and Filter */} - setActiveView("all")} - whileHover={{ scale: 1.05 }} - > - All + + setActiveView("all")} + > + All + + (loggedIn ? setActiveView("personal") : null)} - whileHover={{ scale: 1.05 }} + whileHover={{ scale: loggedIn ? 1.02 : 1 }} + whileTap={{ scale: loggedIn ? 0.98 : 1 }} > - Personal + (loggedIn ? setActiveView("personal") : null)} + > + Personal + + - {!isMobile && ( // Hide header on mobile + {/* Desktop Header */} + {!isMobile && ( @@ -234,11 +218,9 @@ const TransactionsTable = ({ @@ -267,25 +249,30 @@ const TransactionsTable = ({ handleSort={handleSort} label="Transaction ID" active={ - activeSort.column === "date" ? activeSort.direction : false + activeSort.column === "actions" + ? activeSort.direction + : false } /> )} - + + {/* Transactions List */} + {entries.map((entry, index) => ( ))} + + {/* Empty State */} {entries.length === 0 && ( - - - 📊 - - + 📊 + + {activeView === "personal" @@ -338,8 +322,8 @@ const TransactionsTable = ({ { const tabUnselectedStyles = { display: "flex", - width: "2.75rem", - height: "2.3125rem", - padding: "1.125rem 1.5rem", + minWidth: "44px", + height: "40px", + padding: `${spacing.sm} ${spacing.md}`, justifyContent: "center", alignItems: "center", - gap: "0.625rem", borderRadius: borderRadius.md, cursor: "pointer", + fontFamily: typography.fontFamily, + fontSize: typography.fontSize.sm, + fontWeight: typography.fontWeights.medium, + transition: "all 0.3s ease", color: colors.neutral[300], - background: colors.neutral[900], + background: `linear-gradient(145deg, ${colors.neutral[850]} 0%, ${colors.neutral[800]} 100%)`, border: `1px solid ${colors.neutral[700]}`, + "&:hover": { + background: `linear-gradient(135deg, ${colors.primary.main}15 0%, ${colors.primary.dark}08 100%)`, + border: `1px solid ${colors.primary.main}30`, + color: colors.neutral[100], + transform: "translateY(-1px)", + }, }; const tabSelectedStyles = { - borderRadius: borderRadius.md, - background: "rgba(226, 73, 26, 0.10)", + background: `linear-gradient(135deg, ${colors.primary.main}25 0%, ${colors.primary.dark}15 100%)`, + border: `1px solid ${colors.primary.main}80`, color: colors.neutral[50], + boxShadow: `0 0 20px ${colors.primary.main}40`, }; const VolumeChart = ({ @@ -143,24 +154,39 @@ const VolumeChart = ({ sx={{ display: "flex", width: "100%", - padding: "1.5rem", + padding: spacing.lg, flexDirection: "column", justifyContent: "center", alignItems: "flex-start", - gap: "1.5625rem", - borderRadius: "1.5rem", - background: colors.neutral[900], // Adjusted background - border: `1px solid ${colors.neutral[700]}`, // Adjusted border + gap: spacing.lg, + borderRadius: borderRadius.lg, + background: `linear-gradient(145deg, ${colors.neutral[850]} 0%, ${colors.neutral[800]} 100%)`, + border: `1px solid ${colors.neutral[700]}`, + position: "relative", + overflow: "hidden", + "&::before": { + content: '""', + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0, + background: `linear-gradient(135deg, ${colors.primary.main}03 0%, ${colors.primary.dark}02 100%)`, + borderRadius: borderRadius.lg, + pointerEvents: "none", + }, }} > @@ -216,139 +242,153 @@ const VolumeChart = ({ - setSelectedTab("D")} - > - D - - setSelectedTab("M")} - > - M - - setSelectedTab("A")} - > - A - + + setSelectedTab("D")} + > + D + + + + setSelectedTab("M")} + > + M + + + + setSelectedTab("A")} + > + A + + - - - - - - - - - - - - - - - - - - - - - - - { - if (active && payload && payload.length) { - return ( -
-

- {label} -

-

+ + + + + + + + + + + + + + + + + + + + + + + { + if (active && payload && payload.length) { + return ( +

- Volume: - {formatCurrencyStatic.format(Number(payload[0].value))} -

-
- ); - } - return null; - }} - /> +

+ {label} +

+

+ Volume: + {formatCurrencyStatic.format(Number(payload[0].value))} +

+
+ ); + } + return null; + }} + /> - - {data.map((entry, index) => ( - - ))} - -
-
+ + {data.map((entry, index) => ( + + ))} + + + +
); }; diff --git a/packages/utils/src/api/fetchTrades.ts b/packages/utils/src/api/fetchTrades.ts index 86549c35..141f948c 100644 --- a/packages/utils/src/api/fetchTrades.ts +++ b/packages/utils/src/api/fetchTrades.ts @@ -10,7 +10,9 @@ export async function fetchAllTrades( type?: string | undefined, startTime?: string | undefined, endTime?: string | undefined, - personal: string | undefined = undefined + personal: string | undefined = undefined, + sortBy?: string, + sortOrder?: "asc" | "desc" ) { try { const tradeApi = new API(constants.TRADING_API_URL); @@ -41,6 +43,8 @@ export async function fetchAllTrades( limit: limit, startTime: startTime ? Number(startTime) : undefined, endTime: endTime ? Number(endTime) : undefined, + sortBy: sortBy, + sortOrder: sortOrder, }); // Current timestamp and 24 hours ago diff --git a/packages/utils/src/trade_api/trade_api.ts b/packages/utils/src/trade_api/trade_api.ts index 470c475f..baff3928 100644 --- a/packages/utils/src/trade_api/trade_api.ts +++ b/packages/utils/src/trade_api/trade_api.ts @@ -48,7 +48,10 @@ export class API { } async getPrice(name: string): Promise { - if (name === "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75" || name === "CDIKURWHYS4FFTR5KOQK6MBFZA2K3E26WGBQI6PXBYWZ4XIOPJHDFJKP") { + if ( + name === "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75" || + name === "CDIKURWHYS4FFTR5KOQK6MBFZA2K3E26WGBQI6PXBYWZ4XIOPJHDFJKP" + ) { return 1; } return this.get(`/price/${name}`); diff --git a/packages/utils/src/trade_api/types.ts b/packages/utils/src/trade_api/types.ts index fc8da36a..199dc125 100644 --- a/packages/utils/src/trade_api/types.ts +++ b/packages/utils/src/trade_api/types.ts @@ -70,6 +70,8 @@ export interface AdvancedTradesParams { limit?: number; startTime?: number; endTime?: number; + sortBy?: string; + sortOrder?: "asc" | "desc"; } export interface TradeHistoryParams {