diff --git a/src/app/shared/page.tsx b/src/app/shared/page.tsx index 186447e..3d7787c 100644 --- a/src/app/shared/page.tsx +++ b/src/app/shared/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useRef, useEffect } from "react"; +import { Fragment, useState, useRef, useEffect } from "react"; import { useSharedTransactions, useParticipantBalances, @@ -16,6 +16,7 @@ import { } from "@/lib/hooks"; import type { SharedTransactionRow } from "@/lib/queries"; import { EditTransactionModal } from "@/components/edit-transaction-modal"; +import { OrderDetails } from "@/components/order-details"; import { formatCategory } from "@/lib/categories"; import { CATEGORY_COLORS } from "@/lib/category-colors"; @@ -370,6 +371,10 @@ export default function SharedPage() { const [paymentModal, setPaymentModal] = useState<{ id: number; name: string; balance: number } | null>(null); const [showHistory, setShowHistory] = useState(null); const [editModal, setEditModal] = useState(null); + // Receipt expansion, same pattern as the transactions page. The shared + // viewer is a split participant, so /api/transactions/[id]/order + // authorises them — the item list is part of what was shared. + const [expanded, setExpanded] = useState>(new Set()); return (
@@ -543,11 +548,28 @@ export default function SharedPage() { {(transactions as SharedTransactionRow[]).map((tx) => { const splits = Array.isArray(tx.splits) ? tx.splits : []; return ( - + + {formatDate(tx.transaction_date)} {formatDate(tx.created_at)} -

{tx.effective_merchant || tx.description}

+
+ {tx.order_platform && ( + + )} +

{tx.effective_merchant || tx.description}

+
{tx.effective_merchant && (

{tx.description}

)} @@ -615,6 +637,14 @@ export default function SharedPage() { + {expanded.has(tx.id) && ( + + + + + + )} +
); })} diff --git a/src/lib/queries.ts b/src/lib/queries.ts index d137b76..52a67af 100644 --- a/src/lib/queries.ts +++ b/src/lib/queries.ts @@ -866,6 +866,11 @@ export async function getSharedTransactions(ownerId: number, tagIds?: number[], COALESCE(t.owner_id, s.owner_id) as owner_id, p_owner.name as owner_name, COALESCE(src.created_at, t.created_at) as created_at, + -- Receipt flag, same LATERAL the transactions page uses: the shared + -- viewer is a split participant, so the order API authorises them — + -- without the flag here the disclosure arrow (and the item list behind + -- it) existed only on the owner's page. + order_ctx.platform as order_platform, json_agg(json_build_object( 'split_id', ts.id, 'participant_id', ts.participant_id, @@ -879,6 +884,12 @@ export async function getSharedTransactions(ownerId: number, tagIds?: number[], LEFT JOIN transaction_overrides o ON o.transaction_id = t.id LEFT JOIN statements s ON s.id = t.statement_id LEFT JOIN participants p_owner ON p_owner.id = COALESCE(t.owner_id, s.owner_id) + LEFT JOIN LATERAL ( + SELECT em.platform + FROM expense_metadata em + WHERE em.transaction_id = t.id OR em.matched_transaction_id = t.id + LIMIT 1 + ) order_ctx ON true LEFT JOIN transactions src ON src.reconciled_with_id = t.id AND src.statement_id IS NULL WHERE ( ( @@ -892,7 +903,7 @@ export async function getSharedTransactions(ownerId: number, tagIds?: number[], AND ${EXCLUDE_RECONCILED_SOURCE} ${tagClause} ${participantClause} - GROUP BY t.id, o.category_override, o.merchant_normalized, o.notes, s.bank_name, s.currency, s.owner_id, p_owner.name, src.created_at + GROUP BY t.id, o.category_override, o.merchant_normalized, o.notes, s.bank_name, s.currency, s.owner_id, p_owner.name, src.created_at, order_ctx.platform ORDER BY t.transaction_date DESC `, params);