diff --git a/README.md b/README.md index 65f3b31..c3490ae 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ Splitzy is a modern expense sharing platform that simplifies splitting bills and - **💳 Settlement Tracking**: Keep track of payments and settle debts - **📈 Expense Analytics**: Visual insights into spending patterns - **🔐 Secure Authentication**: Safe and secure user authentication +- **📸 Smart Receipt Scanning**: AI-powered OCR to automatically extract expense details from receipts +- **📤 Export to Excel**: Download group expenses to CSV/Excel for offline records +- **🔔 Smart Reminders**: Send gentle notifications to remind friends about pending settlements - **📧 Notifications**: Email reminders for pending expenses and settlements ## Tech Stack @@ -196,9 +199,9 @@ docker run -p 3000:3000 splitzy ## Roadmap - [ ] Mobile app (React Native/Flutter) -- [ ] Receipt scanning with OCR +- [x] Receipt scanning with OCR - [ ] Multiple currency support -- [ ] Expense categories and budgeting +- [x] Expense categories and budgeting - [ ] Integration with banking APIs - [ ] Advanced analytics and reporting - [ ] Recurring expenses diff --git a/UI/package-lock.json b/UI/package-lock.json index 26658c5..36dada6 100644 --- a/UI/package-lock.json +++ b/UI/package-lock.json @@ -24,6 +24,7 @@ "postcss": "^8.5.4", "rxjs": "~7.8.0", "tailwindcss": "^4.1.8", + "tesseract.js": "^7.0.0", "tslib": "^2.3.0", "uuid": "^13.0.0", "zone.js": "~0.15.0" @@ -7251,6 +7252,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==", + "license": "MIT" + }, "node_modules/body-parser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", @@ -8505,7 +8512,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -8516,7 +8522,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -9801,6 +9806,12 @@ "integrity": "sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg==", "license": "ISC" }, + "node_modules/idb-keyval": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", + "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", + "license": "Apache-2.0" + }, "node_modules/ignore-walk": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz", @@ -10175,6 +10186,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, "node_modules/is-what": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", @@ -12201,6 +12218,26 @@ "license": "MIT", "optional": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-forge": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", @@ -12652,6 +12689,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "license": "MIT", + "bin": { + "opencollective-postinstall": "index.js" + } + }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -13533,6 +13579,12 @@ "node": ">=4" } }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, "node_modules/regex-parser": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.1.tgz", @@ -15116,6 +15168,30 @@ } } }, + "node_modules/tesseract.js": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-7.0.0.tgz", + "integrity": "sha512-exPBkd+z+wM1BuMkx/Bjv43OeLBxhL5kKWsz/9JY+DXcXdiBjiAch0V49QR3oAJqCaL5qURE0vx9Eo+G5YE7mA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "bmp-js": "^0.1.0", + "idb-keyval": "^6.2.0", + "is-url": "^1.2.4", + "node-fetch": "^2.6.9", + "opencollective-postinstall": "^2.0.3", + "regenerator-runtime": "^0.13.3", + "tesseract.js-core": "^7.0.0", + "wasm-feature-detect": "^1.8.0", + "zlibjs": "^0.3.1" + } + }, + "node_modules/tesseract.js-core": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-7.0.0.tgz", + "integrity": "sha512-WnNH518NzmbSq9zgTPeoF8c+xmilS8rFIl1YKbk/ptuuc7p6cLNELNuPAzcmsYw450ca6bLa8j3t0VAtq435Vw==", + "license": "Apache-2.0" + }, "node_modules/thingies": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", @@ -15190,6 +15266,12 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/tree-dump": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", @@ -15675,6 +15757,12 @@ "node": ">=0.10.0" } }, + "node_modules/wasm-feature-detect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz", + "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==", + "license": "Apache-2.0" + }, "node_modules/watchpack": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", @@ -15707,6 +15795,12 @@ "license": "MIT", "optional": true }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, "node_modules/webpack": { "version": "5.104.1", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", @@ -16450,6 +16544,16 @@ "node": ">=0.10.0" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -16743,6 +16847,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zlibjs": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz", + "integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/zod": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", diff --git a/UI/package.json b/UI/package.json index abc6839..963b47c 100644 --- a/UI/package.json +++ b/UI/package.json @@ -26,6 +26,7 @@ "postcss": "^8.5.4", "rxjs": "~7.8.0", "tailwindcss": "^4.1.8", + "tesseract.js": "^7.0.0", "tslib": "^2.3.0", "uuid": "^13.0.0", "zone.js": "~0.15.0" diff --git a/UI/src/app/splitz/dashboard/add-member-modal/add-member-modal.component.html b/UI/src/app/splitz/dashboard/add-member-modal/add-member-modal.component.html index 7a59d4f..6b75832 100644 --- a/UI/src/app/splitz/dashboard/add-member-modal/add-member-modal.component.html +++ b/UI/src/app/splitz/dashboard/add-member-modal/add-member-modal.component.html @@ -1,16 +1,23 @@ -
-
- -
+
+
+ +
- +

