From fd4a25376b216362b5011fad256c713e084fbf03 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Tue, 9 Sep 2025 18:58:04 +0200 Subject: [PATCH] Enhance Cospend with debt breakdown and predefined users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add EnhancedBalance component with integrated single-user debt display - Create DebtBreakdown component for multi-user debt overview - Add predefined users configuration (alexander, anna) - Implement personal + equal split payment method - Add profile pictures throughout payment interfaces - Integrate debt information with profile pictures in balance view - Auto-hide debt breakdown when single user (shows in balance instead) - Support both manual and predefined user management modes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/lib/components/DebtBreakdown.svelte | 246 +++++++++++++ src/lib/components/EnhancedBalance.svelte | 334 ++++++++++++++++++ src/lib/components/PaymentModal.svelte | 2 + src/lib/config/users.ts | 16 + src/models/Payment.ts | 4 +- src/models/PaymentSplit.ts | 5 + src/routes/api/cospend/debts/+server.ts | 110 ++++++ src/routes/api/cospend/payments/+server.ts | 16 +- .../api/cospend/payments/[id]/+server.ts | 3 +- src/routes/cospend/+page.svelte | 173 +++------ src/routes/cospend/payments/+page.svelte | 2 + src/routes/cospend/payments/add/+page.svelte | 256 ++++++++++++-- .../cospend/payments/view/[id]/+page.svelte | 2 + 13 files changed, 1019 insertions(+), 150 deletions(-) create mode 100644 src/lib/components/DebtBreakdown.svelte create mode 100644 src/lib/components/EnhancedBalance.svelte create mode 100644 src/lib/config/users.ts create mode 100644 src/routes/api/cospend/debts/+server.ts diff --git a/src/lib/components/DebtBreakdown.svelte b/src/lib/components/DebtBreakdown.svelte new file mode 100644 index 0000000..1885c46 --- /dev/null +++ b/src/lib/components/DebtBreakdown.svelte @@ -0,0 +1,246 @@ + + +{#if !shouldHide} +
+

Debt Overview

+ + {#if loading} +
Loading debt breakdown...
+ {:else if error} +
Error: {error}
+ {:else} +
+ {#if debtData.whoOwesMe.length > 0} +
+

Who owes you

+
+ Total: {formatCurrency(debtData.totalOwedToMe)} +
+ +
+ {#each debtData.whoOwesMe as debt} +
+
+ +
+ {debt.username} + {formatCurrency(debt.netAmount)} +
+
+
+ {debt.transactions.length} transaction{debt.transactions.length !== 1 ? 's' : ''} +
+
+ {/each} +
+
+ {/if} + + {#if debtData.whoIOwe.length > 0} +
+

You owe

+
+ Total: {formatCurrency(debtData.totalIOwe)} +
+ +
+ {#each debtData.whoIOwe as debt} +
+
+ +
+ {debt.username} + {formatCurrency(debt.netAmount)} +
+
+
+ {debt.transactions.length} transaction{debt.transactions.length !== 1 ? 's' : ''} +
+
+ {/each} +
+
+ {/if} +
+ {/if} +
+{/if} + + \ No newline at end of file diff --git a/src/lib/components/EnhancedBalance.svelte b/src/lib/components/EnhancedBalance.svelte new file mode 100644 index 0000000..04abd00 --- /dev/null +++ b/src/lib/components/EnhancedBalance.svelte @@ -0,0 +1,334 @@ + + +
+
0} + class:enhanced={shouldShowIntegratedView}> + + {#if loading} +
+

Your Balance

+
Loading...
+
+ {:else if error} +

Your Balance

+
Error: {error}
+ {:else if shouldShowIntegratedView} + +

Your Balance

+
+
+ {#if balance.netBalance < 0} + +{formatCurrency(balance.netBalance)} + You are owed + {:else if balance.netBalance > 0} + -{formatCurrency(balance.netBalance)} + You owe + {:else} + CHF 0.00 + You're all even + {/if} +
+ +
+
+ {#if singleDebtUser && singleDebtUser.user} + + + + {:else} +
Debug: No singleDebtUser data
+ {/if} +
+
+ {#if singleDebtUser && singleDebtUser.user && singleDebtUser.user.transactions} + {singleDebtUser.user.transactions.length} transaction{singleDebtUser.user.transactions.length !== 1 ? 's' : ''} + {/if} +
+
+
+ {:else} + +

Your Balance

+
+ {#if balance.netBalance < 0} + +{formatCurrency(balance.netBalance)} + You are owed + {:else if balance.netBalance > 0} + -{formatCurrency(balance.netBalance)} + You owe + {:else} + CHF 0.00 + You're all even + {/if} +
+ {/if} +
+
+ + \ No newline at end of file diff --git a/src/lib/components/PaymentModal.svelte b/src/lib/components/PaymentModal.svelte index f8a8056..0af5747 100644 --- a/src/lib/components/PaymentModal.svelte +++ b/src/lib/components/PaymentModal.svelte @@ -79,6 +79,8 @@ return `Split equally among ${payment.splits.length} people`; } else if (payment.splitMethod === 'full') { return `Paid in full by ${payment.paidBy}`; + } else if (payment.splitMethod === 'personal_equal') { + return `Personal amounts + equal split among ${payment.splits.length} people`; } else { return `Custom split among ${payment.splits.length} people`; } diff --git a/src/lib/config/users.ts b/src/lib/config/users.ts new file mode 100644 index 0000000..3dde59a --- /dev/null +++ b/src/lib/config/users.ts @@ -0,0 +1,16 @@ +// Predefined users configuration for Cospend +// When this array has exactly 2 users, the system will always split between them +// For more users, manual selection is allowed + +export const PREDEFINED_USERS = [ + 'alexander', + 'anna' +]; + +export function isPredefinedUsersMode(): boolean { + return PREDEFINED_USERS.length === 2; +} + +export function getAvailableUsers(): string[] { + return [...PREDEFINED_USERS]; +} \ No newline at end of file diff --git a/src/models/Payment.ts b/src/models/Payment.ts index cc47cd0..44592ad 100644 --- a/src/models/Payment.ts +++ b/src/models/Payment.ts @@ -10,7 +10,7 @@ export interface IPayment { date: Date; image?: string; // path to uploaded image category: 'groceries' | 'shopping' | 'travel' | 'restaurant' | 'utilities' | 'fun'; - splitMethod: 'equal' | 'full' | 'proportional'; + splitMethod: 'equal' | 'full' | 'proportional' | 'personal_equal'; createdBy: string; // username/nickname of the person who created the payment createdAt?: Date; updatedAt?: Date; @@ -61,7 +61,7 @@ const PaymentSchema = new mongoose.Schema( splitMethod: { type: String, required: true, - enum: ['equal', 'full', 'proportional'], + enum: ['equal', 'full', 'proportional', 'personal_equal'], default: 'equal' }, createdBy: { diff --git a/src/models/PaymentSplit.ts b/src/models/PaymentSplit.ts index d677abc..221ba91 100644 --- a/src/models/PaymentSplit.ts +++ b/src/models/PaymentSplit.ts @@ -6,6 +6,7 @@ export interface IPaymentSplit { username: string; // username/nickname of the person who owes/is owed amount: number; // amount this person owes (positive) or is owed (negative) proportion?: number; // for proportional splits, the proportion (e.g., 0.5 for 50%) + personalAmount?: number; // for personal_equal splits, the personal portion for this user settled: boolean; // whether this split has been settled settledAt?: Date; createdAt?: Date; @@ -33,6 +34,10 @@ const PaymentSplitSchema = new mongoose.Schema( min: 0, max: 1 }, + personalAmount: { + type: Number, + min: 0 + }, settled: { type: Boolean, default: false diff --git a/src/routes/api/cospend/debts/+server.ts b/src/routes/api/cospend/debts/+server.ts new file mode 100644 index 0000000..1741b8f --- /dev/null +++ b/src/routes/api/cospend/debts/+server.ts @@ -0,0 +1,110 @@ +import type { RequestHandler } from '@sveltejs/kit'; +import { PaymentSplit } from '../../../../models/PaymentSplit'; +import { Payment } from '../../../../models/Payment'; +import { dbConnect, dbDisconnect } from '../../../../utils/db'; +import { error, json } from '@sveltejs/kit'; + +interface DebtSummary { + username: string; + netAmount: number; // positive = you owe them, negative = they owe you + transactions: { + paymentId: string; + title: string; + amount: number; + date: Date; + category: string; + }[]; +} + +export const GET: RequestHandler = async ({ locals }) => { + const auth = await locals.auth(); + if (!auth || !auth.user?.nickname) { + throw error(401, 'Not logged in'); + } + + const currentUser = auth.user.nickname; + + await dbConnect(); + + try { + // Get all splits for the current user + const userSplits = await PaymentSplit.find({ username: currentUser }) + .populate('paymentId') + .lean(); + + // Get all other users who have splits with payments involving the current user + const paymentIds = userSplits.map(split => split.paymentId._id); + const allRelatedSplits = await PaymentSplit.find({ + paymentId: { $in: paymentIds }, + username: { $ne: currentUser } + }) + .populate('paymentId') + .lean(); + + // Group debts by user + const debtsByUser = new Map(); + + // Process current user's splits to understand what they owe/are owed + for (const split of userSplits) { + const payment = split.paymentId as any; + if (!payment) continue; + + // Find other participants in this payment + const otherSplits = allRelatedSplits.filter(s => + s.paymentId._id.toString() === split.paymentId._id.toString() + ); + + for (const otherSplit of otherSplits) { + const otherUser = otherSplit.username; + + if (!debtsByUser.has(otherUser)) { + debtsByUser.set(otherUser, { + username: otherUser, + netAmount: 0, + transactions: [] + }); + } + + const debt = debtsByUser.get(otherUser)!; + + // Current user's amount: positive = they owe, negative = they are owed + // We want to show net between the two users + debt.netAmount += split.amount; + + debt.transactions.push({ + paymentId: payment._id.toString(), + title: payment.title, + amount: split.amount, + date: payment.date, + category: payment.category + }); + } + } + + // Convert map to array and sort by absolute amount (largest debts first) + const debtSummaries = Array.from(debtsByUser.values()) + .filter(debt => Math.abs(debt.netAmount) > 0.01) // Filter out tiny amounts + .sort((a, b) => Math.abs(b.netAmount) - Math.abs(a.netAmount)); + + // Separate into who owes you vs who you owe + const whoOwesMe = debtSummaries.filter(debt => debt.netAmount < 0).map(debt => ({ + ...debt, + netAmount: Math.abs(debt.netAmount) // Make positive for display + })); + + const whoIOwe = debtSummaries.filter(debt => debt.netAmount > 0); + + return json({ + whoOwesMe, + whoIOwe, + totalOwedToMe: whoOwesMe.reduce((sum, debt) => sum + debt.netAmount, 0), + totalIOwe: whoIOwe.reduce((sum, debt) => sum + debt.netAmount, 0) + }); + + } catch (e) { + console.error('Error calculating debt breakdown:', e); + throw error(500, 'Failed to calculate debt breakdown'); + } finally { + await dbDisconnect(); + } +}; \ No newline at end of file diff --git a/src/routes/api/cospend/payments/+server.ts b/src/routes/api/cospend/payments/+server.ts index 7e5fa3d..e6fca34 100644 --- a/src/routes/api/cospend/payments/+server.ts +++ b/src/routes/api/cospend/payments/+server.ts @@ -48,7 +48,7 @@ export const POST: RequestHandler = async ({ request, locals }) => { throw error(400, 'Amount must be positive'); } - if (!['equal', 'full', 'proportional'].includes(splitMethod)) { + if (!['equal', 'full', 'proportional', 'personal_equal'].includes(splitMethod)) { throw error(400, 'Invalid split method'); } @@ -56,6 +56,17 @@ export const POST: RequestHandler = async ({ request, locals }) => { throw error(400, 'Invalid category'); } + // Validate personal + equal split method + if (splitMethod === 'personal_equal' && splits) { + const totalPersonal = splits.reduce((sum: number, split: any) => { + return sum + (parseFloat(split.personalAmount) || 0); + }, 0); + + if (totalPersonal > amount) { + throw error(400, 'Personal amounts cannot exceed total payment amount'); + } + } + await dbConnect(); try { @@ -77,7 +88,8 @@ export const POST: RequestHandler = async ({ request, locals }) => { paymentId: payment._id, username: split.username, amount: split.amount, - proportion: split.proportion + proportion: split.proportion, + personalAmount: split.personalAmount }); }); diff --git a/src/routes/api/cospend/payments/[id]/+server.ts b/src/routes/api/cospend/payments/[id]/+server.ts index a6752c8..f461286 100644 --- a/src/routes/api/cospend/payments/[id]/+server.ts +++ b/src/routes/api/cospend/payments/[id]/+server.ts @@ -75,7 +75,8 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => { paymentId: id, username: split.username, amount: split.amount, - proportion: split.proportion + proportion: split.proportion, + personalAmount: split.personalAmount }); }); diff --git a/src/routes/cospend/+page.svelte b/src/routes/cospend/+page.svelte index d4201c5..29cc617 100644 --- a/src/routes/cospend/+page.svelte +++ b/src/routes/cospend/+page.svelte @@ -3,6 +3,8 @@ import { page } from '$app/stores'; import { pushState } from '$app/navigation'; import ProfilePicture from '$lib/components/ProfilePicture.svelte'; + import EnhancedBalance from '$lib/components/EnhancedBalance.svelte'; + import DebtBreakdown from '$lib/components/DebtBreakdown.svelte'; import { getCategoryEmoji, getCategoryName } from '$lib/utils/categories'; export let data; // Used by the layout for session data @@ -67,83 +69,67 @@

Track and split expenses with your friends and family

+ + + + + + {#if loading} -
Loading your balance...
+
Loading recent activity...
{:else if error}
Error: {error}
- {:else} -
-
0}> -

Your Balance

-
- {#if balance.netBalance < 0} - +{formatCurrency(balance.netBalance)} - You are owed - {:else if balance.netBalance > 0} - -{formatCurrency(balance.netBalance)} - You owe - {:else} - CHF 0.00 - You're all even - {/if} -
-
-
- - - - {#if balance.recentSplits && balance.recentSplits.length > 0} -
-

Recent Activity

-
- {#each balance.recentSplits as split} -
-
- - handlePaymentClick(split.paymentId?._id, e)} - > -
- - {/if} @@ -182,52 +168,6 @@ border-radius: 0.5rem; } - .balance-cards { - display: flex; - justify-content: center; - margin-bottom: 2rem; - } - - .balance-card { - background: white; - padding: 2rem; - border-radius: 0.75rem; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - text-align: center; - min-width: 300px; - } - - .balance-card.net-balance { - background: linear-gradient(135deg, #f5f5f5, #e8e8e8); - } - - .balance-card.net-balance.positive { - background: linear-gradient(135deg, #e8f5e8, #d4edda); - } - - .balance-card.net-balance.negative { - background: linear-gradient(135deg, #ffeaea, #f8d7da); - } - - .balance-card h3 { - margin-bottom: 1rem; - color: #555; - font-size: 1.1rem; - } - - .amount { - font-size: 2rem; - font-weight: bold; - margin-bottom: 0.5rem; - } - - .amount small { - display: block; - font-size: 0.9rem; - font-weight: normal; - color: #666; - margin-top: 0.5rem; - } .positive { color: #2e7d32; @@ -449,11 +389,6 @@ padding: 1rem; } - .balance-card { - min-width: unset; - width: 100%; - } - .actions { flex-direction: column; align-items: center; diff --git a/src/routes/cospend/payments/+page.svelte b/src/routes/cospend/payments/+page.svelte index d012aa3..b85cfa5 100644 --- a/src/routes/cospend/payments/+page.svelte +++ b/src/routes/cospend/payments/+page.svelte @@ -93,6 +93,8 @@ return `Split equally among ${payment.splits.length} people`; } else if (payment.splitMethod === 'full') { return `Paid in full by ${payment.paidBy}`; + } else if (payment.splitMethod === 'personal_equal') { + return `Personal amounts + equal split among ${payment.splits.length} people`; } else { return `Custom split among ${payment.splits.length} people`; } diff --git a/src/routes/cospend/payments/add/+page.svelte b/src/routes/cospend/payments/add/+page.svelte index 96fc6eb..d938f0b 100644 --- a/src/routes/cospend/payments/add/+page.svelte +++ b/src/routes/cospend/payments/add/+page.svelte @@ -2,6 +2,8 @@ import { onMount } from 'svelte'; import { goto } from '$app/navigation'; import { getCategoryOptions } from '$lib/utils/categories'; + import { PREDEFINED_USERS, isPredefinedUsersMode } from '$lib/config/users'; + import ProfilePicture from '$lib/components/ProfilePicture.svelte'; export let data; @@ -18,17 +20,34 @@ let imageFile = null; let imagePreview = ''; - let users = [data.session?.user?.nickname || '']; + let users = []; let newUser = ''; let splitAmounts = {}; + let personalAmounts = {}; let loading = false; let error = null; + let personalTotalError = false; + let predefinedMode = isPredefinedUsersMode(); $: categoryOptions = getCategoryOptions(); onMount(() => { - if (data.session?.user?.nickname) { - addSplitForUser(data.session.user.nickname); + if (predefinedMode) { + // Use predefined users and always split between them + users = [...PREDEFINED_USERS]; + users.forEach(user => addSplitForUser(user)); + // Default to current user as payer if they're in the predefined list + if (data.session?.user?.nickname && PREDEFINED_USERS.includes(data.session.user.nickname)) { + formData.paidBy = data.session.user.nickname; + } else { + formData.paidBy = PREDEFINED_USERS[0]; + } + } else { + // Original behavior for manual user management + if (data.session?.user?.nickname) { + users = [data.session.user.nickname]; + addSplitForUser(data.session.user.nickname); + } } }); @@ -61,6 +80,8 @@ } function addUser() { + if (predefinedMode) return; // No adding users in predefined mode + if (newUser.trim() && !users.includes(newUser.trim())) { users = [...users, newUser.trim()]; addSplitForUser(newUser.trim()); @@ -69,6 +90,8 @@ } function removeUser(userToRemove) { + if (predefinedMode) return; // No removing users in predefined mode + if (users.length > 1 && userToRemove !== data.session.user.nickname) { users = users.filter(u => u !== userToRemove); delete splitAmounts[userToRemove]; @@ -114,11 +137,42 @@ splitAmounts = { ...splitAmounts }; } + function calculatePersonalEqualSplit() { + if (!formData.amount || users.length === 0) return; + + const totalAmount = parseFloat(formData.amount); + + // Calculate total personal amounts + const totalPersonal = users.reduce((sum, user) => { + return sum + (parseFloat(personalAmounts[user]) || 0); + }, 0); + + // Remaining amount to be split equally + const remainder = Math.max(0, totalAmount - totalPersonal); + const equalShare = remainder / users.length; + + users.forEach(user => { + const personalAmount = parseFloat(personalAmounts[user]) || 0; + const totalOwed = personalAmount + equalShare; + + if (user === formData.paidBy) { + // Person who paid gets back what others owe minus what they personally used + splitAmounts[user] = totalOwed - totalAmount; + } else { + // Others owe their personal amount + equal share + splitAmounts[user] = totalOwed; + } + }); + splitAmounts = { ...splitAmounts }; + } + function handleSplitMethodChange() { if (formData.splitMethod === 'equal') { calculateEqualSplits(); } else if (formData.splitMethod === 'full') { calculateFullPayment(); + } else if (formData.splitMethod === 'personal_equal') { + calculatePersonalEqualSplit(); } } @@ -152,6 +206,17 @@ return; } + // Validate personal amounts for personal_equal split + if (formData.splitMethod === 'personal_equal') { + const totalPersonal = Object.values(personalAmounts).reduce((sum, val) => sum + (parseFloat(val) || 0), 0); + const totalAmount = parseFloat(formData.amount); + + if (totalPersonal > totalAmount) { + error = 'Personal amounts cannot exceed the total payment amount'; + return; + } + } + if (users.length === 0) { error = 'Please add at least one user to split with'; return; @@ -169,7 +234,8 @@ const splits = users.map(user => ({ username: user, amount: splitAmounts[user] || 0, - proportion: formData.splitMethod === 'proportional' ? (splitAmounts[user] || 0) / parseFloat(formData.amount) : undefined + proportion: formData.splitMethod === 'proportional' ? (splitAmounts[user] || 0) / parseFloat(formData.amount) : undefined, + personalAmount: formData.splitMethod === 'personal_equal' ? (parseFloat(personalAmounts[user]) || 0) : undefined })); const payload = { @@ -205,6 +271,17 @@ $: if (formData.amount && formData.splitMethod && formData.paidBy) { handleSplitMethodChange(); } + + // Validate and recalculate when personal amounts change + $: if (formData.splitMethod === 'personal_equal' && personalAmounts && formData.amount) { + const totalPersonal = Object.values(personalAmounts).reduce((sum, val) => sum + (parseFloat(val) || 0), 0); + const totalAmount = parseFloat(formData.amount); + personalTotalError = totalPersonal > totalAmount; + + if (!personalTotalError) { + calculatePersonalEqualSplit(); + } + } @@ -323,28 +400,46 @@

Split Between Users

-
- {#each users as user} -
- {user} - {#if user !== data.session.user.nickname} - - {/if} + {#if predefinedMode} +
+

Splitting between predefined users:

+
+ {#each users as user} +
+ + {user} + {#if user === data.session?.user?.nickname} + You + {/if} +
+ {/each}
- {/each} -
+
+ {:else} +
+ {#each users as user} +
+ + {user} + {#if user !== data.session.user.nickname} + + {/if} +
+ {/each} +
-
- e.key === 'Enter' && (e.preventDefault(), addUser())} - /> - -
+
+ e.key === 'Enter' && (e.preventDefault(), addUser())} + /> + +
+ {/if}
@@ -353,7 +448,11 @@
+
{/if} + {#if formData.splitMethod === 'personal_equal'} +
+

Personal Amounts

+

Enter personal amounts for each user. The remainder will be split equally.

+ {#each users as user} +
+ + +
+ {/each} + {#if formData.amount} +
+ Total Personal: CHF {Object.values(personalAmounts).reduce((sum, val) => sum + (parseFloat(val) || 0), 0).toFixed(2)} + Remainder to Split: CHF {Math.max(0, parseFloat(formData.amount) - Object.values(personalAmounts).reduce((sum, val) => sum + (parseFloat(val) || 0), 0)).toFixed(2)} + {#if personalTotalError} +
⚠️ Personal amounts exceed total payment amount!
+ {/if} +
+ {/if} +
+ {/if} + {#if Object.keys(splitAmounts).length > 0}

Split Preview

{#each users as user}
- {user} +
+ + {user} +
0}> {#if splitAmounts[user] > 0} owes CHF {splitAmounts[user].toFixed(2)} @@ -564,6 +694,37 @@ border-radius: 1rem; } + .user-item.with-profile { + gap: 0.75rem; + } + + .user-item .username { + font-weight: 500; + } + + .you-badge { + background-color: #1976d2; + color: white; + padding: 0.125rem 0.5rem; + border-radius: 1rem; + font-size: 0.75rem; + font-weight: 500; + } + + .predefined-users { + background-color: #f8f9fa; + padding: 1rem; + border-radius: 0.5rem; + border: 1px solid #e9ecef; + } + + .predefined-note { + margin: 0 0 1rem 0; + color: #666; + font-size: 0.9rem; + font-style: italic; + } + .remove-user { background-color: #d32f2f; color: white; @@ -652,6 +813,12 @@ margin-bottom: 0.5rem; } + .split-user { + display: flex; + align-items: center; + gap: 0.5rem; + } + .amount.positive { color: #2e7d32; font-weight: 500; @@ -709,6 +876,43 @@ background-color: #e8e8e8; } + .personal-splits { + margin-top: 1rem; + } + + .personal-splits .description { + color: #666; + font-size: 0.9rem; + margin-bottom: 1rem; + font-style: italic; + } + + .remainder-info { + margin-top: 1rem; + padding: 1rem; + background-color: #f8f9fa; + border-radius: 0.5rem; + border: 1px solid #e9ecef; + } + + .remainder-info.error { + background-color: #fff5f5; + border-color: #fed7d7; + } + + .remainder-info span { + display: block; + margin-bottom: 0.5rem; + font-weight: 500; + } + + .error-message { + color: #d32f2f; + font-weight: 600; + margin-top: 0.5rem; + font-size: 0.9rem; + } + @media (max-width: 600px) { .add-payment { padding: 1rem; diff --git a/src/routes/cospend/payments/view/[id]/+page.svelte b/src/routes/cospend/payments/view/[id]/+page.svelte index 269ad66..814a47a 100644 --- a/src/routes/cospend/payments/view/[id]/+page.svelte +++ b/src/routes/cospend/payments/view/[id]/+page.svelte @@ -47,6 +47,8 @@ return `Split equally among ${payment.splits.length} people`; } else if (payment.splitMethod === 'full') { return `Paid in full by ${payment.paidBy}`; + } else if (payment.splitMethod === 'personal_equal') { + return `Personal amounts + equal split among ${payment.splits.length} people`; } else { return `Custom split among ${payment.splits.length} people`; }