Coder Social home page Coder Social logo

spliit-app / spliit Goto Github PK

View Code? Open in Web Editor NEW
744.0 10.0 138.0 742 KB

Free and Open Source Alternative to Splitwise. Share expenses with your friends and family.

Home Page: https://spliit.app

License: MIT License

JavaScript 1.42% CSS 0.64% TypeScript 97.19% Shell 0.32% Dockerfile 0.44%
nextjs react shadcn-ui tailwindcss splitwise tricount template vercel

spliit's People

Contributors

174n avatar acuteengle avatar ankitbahl avatar annalouisep avatar araffin avatar christopherjohnston avatar cufarvid avatar dcbr avatar deepgolani4 avatar gukkey avatar iqqmut avatar jantuomi avatar justcallmelarry avatar laszlomakk avatar magomzr avatar max-thecat avatar mertd avatar meta-boy avatar mpjk avatar owiber avatar raybb avatar sahilmhr avatar sashkent3 avatar sbehrends avatar scastiel avatar shynst avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spliit's Issues

REQUEST: Add Location of Transaction

Would be good to see the location of the transaction as you click on the expense for further details on a map. This could be by adding the location in Realtime using the devices GPS, or adding the location afterwards by providing a location.

Application error when filling out date field from keyboard

When filling the date using the keyboard, if more than 4 digits are inserted in the year field (obviously by mistake ;) ), the app crashes and shows the following error:

Application error: a client-side exception has occurred (see the browser console for more information).

The same happens if I type 0 as the first digit in any of the date fields.

This is from Firefox 121.0 (Ubuntu)

Thanks for the excellent app!

Paginate expenses

The expense list can be slow when displaying several hundreds of transactions. It would make sense to paginate transactions, i.e. either:

  1. Display the first X transactions by default, and then a “Show more” button
  2. Display an actual pagination, i.e. show page one by default and offer the option to go to a random page.

My preference is on option 1, but open to discussion.

Mark a group as favorite

Marking a group as favorite (stored locally) should make it appear at the top of the recent groups list.

Simplify Debts Function

Can we add the "simplify debts" function that splitwise has?

The way it works is if Bob owes Jack $10 and Jack owes Anna $10.

When simplify debts is toggled on, then we can simplify the debts where Bob just owes Anna $10. Pretty prime function that splitwise has.

Let me know if we need some UX work for this. Otherwise we just copy what splitwise has done 😊

Join group by URL in PWA mode

Maybe I'm missing something, but it seems that you cannot join groups (only create them) from an PWA app?
Installed the PWA on my iPhone and group page tells me to open a link with a group or create a new one, but I have no way of opening the link inside the PWA.

Maybe there could be a button which opens a box where you can paste the link or id of a group in order to get it to load in the PWA?

Donations

Hi! I'm loving the app so far and already managed to get a couple of friends on board.

I would like to contribute to the project not only with issues and feature requests, but also monetarily, in order to cover the hosting expenses and ensure the continuity of the project!

I haven't found any way of doing so, is there any? Otherwise I think adding a link on https://spliit.app/ or here on GitHub would be a good idea :)

Ability to archive groups when they’re settled up

Hello!

I've really enjoyed using spliit for the past few months. I originally found it because I was searching for an alternative to Splitwise once they started to only allow you to enter 3 expenses a day on a free-plan. I was even happier when I realized that this project was open source and I could help contribute! That being said, would love to help out!

My feature request is to some how make it easier to see which of the spliit groups are "settled up". On the "groups" page, all the groups keep changing order based on which one I viewed most recently and it's hard to remember which ones are "settled up" and which ones are still "awaiting reimbursements" or I am still adding expenses to.

I had a few different ideas:

  1. Separate sections on the "groups" page (i.e. "Starred", "Recent", "Settled up")
  2. Have an icon/indicator on the "group" card that just says "Settled up"

