v0.27.04
This commit is contained in:
parent
153ed7ab79
commit
74603ff2d5
|
|
@ -1356,7 +1356,7 @@ export function ImportSpreadsheetSection({ onHistoryRefresh }) {
|
|||
// Collect created_at dates from duplicate detail entries so we can show
|
||||
// when the existing payments were originally recorded.
|
||||
const dupDates = (result.details ?? [])
|
||||
.filter(d => d.result === 'skipped_duplicate' && d.existing_created_at)
|
||||
.filter(d => (d.result === 'skipped_duplicate' || d.payment === 'skipped_duplicate') && d.existing_created_at)
|
||||
.map(d => new Date(d.existing_created_at))
|
||||
.filter(d => !isNaN(d.getTime()))
|
||||
.sort((a, b) => a - b);
|
||||
|
|
@ -1522,6 +1522,9 @@ export function ImportSpreadsheetSection({ onHistoryRefresh }) {
|
|||
setDecisions({});
|
||||
setSelectedRows(new Set());
|
||||
setApplyState({ status: 'idle', result: null, error: null });
|
||||
setViewMode('rows');
|
||||
setImportingBillId(null);
|
||||
setBillImportResults(new Map());
|
||||
if (fileRef.current) fileRef.current.value = '';
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -283,16 +283,19 @@ function useSortable(items, setItems, setDirty) {
|
|||
|
||||
const onPointerDown = useCallback((e, index) => {
|
||||
// Only trigger on the grip handle (data-grip attr)
|
||||
if (!e.currentTarget.hasAttribute('data-grip')) return;
|
||||
if (!e.target.closest('[data-grip]')) return;
|
||||
// Ignore right-click
|
||||
if (e.button !== undefined && e.button !== 0) return;
|
||||
|
||||
e.currentTarget.setPointerCapture(e.pointerId);
|
||||
|
||||
const card = e.currentTarget.closest('[data-card]');
|
||||
const card = e.target.closest('[data-card]');
|
||||
const list = card?.parentElement;
|
||||
const rect = card?.getBoundingClientRect();
|
||||
|
||||
// Capture on the container so pointermove/pointerup are dispatched
|
||||
// directly to the element that owns those React handlers — avoids
|
||||
// relying on bubbling from the grip through React's delegation chain.
|
||||
list?.setPointerCapture(e.pointerId);
|
||||
|
||||
state.current = {
|
||||
fromIdx: index,
|
||||
currentIdx: index,
|
||||
|
|
@ -593,12 +596,14 @@ export default function SnowballPage() {
|
|||
data-card
|
||||
data-card-index={index}
|
||||
className={cn(
|
||||
'surface-elevated rounded-xl border transition-all duration-150 select-none touch-none',
|
||||
'surface-elevated rounded-xl border select-none touch-none',
|
||||
// Only animate when not in a drag gesture — instant feedback on grab
|
||||
!isDragging && 'transition-all duration-150',
|
||||
isAttack ? 'border-emerald-500/30 bg-emerald-950/5' : 'border-border/40',
|
||||
// Card being actively dragged — lifted look
|
||||
isDragSource && 'scale-[1.03] shadow-2xl ring-2 ring-primary/40 opacity-80 relative z-10',
|
||||
isDragSource && 'scale-105 shadow-2xl ring-2 ring-primary/60 opacity-75 relative z-10',
|
||||
// Where the card will land — slot highlight
|
||||
isLandTarget && 'ring-2 ring-primary/60 scale-[0.98] opacity-60',
|
||||
isLandTarget && 'ring-2 ring-primary/40 scale-[0.97] opacity-50',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-stretch">
|
||||
|
|
|
|||
|
|
@ -1401,18 +1401,18 @@ function createPaymentFromImport(db, billId, amount, paidDate, notes, allowOverw
|
|||
if (!paidDate || amount == null || amount <= 0) return null;
|
||||
|
||||
const dup = db.prepare(`
|
||||
SELECT id FROM payments
|
||||
SELECT id, created_at FROM payments
|
||||
WHERE bill_id = ? AND paid_date = ? AND amount = ? AND deleted_at IS NULL
|
||||
`).get(billId, paidDate, amount);
|
||||
|
||||
if (dup && !allowOverwrite) return 'skipped_duplicate';
|
||||
if (dup && !allowOverwrite) return { result: 'skipped_duplicate', existing_created_at: dup.created_at ?? null };
|
||||
|
||||
db.prepare(`
|
||||
INSERT INTO payments (bill_id, amount, paid_date, method, notes)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
`).run(billId, amount, paidDate, null, notes);
|
||||
|
||||
return 'created';
|
||||
return { result: 'created', existing_created_at: null };
|
||||
}
|
||||
|
||||
function resolvePaymentInfo(decision, previewRow, amount) {
|
||||
|
|
@ -1448,7 +1448,7 @@ function importRelatedPaidMonthsForNewBill(db, newBillId, billName, sourceRowId,
|
|||
|
||||
const paymentResult = createPaymentFromImport(db, newBillId, paymentAmount, paymentDate, notes, allowOverwrite);
|
||||
if (paymentResult) {
|
||||
detail.payment = paymentResult;
|
||||
detail.payment = paymentResult.result;
|
||||
detail.paid_date = paymentDate;
|
||||
detail.payment_amount = paymentAmount;
|
||||
}
|
||||
|
|
@ -1531,7 +1531,7 @@ function applyOneDecision(db, userId, decision, previewRow, sessionData, allowOv
|
|||
allowOverwrite,
|
||||
);
|
||||
if (paymentResult) {
|
||||
detail.payment = paymentResult;
|
||||
detail.payment = paymentResult.result;
|
||||
detail.paid_date = paymentDate;
|
||||
detail.payment_amount = paymentAmount;
|
||||
}
|
||||
|
|
@ -1588,9 +1588,13 @@ function applyOneDecision(db, userId, decision, previewRow, sessionData, allowOv
|
|||
allowOverwrite,
|
||||
);
|
||||
if (paymentResult) {
|
||||
detail.payment = paymentResult;
|
||||
detail.payment = paymentResult.result;
|
||||
detail.paid_date = paymentDate;
|
||||
detail.payment_amount = paymentAmount;
|
||||
if (paymentResult.result === 'skipped_duplicate') {
|
||||
summary.duplicates++;
|
||||
detail.existing_created_at = paymentResult.existing_created_at;
|
||||
}
|
||||
}
|
||||
}
|
||||
summary.details.push(detail);
|
||||
|
|
|
|||
Loading…
Reference in New Issue