Skip to content

Commit

Permalink
export DB as CSV
Browse files Browse the repository at this point in the history
  • Loading branch information
lucia-gomez committed Sep 26, 2024
1 parent e4c5a52 commit a2b3081
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 0 deletions.
57 changes: 57 additions & 0 deletions booking-app/app/api/bookings/export/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Booking, BookingStatus } from "@/components/src/types";
import { NextRequest, NextResponse } from "next/server";

import { TableNames } from "@/components/src/policy";
import { parse } from "json2csv";
import { serverFetchAllDataFromCollection } from "@/lib/firebase/server/adminDb";

export async function GET(request: NextRequest) {
const bookings = await serverFetchAllDataFromCollection<Booking>(
TableNames.BOOKING,
);
const statuses = await serverFetchAllDataFromCollection<BookingStatus>(
TableNames.BOOKING_STATUS,
);

// need to find corresponding status row for booking row
const idsToData: {
[key: string]: {
booking: Booking;
status: BookingStatus;
};
} = {};

for (let booking of bookings) {
const calendarEventId = booking.calendarEventId;
const statusMatch = statuses.filter(
row => row.calendarEventId === calendarEventId,
)[0];
idsToData[calendarEventId] = {
booking,
status: statusMatch,
};
}

const rows = Object.entries(idsToData)
.map(([_, { booking, status }]) => {
const { requestNumber, ...otherBooking } = booking;
return { requestNumber, ...otherBooking, ...status };
})
.sort((a, b) => a.requestNumber - b.requestNumber);

try {
const csv = parse(rows);
return new NextResponse(csv, {
status: 200,
headers: {
"Content-Type": "text/csv",
"Content-Disposition": 'attachment; filename="data.csv"',
},
});
} catch (error) {
return NextResponse.json(
{ error: "Failed to fetch CSV data" },
{ status: 400 },
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Box, Button, Typography } from "@mui/material";
import React, { useState } from "react";

import AlertToast from "../../components/AlertToast";

export default function ExportDatabase() {
const [loading, setLoading] = useState(false);
const [showError, setShowError] = useState(false);

const onClick = async () => {
setLoading(true);
try {
const response = await fetch("/api/bookings/export");

if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error);
}

const blob = await response.blob();
const url = window.URL.createObjectURL(new Blob([blob]));

// Automatically trigger the download
const link = document.createElement("a");
link.href = url;
link.download = "data.csv";
link.click();

// Clean up
window.URL.revokeObjectURL(url);
} catch (ex) {
setShowError(true);
console.error("error exporting database", ex);
} finally {
setLoading(false);
}
};

return (
<Box>
<Typography variant="h6">Export Database</Typography>
<p>Export database booking contents as a downloadable CSV file</p>
<Box sx={{ marginTop: 2 }}>
<Button onClick={onClick} variant="contained" disabled={loading}>
Export
</Button>
</Box>
<AlertToast
message="Failed to download file"
severity="error"
open={showError}
handleClose={() => setShowError(false)}
/>
</Box>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AdminUsers } from "./AdminUsers";
import { BannedUsers } from "./Ban";
import BookingTypes from "./BookingTypes";
import { Departments } from "./Departments";
import ExportDatabase from "./ExportDatabase";
import FinalApproverSetting from "./PolicySettings";
import Grid from "@mui/material/Unstable_Grid2";
import { Liaisons } from "./Liaisons";
Expand All @@ -20,6 +21,7 @@ const tabs = [
{ label: "Ban", id: "ban" },
{ label: "Booking Types", id: "bookingTypes" },
{ label: "Policy Settings", id: "policy" },
{ label: "Export", id: "export" },
];

export default function Settings() {
Expand Down Expand Up @@ -49,6 +51,7 @@ export default function Settings() {
{tab === "departments" && <Departments />}
{tab === "bookingTypes" && <BookingTypes />}
{tab === "policy" && <FinalApproverSetting />}
{tab === "export" && <ExportDatabase />}
</Grid>
</Grid>
);
Expand Down
36 changes: 36 additions & 0 deletions booking-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions booking-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"fullcalendar": "^6.1.14",
"googleapis": "^140.0.1",
"handlebars": "^4.7.8",
"json2csv": "^6.0.0-alpha.2",
"mysql2": "^3.10.1",
"next": "14.2.4",
"prop-types": "^15.8.1",
Expand Down

0 comments on commit a2b3081

Please sign in to comment.