diff --git a/prisma/migrations/20260412120000_default_splits/migration.sql b/prisma/migrations/20260412120000_default_splits/migration.sql
new file mode 100644
index 00000000..6f2f64c8
--- /dev/null
+++ b/prisma/migrations/20260412120000_default_splits/migration.sql
@@ -0,0 +1,31 @@
+-- CreateTable
+CREATE TABLE "public"."GroupDefaultSplit" (
+ "groupId" INTEGER NOT NULL,
+ "splitType" "public"."SplitType" NOT NULL,
+ "shares" JSONB NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "GroupDefaultSplit_pkey" PRIMARY KEY ("groupId")
+);
+
+-- CreateTable
+CREATE TABLE "public"."FriendDefaultSplit" (
+ "userAId" INTEGER NOT NULL,
+ "userBId" INTEGER NOT NULL,
+ "splitType" "public"."SplitType" NOT NULL,
+ "shares" JSONB NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "FriendDefaultSplit_pkey" PRIMARY KEY ("userAId","userBId")
+);
+
+-- AddForeignKey
+ALTER TABLE "public"."GroupDefaultSplit" ADD CONSTRAINT "GroupDefaultSplit_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "public"."Group"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "public"."FriendDefaultSplit" ADD CONSTRAINT "FriendDefaultSplit_userAId_fkey" FOREIGN KEY ("userAId") REFERENCES "public"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "public"."FriendDefaultSplit" ADD CONSTRAINT "FriendDefaultSplit_userBId_fkey" FOREIGN KEY ("userBId") REFERENCES "public"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index d02a925c..03eee3c6 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -39,29 +39,31 @@ model Session {
}
model User {
- id Int @id @default(autoincrement())
- name String?
- email String? @unique
- emailVerified DateTime?
- image String?
- currency String @default("USD")
- preferredLanguage String @default("")
- bankingId String?
- obapiProviderId String?
- accounts Account[]
- friendBalances BalanceView[] @relation("FriendBalanceView")
- userBalances BalanceView[] @relation("UserBalanceView")
- cachedBankData CachedBankData[] @relation("UserCachedBankData")
- addedExpenses Expense[] @relation("AddedByUser")
- deletedExpenses Expense[] @relation("DeletedByUser")
- paidExpenses Expense[] @relation("PaidByUser")
- updatedExpenses Expense[] @relation("UpdatedByUser")
- expenseNotes ExpenseNote[]
- expenseParticipants ExpenseParticipant[]
- groups Group[]
- associatedGroups GroupUser[]
- sessions Session[]
- hiddenFriendIds Int[] @default([])
+ id Int @id @default(autoincrement())
+ name String?
+ email String? @unique
+ emailVerified DateTime?
+ image String?
+ currency String @default("USD")
+ preferredLanguage String @default("")
+ bankingId String?
+ obapiProviderId String?
+ accounts Account[]
+ friendBalances BalanceView[] @relation("FriendBalanceView")
+ userBalances BalanceView[] @relation("UserBalanceView")
+ cachedBankData CachedBankData[] @relation("UserCachedBankData")
+ addedExpenses Expense[] @relation("AddedByUser")
+ deletedExpenses Expense[] @relation("DeletedByUser")
+ paidExpenses Expense[] @relation("PaidByUser")
+ updatedExpenses Expense[] @relation("UpdatedByUser")
+ expenseNotes ExpenseNote[]
+ expenseParticipants ExpenseParticipant[]
+ groups Group[]
+ associatedGroups GroupUser[]
+ friendDefaultSplitsA FriendDefaultSplit[] @relation("FriendDefaultSplitUserA")
+ friendDefaultSplitsB FriendDefaultSplit[] @relation("FriendDefaultSplitUserB")
+ sessions Session[]
+ hiddenFriendIds Int[] @default([])
@@schema("public")
}
@@ -92,22 +94,48 @@ model Balance {
}
model Group {
- id Int @id @default(autoincrement())
- publicId String @unique
- name String
- image String?
- userId Int
- defaultCurrency String @default("USD")
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- splitwiseGroupId String? @unique
- simplifyDebts Boolean @default(false)
- archivedAt DateTime?
- expenses Expense[]
- createdBy User @relation(fields: [userId], references: [id], onDelete: Cascade)
- groupUsers GroupUser[]
- groupBalances BalanceView[]
+ id Int @id @default(autoincrement())
+ publicId String @unique
+ name String
+ image String?
+ userId Int
+ defaultCurrency String @default("USD")
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ splitwiseGroupId String? @unique
+ simplifyDebts Boolean @default(false)
+ archivedAt DateTime?
+ expenses Expense[]
+ createdBy User @relation(fields: [userId], references: [id], onDelete: Cascade)
+ groupUsers GroupUser[]
+ groupBalances BalanceView[]
+ groupDefaultSplit GroupDefaultSplit?
+
+ @@schema("public")
+}
+
+model GroupDefaultSplit {
+ groupId Int @id
+ splitType SplitType
+ shares Json
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
+
+ @@schema("public")
+}
+model FriendDefaultSplit {
+ userAId Int
+ userBId Int
+ splitType SplitType
+ shares Json
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ userA User @relation("FriendDefaultSplitUserA", fields: [userAId], references: [id], onDelete: Cascade)
+ userB User @relation("FriendDefaultSplitUserB", fields: [userBId], references: [id], onDelete: Cascade)
+
+ @@id([userAId, userBId])
@@schema("public")
}
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index 5c8ea0ef..1c88ac37 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -257,6 +257,8 @@
"group_info": {
"actions": "Actions",
"archive_group": "Archive group",
+ "configure_default_split": "Configure default split",
+ "default_split": "Default split",
"edit_group": "Edit group",
"archive_group_details": {
"can_archive": "This group will be archived and hidden from your main groups list. You can still access it later if needed.",
@@ -297,6 +299,8 @@
"total_expenses": "Total expenses"
},
"messages": {
+ "default_split_cleared": "Default split cleared",
+ "default_split_updated": "Default split updated",
"balances_recalculated": "Balances recalculated successfully",
"group_archived": "Group archived successfully",
"group_name_updated": "Updated group details"
@@ -330,6 +334,16 @@
"description": "Split Expenses with your friends for free",
"title": "SplitPro: Split Expenses with your friends for free"
},
+ "balances": {
+ "user_preferences": {
+ "title": "Preferences"
+ },
+ "default_split": {
+ "cleared": "Default split cleared",
+ "configure": "Default split",
+ "updated": "Default split updated"
+ }
+ },
"navigation": {
"account": "Account",
"activity": "Activity",
diff --git a/src/components/AddExpense/SplitTypeSection.tsx b/src/components/AddExpense/SplitTypeSection.tsx
index 26b6342e..bb64c331 100644
--- a/src/components/AddExpense/SplitTypeSection.tsx
+++ b/src/components/AddExpense/SplitTypeSection.tsx
@@ -10,7 +10,13 @@ import {
Plus,
X,
} from 'lucide-react';
-import React, { type ChangeEvent, type PropsWithChildren, useCallback, useMemo } from 'react';
+import React, {
+ type ChangeEvent,
+ type PropsWithChildren,
+ useCallback,
+ useEffect,
+ useMemo,
+} from 'react';
import { useTranslationWithUtils } from '~/hooks/useTranslationWithUtils';
import { type Participant, useAddExpenseStore } from '~/store/addStore';
@@ -66,7 +72,14 @@ const PayerRow = ({ p, isPaying }: { p: Participant; isPaying: boolean }) => {
);
};
-export const SplitExpenseForm: React.FC
{displayName(friendQuery.data)}
} - actions={{t('group_details.group_info.default_split')}
+{t('group_details.group_info.default_split')}
+{t('group_details.group_info.actions')}
-