I also saw issue (#9) and while I think that it's nice that this could help clean up the db and save space, it's also nice to have a historical record of all past groups and those expenses so you can refer back to see which expenses were included in each group.

JSON export not working?

Clicking on export as JSON opens a new tab but then no download is started.

I tried it on Firefox and Safari, on both I got the same behavior.

The server responds with an HTTP 500.

Deduce category from expense title

Automating the category selection would allow users to input and categorize their expenses faster and more reliably. Imagine a user typing their expense title, and based on their input, a category gets selected for them.

Two approaches of implementing this could be:

  1. AI: Use the OpenAI integration added in #69. Prompt the latest stable turbo model for one of the available categories.
  2. Keywords: For each category, maintain a set of keywords. If a keyword is found, the mapped category will be selected.

Implementing the AI option would allow categorization of many more titles than the keyword approach. It would also increase the running cost of spliit. Starting out with an implementation of keyword based mapping will be more economical. However, usability may be limited considering the range of possible titles.

I would be happy to give either of these approaches a try, with AI being my preference. Are you interested in such a feature? If yes, which approach are you leaning towards?

Assign a category to expenses

Similarly to what Splitwise offers, the idea would be to be able to tell that an expense is related to a certain category.

Would be useful for importing expenses from Splitwise too (#22).

Ability to add attachment (pictures, receipts, etc) to expenses

As a user, I would like to be able to attach files to expenses.

Typical use cases:

  • Someone pays the bill at a restaurant, and immediately adds the picture of the receipt.
  • Someone books something online (accommodation, entertainment, etc) and adds a PDF to the expense.

On a mobile device, receipts can be added from the gallery, or from the camera directly (I believe the mobile operating systems can handle that case directly).

As I user, I want to:

  • be able to add an attachment when creating a new expense or when editing an existing one.
  • see existing attachments on an expense.
  • replace or delete existing attachments.

The first version would simply store the files directly on the same host the server is running.
On a technical level, ideally the directory/folder where the attachments are stored should be configurable (with an env variable).
Later, we could implement more storage mechanisms (FTP, SFTP, S3, etc.)

Feature Request: encryption at rest

First of all, thanks so much for making this app <3
I would like my shared expense data to be encrypted when stored in the database (either via your hosted implementation or my own).

I’ve had a newb scan of the code and can’t tell if the data stored is encrypted?

if it’s not, how about few fields as possible, perhaps the following?

  • Group.Name
  • Participant.Name
  • Expense.Title

With an optional passcode/phrase entered on group creation (or later) that encrypts and decrypts the above information for the viewing/interacting user.

The passcode/phrase is shared along with the group url (ideally separately 😅), and entered by a user when using the app (not sure how often though?).

I can certainly have a go at introducing this, however may take me awhile :)

History of a transaction

A way to see the history of who created a transaction, updated it, what was the update, etc.

Of course, since there's no user account, it might be a challenge to implement it right now. But maybe consider it as a feature request for the future.

Store time of expenses

Currently the time in all expense dates defaults to 00:00:00.000. This causes some awkward ordering in the expenses overview when adding expenses on the same day: expenses added earlier might appear after expenses added later.

An easy fix would be to store the time. Perhaps then it would also be appropriate to have a time picker for the expense date.

Bug: Image paths are too non-unique

Description

I was looking into if I could get minio working over s3 locally without too many issues (I couldn't, but I'll leave that for another time).

I did notice however that the path is just the filename as root in the bucket, which will start causing issues. I have already done some rudimentary tests and found that images do overwrite each other if they share the same name between expenses, and I believe that it also does between groups.

Steps to reproduce:

  1. Create an expense, add the image image.jpg to it.
  2. Look in the S3 bucket, you will see that image.jpg is in the root, so far so good.
  3. Add another expense to the group, add (preferably another) image called image.jpg to it
  4. Notice that there is only one image in the S3 bucket, named image.jpg.
  5. Do the same for a different expense in a different group, still only the one image left.

This is generally not great, as you might end up seeing the images belonging to someone else, and may have your own images overwritten as well.

Suggestion for solving the issue

I have a few suggestions on how to solve the issue, any or all might be used to alleviate the problem:

  • Add the group ID as a path prefix (example: NEFJA5--IBHFY3L99D0r4/image.jpg)
  • Use the ID of the image when uploading it to s3, storing the name in the table instead so that it can be shown in frontend if wanted/needed. This should allow it to be unique, otherwise I guess the database will run into issues
  • Add a timestamp (down to milliseconds) or other uniqueness as a prefix/suffix to the image (2024-01-29T19:48:39.961269--image.jpg / image--809ee38c-6da7-44c2-a34d-54a6802c658a.jpg

I would generally recommend the prefix of group_id, and also just renaming the image to the image ID.
This will allow you to not run into weird issues with filenames (unsure what they might be, but I guess you could use weird chars in filenames that cause issues somehow) but also easily remove all images of a group if it is deleted, both manually and via the CLI/API, even if you lose access to the database somehow.
This will also allow image paths not to be in risk of colliding.

EDIT: I see now that there was an update while I was testing :) will close this issue

Deploy docker image to docker hub

  • Decide on an action to trigger deployment (merge to a release branch, tag creation, manual run)
  • Validate version number is unique
  • @scastiel would have to create a docker hub account and store credentials in private variable that are accessible from the pipeline
  • [Optional] Have two release channels (nightly and official releases)
  • Push to docker hub
  • [Optional] Add image to GitHub releases

Starting balance

I would love to see an option for setting starting/carryover balances when making a new group. This would be particularly useful for folks migrating from other cost splitting apps. I am potentially interested in contributing this once I get up to speed on the structure of the project.

Store and display date of transaction

Would be great to have the ability to add the date of the transaction onto the Expense.
With this the homepage of the group should then be sorted by date.
This should also be broken down by months but still remain on the same page.
i.e

January 2024
3rd - Transition 1- £50
2nd - Transition 2 - $23
1st - Transition 3 - £45

Break

December 2023
31st - Transition - 4 £44
21st - Transition - 5 £123
4th - Transition - 6 £12

Break

November 2023

Make IDs Integers

Is there a reason all IDs are long alphanumeric strings? It makes DB queries and joins pretty inefficient, and will likely impact performance as the number of ids increase. I don't see a disadvantage to using integer IDs for most (if not all) primary key IDs
@scastiel

Tell the app who you are

The first time you open a group, you should be able to tell which participant you are, so that the app can display participants and expenses accordingly (e.g. selecting you as default when creating an expense).

Import from Splitwise

Splitwise offers an "Export as spreadsheet" feature. It would be useful to be able to import this data into Spliit for continuity of groups that were created before.

Splitwise exports CSV files with the following headers:

Date Description Category Cost Currency UserA UserB ...

Values in the User columns are calculated as (Paid - Owe). For example, if UserA paid $100 for an item whose cost was split evenly, UserA's entry would be $100 - $50 = $50 and UserB's would be $0 - $50 = -$50.

Date Description Category Cost Currency UserA UserB
2024-01-01 Something General 100.00 USD 50.00 -50.00

The final row is the total balance per user, which is the column sum for that user. There is no need to import this, but for the record, a positive value represents that the user "gets back" some amount, whereas a negative value represents that the user "owes" the amount.

This would require #6, at least the ability to split unevenly by dollar amount.

I'd suggest matching users by column name and error if a match isn't found; it's very easy to edit the CSV file if the name needs to be changed, no need to create new UI for it.

Development of iOS and Android Apps

I found this project after searching for alternatives to Splitwise. They've recently implemented a limitation that allows only four (4) expense submissions per day before requiring a paid upgrade, which I find unacceptable.

I'd be open to contributing to this project. My idea is to utilize React Native to maintain a single codebase for building apps for both iOS and Android platforms. We could use Native Wind to ensure consistent styling across both platforms.

Split unevenly

It would be nice to be able to split an expense unevenly:

  • by percentage (e.g. Alice pays 50%, Bob 25% and Charlie 25%)
  • by shares (e.g. Alice pays 2 share, Bob one and Charlie one)
  • by amount (e.g. Alice pays 20$, Bob pays 10$ and Charlie 5$)

Recurring expenses

hi!
really loving and appreciating this project.
i was wondering whether recurring expenses are a feature that you'd consider adding.
with that, transitioning from splitwise would be a no-brainer, for me and i'm assuming for others.
thanks so much

Feature Request: Multi-payer support

Allow an expense to have multiple payers. This would make it easier to split bills that are paid by multiple people in a single transaction. Currently, managing this scenario requires creating individual expenses for each payer, which can be a bit of a hassle. I am not aware of any other workaround for this scenario.

Attach other documents than images to expenses

Since #63 it is possible to attach images to expenses. Might be interested to attach other kind of documents (PDF, doc, video…). Uploading the file is not a problem (you can upload anything to S3), but to see the files, an Image tag is used. We’d need to cover other behavior for other files (with a preview, ability to download…).

Split calculation is wrong

Hi,

the split calculation seems to be wrong. I'm getting almost 60€ difference when comparing to other splitting apps or manual calculation.

All expenses are split evenly. It should result in 246.60€ to be paid from PersonA to PersonB.
The balances tab shows 299.58€ for some reason:

grafik

Suggested reimbursements shows the same amount.

The expenses:

{
    "id": "iOEPN60AFdBDcY5AxzG6i",
    "name": "Expenses",
    "currency": "",
    "expenses": [
        {
            "expenseDate": "2024-01-03T00:00:00.000Z",
            "title": "A",
            "category": {
                "grouping": "Food and Drink",
                "name": "Groceries"
            },
            "amount": 7400,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-03T00:00:00.000Z",
            "title": "B",
            "category": {
                "grouping": "Life",
                "name": "Insurance"
            },
            "amount": 6700,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-07T00:00:00.000Z",
            "title": "C",
            "category": {
                "grouping": "Home",
                "name": "Pets"
            },
            "amount": 5772,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-08T00:00:00.000Z",
            "title": "D",
            "category": {
                "grouping": "Food and Drink",
                "name": "Groceries"
            },
            "amount": 996,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-13T00:00:00.000Z",
            "title": "E",
            "category": {
                "grouping": "Home",
                "name": "Household Supplies"
            },
            "amount": 525,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-17T00:00:00.000Z",
            "title": "F",
            "category": {
                "grouping": "Food and Drink",
                "name": "Groceries"
            },
            "amount": 6634,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                },
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-17T00:00:00.000Z",
            "title": "G",
            "category": {
                "grouping": "Entertainment",
                "name": "Sports"
            },
            "amount": 16000,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-16T00:00:00.000Z",
            "title": "H",
            "category": {
                "grouping": "Food and Drink",
                "name": "Dining Out"
            },
            "amount": 5500,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-12T00:00:00.000Z",
            "title": "I",
            "category": {
                "grouping": "Food and Drink",
                "name": "Food and Drink"
            },
            "amount": 1800,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-19T00:00:00.000Z",
            "title": "J",
            "category": {
                "grouping": "Transportation",
                "name": "Hotel"
            },
            "amount": 19000,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-19T00:00:00.000Z",
            "title": "K",
            "category": {
                "grouping": "Uncategorized",
                "name": "General"
            },
            "amount": 16000,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-20T00:00:00.000Z",
            "title": "L",
            "category": {
                "grouping": "Food and Drink",
                "name": "Dining Out"
            },
            "amount": 3800,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-20T00:00:00.000Z",
            "title": "M",
            "category": {
                "grouping": "Transportation",
                "name": "Parking"
            },
            "amount": 500,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-20T00:00:00.000Z",
            "title": "N",
            "category": {
                "grouping": "Food and Drink",
                "name": "Food and Drink"
            },
            "amount": 700,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-20T00:00:00.000Z",
            "title": "O",
            "category": {
                "grouping": "Food and Drink",
                "name": "Groceries"
            },
            "amount": 1498,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-20T00:00:00.000Z",
            "title": "P",
            "category": {
                "grouping": "Uncategorized",
                "name": "General"
            },
            "amount": 10600,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-21T00:00:00.000Z",
            "title": "Q",
            "category": {
                "grouping": "Food and Drink",
                "name": "Dining Out"
            },
            "amount": 3500,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-21T00:00:00.000Z",
            "title": "R",
            "category": {
                "grouping": "Transportation",
                "name": "Parking"
            },
            "amount": 400,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-21T00:00:00.000Z",
            "title": "S",
            "category": {
                "grouping": "Food and Drink",
                "name": "Dining Out"
            },
            "amount": 2000,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-23T00:00:00.000Z",
            "title": "T",
            "category": {
                "grouping": "Home",
                "name": "Maintenance"
            },
            "amount": 32625,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-24T00:00:00.000Z",
            "title": "U",
            "category": {
                "grouping": "Food and Drink",
                "name": "Food and Drink"
            },
            "amount": 1600,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-22T00:00:00.000Z",
            "title": "V",
            "category": {
                "grouping": "Food and Drink",
                "name": "Food and Drink"
            },
            "amount": 1920,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-17T00:00:00.000Z",
            "title": "W",
            "category": {
                "grouping": "Food and Drink",
                "name": "Groceries"
            },
            "amount": 1240,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-17T00:00:00.000Z",
            "title": "X",
            "category": {
                "grouping": "Entertainment",
                "name": "Sports"
            },
            "amount": 14040,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-28T00:00:00.000Z",
            "title": "Y",
            "category": {
                "grouping": "Food and Drink",
                "name": "Food and Drink"
            },
            "amount": 695,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-27T00:00:00.000Z",
            "title": "Z",
            "category": {
                "grouping": "Food and Drink",
                "name": "Groceries"
            },
            "amount": 7816,
            "paidById": "Slo8FjtEEdkP2p6NqN6OB",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-02-01T00:00:00.000Z",
            "title": "1",
            "category": {
                "grouping": "Food and Drink",
                "name": "Food and Drink"
            },
            "amount": 1580,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 1
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 1
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-05T00:00:00.000Z",
            "title": "2",
            "category": {
                "grouping": "Food and Drink",
                "name": "Groceries"
            },
            "amount": 698,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        },
        {
            "expenseDate": "2024-01-08T00:00:00.000Z",
            "title": "3",
            "category": {
                "grouping": "Home",
                "name": "Household Supplies"
            },
            "amount": 2091,
            "paidById": "A-ieqXKmKJZXu3XJpGLo4",
            "paidFor": [
                {
                    "participantId": "A-ieqXKmKJZXu3XJpGLo4",
                    "shares": 100
                },
                {
                    "participantId": "Slo8FjtEEdkP2p6NqN6OB",
                    "shares": 100
                }
            ],
            "isReimbursement": false,
            "splitMode": "EVENLY"
        }
    ],
    "participants": [
        {
            "id": "A-ieqXKmKJZXu3XJpGLo4",
            "name": "PersonA"
        },
        {
            "id": "Slo8FjtEEdkP2p6NqN6OB",
            "name": "PersonB"
        }
    ]
}

