Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ jobs:
run: npm audit --audit-level=moderate || echo "Security audit completed with issues"

# - name: 🧪 Run Jest Tests
# run: npm test
# run: npm test
33 changes: 20 additions & 13 deletions api/ocr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import fs from "node:fs/promises";
export const config = {
api: {
bodyParser: false,
maxDuration: 10
}
maxDuration: 10,
},
};

type VisionAnnotateResponse = {
Expand All @@ -28,15 +28,21 @@ export default async function handler(req: VercelRequest, res: VercelResponse) {
multiples: false,
maxFileSize: 8 * 1024 * 1024,
filter: (part) =>
part.mimetype ? /^image\/(png|jpe?g|webp)$/i.test(part.mimetype) : false
part.mimetype
? /^image\/(png|jpe?g|webp)$/i.test(part.mimetype)
: false,
});

const { files } = await new Promise<{ files: FormidableFiles }>((resolve, reject) =>
form.parse(req, (err, _fields, files) => (err ? reject(err) : resolve({ files })))
const { files } = await new Promise<{ files: FormidableFiles }>(
(resolve, reject) =>
form.parse(req, (err, _fields, files) =>
err ? reject(err) : resolve({ files }),
),
);

const file = Array.isArray(files.file) ? files.file[0] : files.file;
if (!file?.filepath) return res.status(400).json({ error: "No file uploaded" });
if (!file?.filepath)
return res.status(400).json({ error: "No file uploaded" });

const buf = await fs.readFile(file.filepath);
const content = buf.toString("base64");
Expand All @@ -51,11 +57,11 @@ export default async function handler(req: VercelRequest, res: VercelResponse) {
requests: [
{
image: { content },
features: [{ type: "TEXT_DETECTION" }]
}
]
})
}
features: [{ type: "TEXT_DETECTION" }],
},
],
}),
},
);

if (!r.ok) {
Expand All @@ -70,11 +76,12 @@ export default async function handler(req: VercelRequest, res: VercelResponse) {
resp?.textAnnotations?.[0]?.description ??
"";

if (!text) return res.status(200).json({ text: "", warning: "No text found" });
if (!text)
return res.status(200).json({ text: "", warning: "No text found" });
return res.status(200).json({ text });
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : "OCR failed";
console.error(err);
return res.status(500).json({ error: msg });
}
}
}
5 changes: 4 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Bill Buddy</title>
<meta name="description" content="Split your bills easily and fairly with Bill Buddy." />
<meta
name="description"
content="Split your bills easily and fairly with Bill Buddy."
/>
<link rel="icon" type="image/svg+xml" href="/icon.png" />
</head>
<body>
Expand Down
16 changes: 8 additions & 8 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Routes, Route } from 'react-router-dom';
import { Routes, Route } from "react-router-dom";

import Calculator from './pages/Calculator';
import Footer from './components/Footer';
import Home from './pages/Home';
import Navbar from './components/Navbar';
import Review from './pages/Review';
import Split from './pages/Split';
import Calculator from "./pages/Calculator";
import Footer from "./components/Footer";
import Home from "./pages/Home";
import Navbar from "./components/Navbar";
import Review from "./pages/Review";
import Split from "./pages/Split";

const App = () => {
return (
Expand All @@ -19,7 +19,7 @@ const App = () => {
</Routes>
<Footer />
</>
)
);
};

export default App;
4 changes: 2 additions & 2 deletions src/components/AssignItemModal.module.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Modal Title*/
.modalTitle {
font-weight: bold;
font-weight: bold;
}

/* People Selection */
Expand Down Expand Up @@ -96,4 +96,4 @@
.warning::before {
content: "⚠️ ";
margin-right: 0.5rem;
}
}
30 changes: 15 additions & 15 deletions src/components/Footer.module.css
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
footer {
margin-top: 4rem;
padding: 2rem 1rem;
text-align: center;
font-size: 0.9rem;
color: #666;
border-top: 1px solid #eee;
margin-top: 4rem;
padding: 2rem 1rem;
text-align: center;
font-size: 0.9rem;
color: #666;
border-top: 1px solid #eee;
}

footer a {
color: var(--primary-pink);
font-weight: 600;
text-decoration: none;
color: var(--primary-pink);
font-weight: 600;
text-decoration: none;
}

footer a:hover {
text-decoration: underline;
color: var(--primary-pink);
cursor: url('/cursors/Yellow.png'), auto;
}
text-decoration: underline;
color: var(--primary-pink);
cursor: url("/cursors/Yellow.png"), auto;
}
45 changes: 26 additions & 19 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import confetti from 'canvas-confetti';
import confetti from "canvas-confetti";

