11import { useEffect , useState } from "react" ;
22import { Link , useParams } from "react-router-dom" ;
3- import { InboxInIcon as NoApplicationsForRoundIcon } from "@heroicons/react/outline" ;
4- import { Spinner } from "../common/Spinner" ;
3+ import {
4+ DownloadIcon ,
5+ InboxInIcon as NoApplicationsForRoundIcon ,
6+ } from "@heroicons/react/outline" ;
7+ import { LoadingRing , Spinner } from "../common/Spinner" ;
58import {
69 BasicCard ,
710 CardContent ,
@@ -34,17 +37,47 @@ import ProgressModal from "../common/ProgressModal";
3437import { errorModalDelayMs } from "../../constants" ;
3538import ErrorModal from "../common/ErrorModal" ;
3639import { renderToPlainText } from "common" ;
40+ import { roundApplicationsToCSV } from "../api/exports" ;
41+ import { utils } from "ethers" ;
42+ import { useWallet } from "../common/Auth" ;
43+
44+ async function exportAndDownloadCSV (
45+ roundId : string ,
46+ chainId : number ,
47+ chainName : string
48+ ) {
49+ const csv = await roundApplicationsToCSV ( roundId , chainId , chainName ) ;
50+
51+ // create a download link and click it
52+ const outputBlob = new Blob ( [ csv ] , {
53+ type : "text/csv;charset=utf-8;" ,
54+ } ) ;
55+
56+ const link = document . createElement ( "a" ) ;
57+
58+ try {
59+ const dataUrl = URL . createObjectURL ( outputBlob ) ;
60+ link . setAttribute ( "href" , dataUrl ) ;
61+ link . setAttribute ( "download" , `applications-${ roundId } .csv` ) ;
62+ link . style . visibility = "hidden" ;
63+ document . body . appendChild ( link ) ;
64+ link . click ( ) ;
65+ } finally {
66+ document . body . removeChild ( link ) ;
67+ }
68+ }
3769
3870type Props = {
3971 isDirectRound ?: boolean ;
4072} ;
4173
42- // Direct Grant Applications to Approve/Reject
74+ // Approve or reject applications received in bulk, both in QF & direct grants
4375
44- export default function DGApplicationsToApproveReject ( {
76+ export default function ApplicationsToApproveReject ( {
4577 isDirectRound = false ,
4678} : Props ) {
4779 const { id } = useParams ( ) ;
80+ const { chain } = useWallet ( ) ;
4881
4982 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
5083 const { applications, isLoading } = useApplicationByRoundId ( id ! ) ;
@@ -59,6 +92,7 @@ export default function DGApplicationsToApproveReject({
5992 const [ openProgressModal , setOpenProgressModal ] = useState ( false ) ;
6093 const [ openErrorModal , setOpenErrorModal ] = useState ( false ) ;
6194 const [ selected , setSelected ] = useState < GrantApplication [ ] > ( [ ] ) ;
95+ const [ isCsvExportLoading , setIsCsvExportLoading ] = useState ( false ) ;
6296
6397 const {
6498 bulkUpdateGrantApplications,
@@ -164,9 +198,50 @@ export default function DGApplicationsToApproveReject({
164198 }
165199 } ;
166200
201+ async function handleExportCsvClick (
202+ roundId : string ,
203+ chainId : number ,
204+ chainName : string
205+ ) {
206+ try {
207+ setIsCsvExportLoading ( true ) ;
208+ await exportAndDownloadCSV ( roundId , chainId , chainName ) ;
209+ } catch ( e ) {
210+ datadogLogs . logger . error (
211+ `error: exportApplicationCsv - ${ e } , id: ${ roundId } `
212+ ) ;
213+ console . error ( "exportApplicationCsv" , e ) ;
214+ } finally {
215+ setIsCsvExportLoading ( false ) ;
216+ }
217+ }
218+
167219 return (
168220 < div >
169221 < div className = "flex items-center mb-4" >
222+ { id && applications && applications . length > 0 && (
223+ < Button
224+ type = "button"
225+ $variant = "outline"
226+ className = "text-xs px-3 py-1 inline-block"
227+ disabled = { isCsvExportLoading }
228+ onClick = { ( ) =>
229+ handleExportCsvClick ( utils . getAddress ( id ) , chain . id , chain . name )
230+ }
231+ >
232+ { isCsvExportLoading ? (
233+ < >
234+ < LoadingRing className = "animate-spin w-3 h-3 inline-block mr-2 -mt-0.5" />
235+ < span className = "text-grey-400" > Exporting...</ span >
236+ </ >
237+ ) : (
238+ < >
239+ < DownloadIcon className = "w-4 h-4 inline -mt-0.5 mr-1" />
240+ < span > CSV</ span >
241+ </ >
242+ ) }
243+ </ Button >
244+ ) }
170245 { filteredApplications && filteredApplications . length > 0 && (
171246 < div className = "flex items-center justify-end ml-auto" >
172247 < span className = "text-grey-400 text-sm mr-6" >
0 commit comments