Docker container version

Hello,

I apologise if this is the wrong place to post this, but I saw this announced on Reddit and I'm very excited to use it. Thank you so much for creating it!

I was wondering whether it would be a lot to ask for a docker container version? It might be easier for a lot of people rather than trying to set up a database and app separately.

Thank you so much!

Search for expenses

I personally need to look for old expenses often. One of the annoyingly premium features of Splitwise is searching for expenses - it would be nice to have some sort of search on the expenses list page.

Export group expenses as JSON

One thing I liked about splitwise is the ability to download a json file of all the expenses. It'd be nice to have this feature here.

Search fails when enterering special characters

This issue occurs because the special characters are not properly escaped when used in a regular expression pattern.

Steps to reproduce:

  1. Enter a special character like ( or [ in the expenses search field.
  2. The application will crash.

Group deletion

HI, first of all, thanks for this app, I've been using it for a while and works great!

I have two questions related to group deletion:

  1. How can I delete a group? I couldn't find it anywhere on the UI.
  2. How long are groups stored for? That is, if for example I didn't update a group for months, will it be automatically deleted eventually?

Translations of the website

Hi,

not an issue, but is there an available way to contribute to translate the website in other languages ? I'm French and I'd love to contribute to get the website in a French translation :)
Thanks,
cress

Default participants and split

With the current defaults (no participant checked), at least one interaction with the participant list is necessary to be able to save an expense. I have to "select all" participants almost every time.

Considering there is no use case where saving without any interactions is possible, having the expense split evenly across all group members may be a better default.

Home assistant add-on

[edited to better reflect the requirement]

When a branch is merged to main, could this be triggered a workflow to generate a versioned release archive? This will aid local (and potentially homeassistant) deployments.

Also, great that this has been moved into its own organisation - lends itself well to keeping related repositories together!

RFC: Optimize Spliit for self-hosting

As Spliit is open source, I think it would be nice if it was easy to deploy it anywhere easily.

This means:

  • Having a bit of documentation to explain the steps to follow.
  • Put all the branding content out of this repo (landing page, footer…) to offer a more neutral application by default.

Curious to know if anyone has this need or suggestions about implementation. Feel free to give your two cents here 😉

Store images somewhere else than S3

Since #63, users can attach images to expenses, but they can be stored only on S3. If someone has the need to store images somewhere else (locally, on an FTP server…), feel free to comment here with your need and we’ll see how to implement it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.