shared page: expandable receipt details on split transactions
ci / lint-test (push) Successful in 57s
ci / lint-test (push) Successful in 57s
The item list existed only on the owner's transactions page — the person a meal or order was split WITH could see the amount but never what was in it. getSharedTransactions now carries the same order_platform LATERAL the transactions page uses, and rows with a receipt get the same disclosure arrow + OrderDetails expansion. The shared viewer is a split participant, so canAccessTransactions already authorises the order API for them; meal rows keep the verdict UI (the partner records their own), bridge rows stay review-free.
This commit is contained in:
+33
-3
@@ -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<number | null>(null);
|
||||
const [editModal, setEditModal] = useState<SharedTransactionRow | null>(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<Set<number>>(new Set());
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -543,11 +548,28 @@ export default function SharedPage() {
|
||||
{(transactions as SharedTransactionRow[]).map((tx) => {
|
||||
const splits = Array.isArray(tx.splits) ? tx.splits : [];
|
||||
return (
|
||||
<tr key={tx.id} className="border-b border-zinc-800/50 hover:bg-zinc-800/30">
|
||||
<Fragment key={tx.id}>
|
||||
<tr className="border-b border-zinc-800/50 hover:bg-zinc-800/30">
|
||||
<td className="px-4 py-3 text-zinc-400 whitespace-nowrap">{formatDate(tx.transaction_date)}</td>
|
||||
<td className="px-4 py-3 text-zinc-500 text-xs whitespace-nowrap">{formatDate(tx.created_at)}</td>
|
||||
<td className="px-4 py-3 max-w-xs sticky left-0 z-10 bg-zinc-900 border-r border-zinc-800/80">
|
||||
<p className="font-medium break-words">{tx.effective_merchant || tx.description}</p>
|
||||
<div className="flex items-start gap-1.5">
|
||||
{tx.order_platform && (
|
||||
<button
|
||||
onClick={() => setExpanded((prev) => {
|
||||
const next = new Set(prev);
|
||||
if (next.has(tx.id)) next.delete(tx.id); else next.add(tx.id);
|
||||
return next;
|
||||
})}
|
||||
className="text-zinc-600 hover:text-zinc-300 leading-none mt-0.5 shrink-0"
|
||||
title={expanded.has(tx.id) ? "Hide receipt" : "Show the receipt this came from"}
|
||||
aria-expanded={expanded.has(tx.id)}
|
||||
>
|
||||
{expanded.has(tx.id) ? "▾" : "▸"}
|
||||
</button>
|
||||
)}
|
||||
<p className="font-medium break-words">{tx.effective_merchant || tx.description}</p>
|
||||
</div>
|
||||
{tx.effective_merchant && (
|
||||
<p className="text-xs text-zinc-500 break-words">{tx.description}</p>
|
||||
)}
|
||||
@@ -615,6 +637,14 @@ export default function SharedPage() {
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{expanded.has(tx.id) && (
|
||||
<tr className="border-b border-zinc-800/50 bg-zinc-900/40">
|
||||
<td colSpan={8} className="px-4 py-3">
|
||||
<OrderDetails transactionId={tx.id} currency={tx.currency ?? null} bare />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
|
||||
Reference in New Issue
Block a user