Skip to content

Commit

Permalink
Merge pull request #37 from evmiguel/read-file
Browse files Browse the repository at this point in the history
Read file
  • Loading branch information
evmiguel committed Apr 9, 2024
2 parents cc5652a + 2465f1b commit 37e0bc6
Show file tree
Hide file tree
Showing 6 changed files with 980 additions and 16 deletions.
2 changes: 2 additions & 0 deletions app/purchases/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Purchases from "@/components/Purchases";
import AddPurchase from "@/components/AddPurchase";
import Sidebar from "@/components/Sidebar";
import { authOptions } from "../api/auth/[...nextauth]/options";
import FilePicker from "@/components/FilePicker";

async function getPurchases(email: string) {
const user = await prisma.user.findFirst(
Expand Down Expand Up @@ -36,6 +37,7 @@ export default async function Page() {
<main className="mb-8 md:col-span-4 md:order-1 lg:col-span-6 xl:col-span-8">
<Purchases purchases={purchases} />
<AddPurchase />
<FilePicker className={'container mx-auto text-center'} />
</main>
</div>
)
Expand Down
67 changes: 67 additions & 0 deletions classes/WorkbookParser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

import { Purchase } from '@/components/Purchases/columns';
import exceljs from 'exceljs';

export type ParserOutput = {
[index: number]: Purchase
}

abstract class WorkbookParser {
file: File;

constructor(file: File) {
this.file = file
}

readFile(fileRes: any) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsArrayBuffer(fileRes)
reader.onload = () => {
resolve(reader.result)
}
})
}

abstract parse(): Promise<ParserOutput>
}

class AmexWorkbookParser extends WorkbookParser {
constructor(file: File) {
super(file);
}

async parse() {
const workbook = new exceljs.Workbook();
const buffer = await this.readFile(this.file);
const fileData = await workbook.xlsx.load(buffer as Buffer);
const sheet = fileData.worksheets[0];
const data:ParserOutput = { }
sheet.eachRow((row, rowIndex) => {
if ([1, 2, 3, 4, 5, 6, 7].includes(rowIndex)) {
return;
}

const values = row.values as Array<any>;

data[rowIndex] = {
date: values[1],
name: values[2],
cost: values[3],
category: values[11],
};
});
return data;
}
}

enum Banks {
AMEX = 'AMEX'
}

export default function WorkbookParserFactory(bank: string, file: File) {
if (bank === Banks.AMEX) {
return new AmexWorkbookParser(file);
}
return null;
}
62 changes: 62 additions & 0 deletions components/FilePicker/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

'use client'
import { useRouter } from "next/navigation";
import WorkbookParserFactory, { ParserOutput } from "@/classes/WorkbookParser";
import { Purchase } from "../Purchases/columns";

type FilePickerProps = {
className: string
}

export default function FilePicker({ className }: FilePickerProps) {

const router = useRouter();

async function savePurchases(purchases: ParserOutput) {

Promise.all(Object.values(purchases as Array<Purchase>).map((purchase: Purchase) => {
const data = {
name: purchase.name,
cost: purchase.cost,
category: purchase.category,
date: new Date(purchase.date as unknown as string).setHours(24)
}

try {
fetch('/api/purchase', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
router.refresh();
} catch (error) {
console.error(error);
}
}));
}

const readExcel = async (file: File) => {
const parser = WorkbookParserFactory('AMEX', file);
if (!parser) {
return
}
const data = await parser.parse();
savePurchases(data);
};
return (
<div className={className}>
<input
placeholder="fileInput"
type="file"
multiple={true}
onChange={async (e: any) => {
const file = e.target.files[0];
await readExcel(file);
}}
accept=".xlsx,.xls,.csv"
/>
</div>
)
}
4 changes: 2 additions & 2 deletions components/Purchases/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {
} from "@/components/ui/dropdown-menu";

export type Purchase = {
id: bigint,
userId: string,
id?: bigint,
userId?: string,
name: string,
date: Date,
cost: number,
Expand Down
Loading

0 comments on commit 37e0bc6

Please sign in to comment.