diff --git a/src/containers/Treasuries/index.tsx b/src/containers/Treasuries/index.tsx
index 39bdd2e7d6..1b800a65d5 100644
--- a/src/containers/Treasuries/index.tsx
+++ b/src/containers/Treasuries/index.tsx
@@ -14,13 +14,15 @@ import { TableWithSearch } from '~/components/Table/TableWithSearch'
import { TokenLogo } from '~/components/TokenLogo'
import { Tooltip } from '~/components/Tooltip'
import Layout from '~/layout'
-import { download, formattedNum, getDominancePercent, tokenIconUrl } from '~/utils'
+import { formattedNum, getDominancePercent, tokenIconUrl } from '~/utils'
+import { useCSVDownload } from '~/hooks/useCSVDownload'
const pageName = ['Protocols', 'ranked by', 'Treasury']
export function Treasuries({ data, entity }) {
const [columnFilters, setColumnFilters] = useState([])
const [sorting, setSorting] = useState([])
+ const { downloadCSV, isLoading: isDownloadLoading } = useCSVDownload()
const tableColumns = useMemo(
() => (entity ? columns.filter((c: any) => !['ownTokens', 'coreTvl'].includes(c.accessorKey)) : columns),
[entity]
@@ -41,7 +43,7 @@ export function Treasuries({ data, entity }) {
const [projectName, setProjectName] = useState('')
- const downloadCSV = () => {
+ const handleCSVDownload = () => {
const headers = [
'Name',
'Category',
@@ -75,7 +77,7 @@ export function Treasuries({ data, entity }) {
const csv = [headers.join(',')]
.concat(dataToDownload.map((row) => headers.map((header) => row[header]).join(',')))
.join('\n')
- download('treasuries.csv', csv)
+ downloadCSV('treasuries.csv', csv)
}
useEffect(() => {
@@ -96,7 +98,7 @@ export function Treasuries({ data, entity }) {
header={'Treasuries'}
customFilters={
<>
-
+
>
}
/>
diff --git a/src/containers/Yields/Filters/Dropdowns.tsx b/src/containers/Yields/Filters/Dropdowns.tsx
index d2475698a5..99b8272789 100644
--- a/src/containers/Yields/Filters/Dropdowns.tsx
+++ b/src/containers/Yields/Filters/Dropdowns.tsx
@@ -52,7 +52,8 @@ export function YieldFilterDropdowns({
showTotalSupplied,
showTotalBorrowed,
showAvailable,
- onCSVDownload
+ onCSVDownload,
+ isCSVDownloading
}: IDropdownMenusProps) {
const router = useRouter()
@@ -316,6 +317,7 @@ export function YieldFilterDropdowns({
: 'flex cursor-pointer flex-nowrap items-center gap-2 rounded-md bg-(--btn-bg) px-3 py-2 text-xs text-(--text-primary) hover:bg-(--btn-hover-bg) focus-visible:bg-(--btn-hover-bg)'
}
onClick={onCSVDownload}
+ isLoading={isCSVDownloading}
/>
) : null}
>
diff --git a/src/containers/Yields/Filters/types.ts b/src/containers/Yields/Filters/types.ts
index 1638527bd3..98e058cdfe 100644
--- a/src/containers/Yields/Filters/types.ts
+++ b/src/containers/Yields/Filters/types.ts
@@ -36,6 +36,7 @@ export interface IDropdownMenusProps {
showTotalBorrowed?: boolean
showAvailable?: boolean
onCSVDownload?: () => void
+ isCSVDownloading?: boolean
}
export interface IYieldFiltersProps extends IDropdownMenusProps {
@@ -48,4 +49,5 @@ export interface IYieldFiltersProps extends IDropdownMenusProps {
noOfStrategies?: number
showSearchOnMobile?: boolean
onCSVDownload?: () => void
+ isCSVDownloading?: boolean
}
diff --git a/src/containers/Yields/index.tsx b/src/containers/Yields/index.tsx
index 05b5840135..77ed4bb3a2 100644
--- a/src/containers/Yields/index.tsx
+++ b/src/containers/Yields/index.tsx
@@ -2,7 +2,7 @@ import * as React from 'react'
import { useRouter } from 'next/router'
import { Announcement } from '~/components/Announcement'
import { LocalLoader } from '~/components/LocalLoader'
-import { download } from '~/utils'
+import { useCSVDownload } from '~/hooks/useCSVDownload'
import { YieldFiltersV2 } from './Filters'
import { useFormatYieldQueryParams } from './hooks'
import { YieldsPoolsTable } from './Tables/Pools'
@@ -12,6 +12,7 @@ const YieldPage = ({ pools, projectList, chainList, categoryList, tokens, tokenS
const { query, pathname, push } = useRouter()
const { minTvl, maxTvl, minApy, maxApy } = query
const [loading, setLoading] = React.useState(true)
+ const { downloadCSV, isLoading: isDownloadLoading } = useCSVDownload()
const {
selectedProjects,
@@ -127,7 +128,7 @@ const YieldPage = ({ pools, projectList, chainList, categoryList, tokens, tokenS
pathname,
pairTokens
])
- const downloadCSV = React.useCallback(() => {
+ const handleCSVDownload = React.useCallback(() => {
const headers = [
'Pool',
'Project',
@@ -191,8 +192,8 @@ const YieldPage = ({ pools, projectList, chainList, categoryList, tokens, tokenS
}
})
const csv = [headers].concat(csvData.map((row) => headers.map((header) => row[header]))).join('\n')
- download('yields.csv', csv)
- }, [poolsData])
+ downloadCSV('yields.csv', csv)
+ }, [poolsData, downloadCSV])
return (
<>
@@ -251,7 +252,8 @@ const YieldPage = ({ pools, projectList, chainList, categoryList, tokens, tokenS
showTotalBorrowed={true}
showAvailable={true}
showLTV={true}
- onCSVDownload={downloadCSV}
+ onCSVDownload={handleCSVDownload}
+ isCSVDownloading={isDownloadLoading}
/>
{loading ? (
diff --git a/src/hooks/useCSVDownload.ts b/src/hooks/useCSVDownload.ts
new file mode 100644
index 0000000000..40333235fc
--- /dev/null
+++ b/src/hooks/useCSVDownload.ts
@@ -0,0 +1,41 @@
+import { useState, useCallback } from 'react'
+import { downloadCSV as downloadCSVUtil, downloadDatasetCSV as downloadDatasetCSVUtil } from '~/utils'
+import { downloadChart as downloadChartUtil } from '~/components/ECharts/utils'
+
+export function useCSVDownload() {
+ const [isLoading, setIsLoading] = useState(false)
+
+ const downloadCSV = useCallback((filename: string, csvData: any, options: any = {}) => {
+ return downloadCSVUtil(filename, csvData, {
+ ...options,
+ onLoadingStart: () => setIsLoading(true),
+ onLoadingEnd: () => setIsLoading(false),
+ onError: () => setIsLoading(false)
+ })
+ }, [])
+
+ const downloadDatasetCSV = useCallback((options: any) => {
+ return downloadDatasetCSVUtil({
+ ...options,
+ onLoadingStart: () => setIsLoading(true),
+ onLoadingEnd: () => setIsLoading(false),
+ onError: () => setIsLoading(false)
+ })
+ }, [])
+
+ const downloadChart = useCallback((data: any, filename: string, options: any = {}) => {
+ return downloadChartUtil(data, filename, {
+ ...options,
+ onLoadingStart: () => setIsLoading(true),
+ onLoadingEnd: () => setIsLoading(false),
+ onError: () => setIsLoading(false)
+ })
+ }, [])
+
+ return {
+ isLoading,
+ downloadCSV,
+ downloadDatasetCSV,
+ downloadChart
+ }
+}
\ No newline at end of file
diff --git a/src/pages/etfs.tsx b/src/pages/etfs.tsx
index 29886fba91..d3357dfc98 100644
--- a/src/pages/etfs.tsx
+++ b/src/pages/etfs.tsx
@@ -8,6 +8,7 @@ import { TableWithSearch } from '~/components/Table/TableWithSearch'
import { TagGroup } from '~/components/TagGroup'
import Layout from '~/layout'
import { download, firstDayOfMonth, formattedNum, lastDayOfWeek, toNiceCsvDate } from '~/utils'
+import { useCSVDownload } from '~/hooks/useCSVDownload'
import { withPerformanceLogging } from '~/utils/perf'
const LineAndBarChart = React.lazy(
@@ -79,6 +80,7 @@ const groupByList = ['Daily', 'Weekly', 'Monthly', 'Cumulative']
const PageView = ({ snapshot, flows, totalsByAsset, lastUpdated }: PageViewProps) => {
const [groupBy, setGroupBy] = React.useState<(typeof groupByList)[number]>('Weekly')
const [tickers, setTickers] = React.useState(['Bitcoin', 'Ethereum'])
+ const { downloadCSV, isLoading: isDownloadLoading } = useCSVDownload()
const charts = React.useMemo(() => {
const bitcoin = {}
@@ -196,11 +198,12 @@ const PageView = ({ snapshot, flows, totalsByAsset, lastUpdated }: PageViewProps
rows.push([date, toNiceCsvDate(date), flows[date]['Bitcoin'] ?? '', flows[date]['Ethereum'] ?? ''])
}
const filename = `etf-flows-${new Date().toISOString().split('T')[0]}.csv`
- download(filename, rows.map((r) => r.join(',')).join('\n'))
+ downloadCSV(filename, rows.map((r) => r.join(',')).join('\n'))
} catch (error) {
console.error('Error generating CSV:', error)
}
}}
+ isLoading={isDownloadLoading}
smol
/>
diff --git a/src/pages/forks.tsx b/src/pages/forks.tsx
index 5aa264cb0d..d82ad53f2f 100644
--- a/src/pages/forks.tsx
+++ b/src/pages/forks.tsx
@@ -8,7 +8,8 @@ import { TableWithSearch } from '~/components/Table/TableWithSearch'
import { getForkPageData } from '~/containers/Forks/queries'
import { useCalcGroupExtraTvlsByDay, useCalcStakePool2Tvl } from '~/hooks/data'
import Layout from '~/layout'
-import { download, preparePieChartData } from '~/utils'
+import { preparePieChartData } from '~/utils'
+import { useCSVDownload } from '~/hooks/useCSVDownload'
import { withPerformanceLogging } from '~/utils/perf'
const PieChart = React.lazy(() => import('~/components/ECharts/PieChart')) as React.FC
@@ -30,6 +31,7 @@ const pageName = ['Protocols', 'ranked by', 'TVL in Forks']
export default function Forks({ chartData, tokensProtocols, tokens, tokenLinks, parentTokens, forkColors }) {
const forkedTokensData = useCalcStakePool2Tvl(parentTokens)
+ const { downloadCSV, isLoading: isDownloadLoading } = useCSVDownload()
const { chainsWithExtraTvlsByDay, chainsWithExtraTvlsAndDominanceByDay } = useCalcGroupExtraTvlsByDay(chartData)
@@ -59,7 +61,7 @@ export default function Forks({ chartData, tokensProtocols, tokens, tokenLinks,
return { tokenTvls, tokensList }
}, [chainsWithExtraTvlsByDay, tokensProtocols, forkedTokensData])
- const downloadCSV = () => {
+ const handleCSVDownload = () => {
const headers = ['Name', 'Forked Protocols', 'TVL', 'Forked TVL / Original TVL %']
const csvData = tokensList.map((row) => {
return {
@@ -70,7 +72,7 @@ export default function Forks({ chartData, tokensProtocols, tokens, tokenLinks,
}
})
const csv = [headers].concat(csvData.map((row) => headers.map((header) => row[header]))).join('\n')
- download('forks.csv', csv)
+ downloadCSV('forks.csv', csv)
}
return (
@@ -78,7 +80,7 @@ export default function Forks({ chartData, tokensProtocols, tokens, tokenLinks,
-
+
>}>
diff --git a/src/pages/hacks/total-value-lost.tsx b/src/pages/hacks/total-value-lost.tsx
index afa6f111ea..2e41e2cb50 100644
--- a/src/pages/hacks/total-value-lost.tsx
+++ b/src/pages/hacks/total-value-lost.tsx
@@ -12,6 +12,7 @@ import {
} from '~/containers/Hacks/queries'
import Layout from '~/layout'
import { download, formattedNum, tokenIconUrl } from '~/utils'
+import { useCSVDownload } from '~/hooks/useCSVDownload'
import { withPerformanceLogging } from '~/utils/perf'
export const getStaticProps = withPerformanceLogging('protocols/total-value-lost-in-hacks', async () => {
@@ -25,6 +26,7 @@ export const getStaticProps = withPerformanceLogging('protocols/total-value-lost
const pageName = ['Protocols', 'ranked by', 'Total Value Lost in Hacks']
export default function TotalLostInHacks({ protocols }: IProtocolTotalValueLostInHacksByProtocol) {
+ const { downloadCSV, isLoading: isDownloadLoading } = useCSVDownload()
const [selectedColumns, setSelectedColumns] = React.useState
>([
'Name',
'Total Hacked',
@@ -73,8 +75,9 @@ export default function TotalLostInHacks({ protocols }: IProtocolTotalValueLostI
protocol.totalHacked - protocol.returnedFunds
])
}
- download('total-value-lost-in-hacks.csv', rows.map((r) => r.join(',')).join('\n'))
+ downloadCSV('total-value-lost-in-hacks.csv', rows.map((r) => r.join(',')).join('\n'))
}}
+ isLoading={isDownloadLoading}
smol
/>
>
diff --git a/src/pages/protocol/bridge-aggregators/[...protocol].tsx b/src/pages/protocol/bridge-aggregators/[...protocol].tsx
index 9decf3f46d..8d022043b2 100644
--- a/src/pages/protocol/bridge-aggregators/[...protocol].tsx
+++ b/src/pages/protocol/bridge-aggregators/[...protocol].tsx
@@ -1,7 +1,8 @@
import { lazy, Suspense, useMemo, useState } from 'react'
import { maxAgeForNext } from '~/api'
import { CSVDownloadButton } from '~/components/ButtonStyled/CsvButton'
-import { downloadChart, formatBarChart } from '~/components/ECharts/utils'
+import { formatBarChart } from '~/components/ECharts/utils'
+import { useCSVDownload } from '~/hooks/useCSVDownload'
import { TokenLogo } from '~/components/TokenLogo'
import { Tooltip } from '~/components/Tooltip'
import { oldBlue } from '~/constants/colors'
@@ -106,6 +107,7 @@ const INTERVALS_LIST = ['daily', 'weekly', 'monthly', 'cumulative'] as const
export default function Protocols(props) {
const [groupBy, setGroupBy] = useState<(typeof INTERVALS_LIST)[number]>(props.defaultChartView)
+ const { downloadChart, isLoading } = useCSVDownload()
const finalCharts = useMemo(() => {
return {
'Bridge Aggregator Volume': {
@@ -172,6 +174,7 @@ export default function Protocols(props) {
console.error('Error generating CSV:', error)
}
}}
+ isLoading={isLoading}
smol
/>
diff --git a/src/pages/protocol/dex-aggregators/[...protocol].tsx b/src/pages/protocol/dex-aggregators/[...protocol].tsx
index 1c58dee927..b3eeef2868 100644
--- a/src/pages/protocol/dex-aggregators/[...protocol].tsx
+++ b/src/pages/protocol/dex-aggregators/[...protocol].tsx
@@ -1,7 +1,8 @@
import { lazy, Suspense, useMemo, useState } from 'react'
import { maxAgeForNext } from '~/api'
import { CSVDownloadButton } from '~/components/ButtonStyled/CsvButton'
-import { downloadChart, formatBarChart } from '~/components/ECharts/utils'
+import { formatBarChart } from '~/components/ECharts/utils'
+import { useCSVDownload } from '~/hooks/useCSVDownload'
import { TokenLogo } from '~/components/TokenLogo'
import { Tooltip } from '~/components/Tooltip'
import { oldBlue } from '~/constants/colors'
@@ -106,6 +107,7 @@ const INTERVALS_LIST = ['daily', 'weekly', 'monthly', 'cumulative'] as const
export default function Protocols(props) {
const [groupBy, setGroupBy] = useState<(typeof INTERVALS_LIST)[number]>(props.defaultChartView)
+ const { downloadChart, isLoading } = useCSVDownload()
const finalCharts = useMemo(() => {
return {
'DEX Aggregator Volume': {
@@ -172,6 +174,7 @@ export default function Protocols(props) {
console.error('Error generating CSV:', error)
}
}}
+ isLoading={isLoading}
smol
/>
diff --git a/src/pages/protocol/dexs/[...protocol].tsx b/src/pages/protocol/dexs/[...protocol].tsx
index e610d3b01d..7679a912b0 100644
--- a/src/pages/protocol/dexs/[...protocol].tsx
+++ b/src/pages/protocol/dexs/[...protocol].tsx
@@ -1,7 +1,8 @@
import { lazy, Suspense, useMemo, useState } from 'react'
import { maxAgeForNext } from '~/api'
import { CSVDownloadButton } from '~/components/ButtonStyled/CsvButton'
-import { downloadChart, formatBarChart } from '~/components/ECharts/utils'
+import { formatBarChart } from '~/components/ECharts/utils'
+import { useCSVDownload } from '~/hooks/useCSVDownload'
import { TokenLogo } from '~/components/TokenLogo'
import { Tooltip } from '~/components/Tooltip'
import { oldBlue } from '~/constants/colors'
@@ -105,6 +106,7 @@ const INTERVALS_LIST = ['daily', 'weekly', 'monthly', 'cumulative'] as const
export default function Protocols(props) {
const [groupBy, setGroupBy] = useState<(typeof INTERVALS_LIST)[number]>(props.defaultChartView)
+ const { downloadChart, isLoading } = useCSVDownload()
const finalCharts = useMemo(() => {
return {
'DEX Volume': {
@@ -171,6 +173,7 @@ export default function Protocols(props) {
console.error('Error generating CSV:', error)
}
}}
+ isLoading={isLoading}
smol
/>
diff --git a/src/pages/protocol/fees/[...protocol].tsx b/src/pages/protocol/fees/[...protocol].tsx
index 91a4215dda..32045552b5 100644
--- a/src/pages/protocol/fees/[...protocol].tsx
+++ b/src/pages/protocol/fees/[...protocol].tsx
@@ -1,7 +1,8 @@
import { lazy, Suspense, useMemo, useState } from 'react'
import { maxAgeForNext } from '~/api'
import { CSVDownloadButton } from '~/components/ButtonStyled/CsvButton'
-import { downloadChart, formatBarChart } from '~/components/ECharts/utils'
+import { formatBarChart } from '~/components/ECharts/utils'
+import { useCSVDownload } from '~/hooks/useCSVDownload'
import { feesOptions } from '~/components/Filters/options'
import { Select } from '~/components/Select'
import { TokenLogo } from '~/components/TokenLogo'
@@ -221,6 +222,7 @@ export default function Protocols(props) {
const [groupBy, setGroupBy] = useState<(typeof INTERVALS_LIST)[number]>(props.defaultChartView)
const [charts, setCharts] = useState