Archive Commit

This commit is contained in:
2024-06-13 13:22:17 -07:00
commit 6015fa6048
29 changed files with 7462 additions and 0 deletions

24
demo/frontend/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

13
demo/frontend/index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

3459
demo/frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
{
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@vitejs/plugin-react": "^3.1.0",
"autoprefixer": "^10.4.13",
"postcss": "^8.4.21",
"tailwindcss": "^3.2.6",
"vite": "^4.1.0"
}
}

View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

40
demo/frontend/src/App.jsx Normal file
View File

@@ -0,0 +1,40 @@
import {useState} from 'react';
import {TransactionController} from './TransactionController';
function App() {
const [file, setFile] = useState(null);
const [transactions, setTransactions] = useState([]);
function handleUpload() {
const formData = new FormData();
formData.append('file', file);
fetch('/api/upload/', {
method: 'POST',
body: formData,
})
.then((response) => response.json())
.then((data) => {
setTransactions(data);
})
}
return (
<div className="bg-gray-100 h-screen flex flex-col justify-center items-center">
<div className="bg-white rounded-lg shadow-lg p-8">
<h1 className="text-2xl font-bold mb-4">Welcome to the Budget App</h1>
<p className="text-gray-500 mb-4">This is a simple app that will help you categorize your expenses.</p>
<p className="text-gray-500 mb-4">Upload a CSV file and we will do the rest.</p>
<div className="flex justify-center">
<input type="file" className="" onChange={(e) => setFile(e.target.files[0])} />
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={() => handleUpload()}>
Upload CSV
</button>
</div>
</div>
<TransactionController transactions={transactions} />
</div>
)
}
export default App

View File

@@ -0,0 +1,40 @@
import React from 'react';
import {TransactionsList} from './TransactionsList';
function TransactionController({transactions}) {
if(transactions.length === 0) {
return (
<div className="bg-white rounded-lg shadow-lg p-8 mt-6">
<h1 className="text-2xl font-bold mb-4">Transactions</h1>
<p className="text-gray-500 mb-4">No transactions to display.</p>
</div>
)
}
for(let i = 0; i < transactions.length; i++) {
transactions[i].id = i;
}
// Sort transactions by category and render a transactions list for each category
let sortedTransactions = {};
transactions.map((transaction) => {
if(sortedTransactions[transaction.Category] === undefined) {
sortedTransactions[transaction.Category] = [];
sortedTransactions[transaction.Category].push(transaction);
} else {
sortedTransactions[transaction.Category].push(transaction);
}
})
return (
<div className="bg-white rounded-lg shadow-lg p-8 mt-6">
<h1 className="text-2xl font-bold mb-4">Transactions</h1>
{Object.keys(sortedTransactions).map((category) => (
<TransactionsList key={category} category={category} transactions={sortedTransactions[category]} />
))}
</div>
)
}
export { TransactionController }

View File

@@ -0,0 +1,31 @@
import React from 'react';
function TransactionsList({category, transactions}) {
return (
<div className="bg-slate-100 rounded-lg shadow-lg p-8 mt-6">
<h1 className="text-2xl font-bold mb-4">{category}</h1>
<table className="table-auto">
<thead>
<tr>
<th className="px-4 py-2">Date</th>
<th className="px-4 py-2">Description</th>
<th className="px-4 py-2">Credit</th>
<th className="px-4 py-2">Debit</th>
</tr>
</thead>
<tbody>
{transactions.map((transaction) => (
<tr key={transaction.id}>
<td className="border px-4 py-2">{transaction.Date}</td>
<td className="border px-4 py-2">{transaction.Description}</td>
<td className="border px-4 py-2">{transaction.Credit}</td>
<td className="border px-4 py-2">{transaction.Debit}</td>
</tr>
))}
</tbody>
</table>
</div>
)
}
export { TransactionsList }

View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)

View File

@@ -0,0 +1,12 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}

View File

@@ -0,0 +1,16 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server:{
proxy:{
"/api" : {
target: 'http://localhost:3000/api/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
}
}
}
})