Add drag & drop reordering of trips on the dashboard
- trip_members.sort_order (per-user, migrated) drives GET /api/trips order - PATCH /api/trips/:id/order updates only the caller's membership row - Trip cards get a drag handle reusing the generalized row-reorder helper; clicking the card still navigates
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { api } from '../api.js';
|
||||
import { el, mount, clear, loading, errorBox, emptyState, toast } from '../dom.js';
|
||||
import { formatRange, ymd, parseYMD, pluralize, normalizeCode } from '../format.js';
|
||||
import { enableTripReorder } from './dragdrop.js';
|
||||
|
||||
export function renderTrips(container, ctx) {
|
||||
mount(container, loading('Loading your trips…'));
|
||||
@@ -57,27 +58,46 @@ export function renderTrips(container, ctx) {
|
||||
);
|
||||
} else {
|
||||
const grid = el('div', { class: 'trip-grid' });
|
||||
for (const trip of trips) grid.appendChild(tripCard(trip));
|
||||
// Reordering only makes sense with 2+ trips (mirrors the day editor's
|
||||
// entry-row reorder — see dragdrop.js).
|
||||
const reorderable = trips.length > 1;
|
||||
const rows = [];
|
||||
for (const trip of trips) {
|
||||
const { node, handle } = tripCard(trip, reorderable);
|
||||
if (reorderable) rows.push({ node, handle, trip });
|
||||
grid.appendChild(node);
|
||||
}
|
||||
page.appendChild(grid);
|
||||
if (reorderable) enableTripReorder(rows, load);
|
||||
}
|
||||
|
||||
mount(container, page);
|
||||
}
|
||||
|
||||
function tripCard(trip) {
|
||||
function tripCard(trip, reorderable) {
|
||||
const today = ymd(new Date());
|
||||
const future = trip.start_date > today;
|
||||
const daysUntil = future
|
||||
? Math.round((parseYMD(trip.start_date) - parseYMD(today)) / 86400000)
|
||||
: 0;
|
||||
return el(
|
||||
const handle = reorderable
|
||||
? el('span', {
|
||||
class: 'trip-drag-handle',
|
||||
title: 'Drag to reorder',
|
||||
'aria-hidden': 'true',
|
||||
onClick: (e) => e.preventDefault(),
|
||||
}, '⋮⋮')
|
||||
: null;
|
||||
const node = el(
|
||||
'a',
|
||||
{ class: 'trip-card card', href: `#/trip/${trip.id}` },
|
||||
{ class: 'trip-card card', href: `#/trip/${trip.id}`, draggable: 'false' },
|
||||
el(
|
||||
'div',
|
||||
{ class: 'trip-card-top' },
|
||||
el('h3', { class: 'trip-card-name' }, trip.name),
|
||||
el('span', { class: `role-badge role-${trip.role}` }, trip.role),
|
||||
el('div', { class: 'trip-card-top-right' },
|
||||
handle,
|
||||
el('span', { class: `role-badge role-${trip.role}` }, trip.role)),
|
||||
),
|
||||
el(
|
||||
'div',
|
||||
@@ -93,6 +113,7 @@ export function renderTrips(container, ctx) {
|
||||
el('span', { class: 'trip-card-currency' }, trip.currency || 'USD'),
|
||||
),
|
||||
);
|
||||
return { node, handle };
|
||||
}
|
||||
|
||||
// Render `build()` into the slot, or close it if the same panel is open.
|
||||
|
||||
Reference in New Issue
Block a user