Skip to content

Commit

Permalink
export to csv
Browse files Browse the repository at this point in the history
  • Loading branch information
salvobonsma committed Aug 20, 2024
1 parent fcec149 commit 5d082e1
Show file tree
Hide file tree
Showing 5 changed files with 546 additions and 3 deletions.
53 changes: 53 additions & 0 deletions app/[eventId]/overview/export-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use client'

import {Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger} from "@/components/ui/dialog";
import {Button} from "@/components/ui/button";
import React, {useState} from "react";
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "@/components/ui/select";
import {Label} from "@/components/ui/label";
import ExportCSV from "@/lib/database/export-csv"; // Adjust the path to where your ExportCSV function is located

export default function ExportDialog({eventId}: { eventId: number }) {
const [exportType, setExportType] = useState("csv");

async function downloadCSV() {
try {
const buffer = await ExportCSV(eventId);
const blob = new Blob([buffer], {type: 'application/zip'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'matches.zip';
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(url);
document.body.removeChild(a);
} catch (error) {
console.error('Error downloading CSV:', error);
}
}

return (
<Dialog>
<DialogTrigger asChild><Button className={"m-1.5"}>Export</Button></DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Export</DialogTitle>
</DialogHeader>
<div className={"flex justify-end gap-3 items-center"}>
<Label htmlFor={"exportType"}>Export to:</Label>
<Select value={exportType} onValueChange={setExportType}>
<SelectTrigger id={"exportType"} className={"w-32"}>
<SelectValue/>
</SelectTrigger>
<SelectContent>
<SelectItem value={"csv"}>CSV</SelectItem>
<SelectItem disabled value={"pdf"}>PDF</SelectItem>
</SelectContent>
</Select>
<Button onClick={downloadCSV}>Export</Button>
</div>
</DialogContent>
</Dialog>
);
}
4 changes: 2 additions & 2 deletions app/[eventId]/overview/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import prisma from "@/lib/prisma";
import NotFound from "@/app/not-found";
import {Separator} from "@/components/ui/separator";
import {Button} from "@/components/ui/button";
import Back from "@/components/back";
import React from "react";
import OverviewCharts from "@/app/[eventId]/overview/overview-charts";
import ScoutingCharts from "@/app/[eventId]/overview/scouting-charts";
import Teams from "@/app/[eventId]/overview/teams";
import ExportDialog from "@/app/[eventId]/overview/export-dialog";

export default async function Overview({params}: { params: { eventId: string } }) {
if (!+params.eventId) return NotFound();
Expand Down Expand Up @@ -52,7 +52,7 @@ export default async function Overview({params}: { params: { eventId: string } }
<Back link={`/${event.id}`} display={"Event"}/>
<div className={"flex justify-between items-center gap-2"}>
<h1>Event Overview</h1>
<Button className={"m-1.5"} disabled>Export</Button>
<ExportDialog eventId={+params.eventId}/>
</div>
<Separator/>
<OverviewCharts teamEntries={teamEntries}/>
Expand Down
44 changes: 44 additions & 0 deletions lib/database/export-csv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use server'

import prisma from "@/lib/prisma";
import archiver from "archiver";
import {Blob} from 'buffer';

export default async function ExportCSV(eventId: number) {
const matches = await arrayToCsv(await prisma.match.findMany({
where: {}
}));

const archive = archiver('zip', {zlib: {level: 9}});

// Add CSV data to archive
archive.append(matches, {name: 'matches.csv'});

// Finalize the archive (this returns a promise)
await archive.finalize();

// Collect archive chunks into a buffer
const bufferChunks: Uint8Array[] = [];
archive.on('data', (chunk) => bufferChunks.push(chunk));

await new Promise<void>((resolve, reject) => {
archive.on('end', () => resolve());
archive.on('error', (err) => reject(err));
});

return Buffer.from(await new Blob(bufferChunks, {type: 'application/zip'}).arrayBuffer());
}

async function arrayToCsv(data: any[]) {
if (data.length === 0) return '';

const headers = Object.keys(data[0]);
const csvRows = data.map(row =>
headers.map(header => {
const value = row[header];
return typeof value === 'string' ? `"${value.replace(/"/g, '""')}"` : value;
}).join(',')
);

return [headers.join(','), ...csvRows].join('\n');
}
Loading

0 comments on commit 5d082e1

Please sign in to comment.