Add Members

-
@if (errorMessage) { -
- - - - {{ errorMessage }} -
+
+ + + + {{ errorMessage }} +
}
@for (email of userEmails; track trackByIndex(i); let i = $index) { -
-
-
- - - -
-
- - @if (getEmailError(i)) { -

- - - - {{ getEmailError(i) }} -

- } -
+
+
+
+ + + +
- @if (userEmails.length > 1) { - - } + {{ getEmailError(i) }} +

+ } +
+ @if (userEmails.length > 1) { + + } +
}
-
- - +
+ +

Enter email addresses of people you want to add. You can add more members later. @@ -87,10 +113,14 @@

Add Members

- - -
-
- } +
+
+ @if (oweTo && oweTo.length) { +
+ @for (person of oweTo; track trackByPersonName($index, person)) { +
+
+
+ {{ getInitials(person.name) }} +
+
+ {{ person.name }} + Outstanding debt +
- } @else { -
-
🎉
- You owe nothing! - You're all caught up with payments +
+ + {{ person.amount | currency:'INR':'symbol': '1.2-2' }} + +
+
}
+ } @else { +
+
🎉
+ You owe nothing! + You're all caught up with payments +
+ }
+
-
-
-
-
- - - -
-

You Are Owed

+
+
+
+
+ + + +
+

You Are Owed

-
- @if (owedFrom && owedFrom.length) { -
- @for (person of owedFrom; track trackByPersonName($index, person)) { -
-
-
- {{ getInitials(person.name) }} -
-
- {{ person.name }} - Owes you money -
-
-
- - {{ person.amount | currency:'INR':'symbol': '1.2-2' }} - - -
-
- } +
+
+ @if (owedFrom && owedFrom.length) { +
+ @for (person of owedFrom; track trackByPersonName($index, person)) { +
+
+
+ {{ getInitials(person.name) }} +
+
+ {{ person.name }} + Owes you money +
- } @else { -
-
💸
- No one owes you! - Time to add some expenses +
+ + {{ person.amount | currency:'INR':'symbol': '1.2-2' }} + +
+
}
+ } @else { +
+
💸
+ No one owes you! + Time to add some expenses +
+ }
+
-
-
-
-
- - - -
-

Groups

-
- +
+

Groups

-
- @if (groups && groups.length) { -
- @for (group of groups; track trackByGroupId($index, group)) { -
- -
- - - -
-
- {{ group.groupName }} - {{ getGroupStatus(group.netBalance) }} -
-
-
-
- + + + + +
+
+ @if (groups && groups.length) { +
+ @for (group of groups; track trackByGroupId($index, group)) { +
+ +
+ + + + +
+
+ {{ + group.groupName }} + {{ getGroupStatus(group.netBalance) }} +
+
+
+
+ - {{ group.netBalance | currency:'INR':'symbol': '1.2-2' }} - -
- -
-
- } -
- } @else { -
-
👥
- No groups yet! - Create a group to start splitting expenses -
+
+
}
+ } @else { +
+
👥
+ No groups yet! + Create a group to start splitting expenses + +
+ }
+
} @if (showExpenseModal) { - - + + } @if (showGroupModal) { - - + + } \ No newline at end of file diff --git a/UI/src/app/splitz/dashboard/expense-modal/expense-modal.component.html b/UI/src/app/splitz/dashboard/expense-modal/expense-modal.component.html index 02e6a32..1171ca6 100644 --- a/UI/src/app/splitz/dashboard/expense-modal/expense-modal.component.html +++ b/UI/src/app/splitz/dashboard/expense-modal/expense-modal.component.html @@ -1,7 +1,19 @@ -
-
+
+
-
+ +
+
+

Scanning Receipt...

+

This may take a moment

+
+ +
@@ -10,7 +22,9 @@

{{addOrEdit}} an Expense

- +
₹ - +
@@ -41,18 +73,22 @@

{{addOrEdit}} an Expense

Description - +
- @for (member of splitMembers; track member) { } - +
@@ -71,37 +108,51 @@

{{addOrEdit}} an Expense

- -
-
- -