import styles from "./Footer.module.css"
import styles from "./Footer.module.css";

const Footer = () => {
const handleHover = () => {
confetti({
particleCount: 150,
spread: 60,
origin: { y: 0.6 },
scalar: 0.6,
});
};

return (
<footer className={styles.footer}>
<p>
Made with ❤️ and a calculator by <a href="https://github.com/rxshellg" target="_blank" onMouseEnter={handleHover}>Rashell Guerrero</a>
</p>
</footer>
)
const handleHover = () => {
confetti({
particleCount: 150,
spread: 60,
origin: { y: 0.6 },
scalar: 0.6,
});
};

return (
<footer className={styles.footer}>
<p>
Made with ❤️ and a calculator by{" "}
<a
href="https://github.com/rxshellg"
target="_blank"
onMouseEnter={handleHover}
>
Rashell Guerrero
</a>
</p>
</footer>
);
};

export default Footer;
export default Footer;
38 changes: 19 additions & 19 deletions src/components/Navbar.module.css
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
.navbar {
width: 100%;
padding: 1rem 2rem;
background-color: white;
border-bottom: 1px solid #eee;
display: flex;
align-items: center;
justify-content: space-between;
position: sticky;
top: 0;
z-index: 10;
width: 100%;
padding: 1rem 2rem;
background-color: white;
border-bottom: 1px solid #eee;
display: flex;
align-items: center;
justify-content: space-between;
position: sticky;
top: 0;
z-index: 10;
}

.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary-pink);
text-decoration: none;
transition: color 0.3s ease;
font-size: 1.5rem;
font-weight: bold;
color: var(--primary-pink);
text-decoration: none;
transition: color 0.3s ease;
}

.logo:hover {
color: #db195a;
cursor: url('/cursors/Yellow.png'), auto;
color: #db195a;
cursor: url("/cursors/Yellow.png"), auto;
}
18 changes: 9 additions & 9 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Link } from "react-router-dom";
import styles from './Navbar.module.css';
import styles from "./Navbar.module.css";

const Navbar = () => {
return (
<nav className={styles.navbar}>
<Link to="/" className={styles.logo}>
Bill Buddy
</Link>
</nav>
)
return (
<nav className={styles.navbar}>
<Link to="/" className={styles.logo}>
Bill Buddy
</Link>
</nav>
);
};

export default Navbar;
export default Navbar;
4 changes: 2 additions & 2 deletions src/components/PeopleManager/AddPersonModal.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Modal Title*/
.modalTitle {
font-weight: bold;
}
font-weight: bold;
}
12 changes: 8 additions & 4 deletions src/components/PeopleManager/AddPersonModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Modal from "react-bootstrap/Modal";
import { useState } from "react";
import { DEFAULT_COLORS } from "./usePeople";
import styles from './AddPersonModal.module.css';
import styles from "./AddPersonModal.module.css";

interface Props {
show: boolean;
Expand Down Expand Up @@ -47,7 +47,7 @@ export default function AddPersonModal({ show, onClose, onSubmit }: Props) {
height: 28,
borderRadius: "50%",
border: color === c ? "3px solid #111" : "1px solid #aaa",
backgroundColor: c
backgroundColor: c,
}}
/>
))}
Expand All @@ -58,10 +58,14 @@ export default function AddPersonModal({ show, onClose, onSubmit }: Props) {
<button className="whiteButton" onClick={onClose}>
Cancel
</button>
<button className="pinkButton" onClick={handleAdd} disabled={!name.trim()}>
<button
className="pinkButton"
onClick={handleAdd}
disabled={!name.trim()}
>
Add
</button>
</Modal.Footer>
</Modal>
);
}
}
14 changes: 7 additions & 7 deletions src/components/PeopleManager/PeopleChips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ interface Props {
onRemovePerson: (id: string) => void;
}

export default function PeopleChips({ people, onAddClick, onRemovePerson }: Props) {
export default function PeopleChips({
people,
onAddClick,
onRemovePerson,
}: Props) {
return (
<div className={styles.chipsRow}>
{people.map((p) => (
Expand All @@ -22,13 +26,9 @@ export default function PeopleChips({ people, onAddClick, onRemovePerson }: Prop
</button>
))}

<button
type="button"
onClick={onAddClick}
className={styles.addChip}
>
<button type="button" onClick={onAddClick} className={styles.addChip}>
+ Add person
</button>
</div>
);
}
}
2 changes: 1 addition & 1 deletion src/components/PeopleManager/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { usePeople } from "./usePeople";
export { default as PeopleChips } from "./PeopleChips";
export { default as AddPersonModal } from "./AddPersonModal";
export { default as AddPersonModal } from "./AddPersonModal";
Loading
Loading