Port occupancy sync + category ordering from the forecasting version
- Bookability showed no availability because newbook_occupancy_report_data was never populated: add reports_occupancy client method and sync_occupancy job, run before rates in both Sync Now and the daily schedule (single fast API call) - Category order: default display_order to the Newbook category id on sync (was 0 → alphabetical), preserve manual order on re-sync, extend PATCH to accept display_order, add up/down reorder arrows in Settings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
c924d793e8
commit
f51e1dcb76
5 changed files with 199 additions and 9 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import { useState } from 'react'
|
||||
import { useParams, useNavigate } from 'react-router-dom'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { Save, RefreshCw, Database, Clock, BedDouble } from 'lucide-react'
|
||||
import { Save, RefreshCw, Database, Clock, BedDouble, ChevronUp, ChevronDown } from 'lucide-react'
|
||||
import api from '../api'
|
||||
|
||||
const TABS = [
|
||||
|
|
@ -203,6 +203,23 @@ function RoomCategoriesCard() {
|
|||
onSuccess: () => qc.invalidateQueries({ queryKey: ['room-categories'] }),
|
||||
})
|
||||
|
||||
const reorderCategories = useMutation({
|
||||
mutationFn: (ordered: RoomCategory[]) =>
|
||||
Promise.all(ordered.map((cat, idx) =>
|
||||
api.patch(`/bookability/categories/${cat.id}`, { display_order: (idx + 1) * 10 })
|
||||
)),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ['room-categories'] }),
|
||||
})
|
||||
|
||||
const moveCategory = (idx: number, dir: -1 | 1) => {
|
||||
if (!categories) return
|
||||
const target = idx + dir
|
||||
if (target < 0 || target >= categories.length) return
|
||||
const reordered = [...categories]
|
||||
;[reordered[idx], reordered[target]] = [reordered[target], reordered[idx]]
|
||||
reorderCategories.mutate(reordered)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
<div className="card-header">
|
||||
|
|
@ -243,10 +260,11 @@ function RoomCategoriesCard() {
|
|||
<th>Included</th>
|
||||
<th>Category</th>
|
||||
<th>Rooms</th>
|
||||
<th>Order</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{categories.map(cat => (
|
||||
{categories.map((cat, idx) => (
|
||||
<tr key={cat.id}>
|
||||
<td>
|
||||
<input
|
||||
|
|
@ -258,6 +276,28 @@ function RoomCategoriesCard() {
|
|||
</td>
|
||||
<td>{cat.site_name}</td>
|
||||
<td>{cat.room_count}</td>
|
||||
<td>
|
||||
<span style={{ display: 'inline-flex', gap: 4 }}>
|
||||
<button
|
||||
className="btn btn-outline btn-sm"
|
||||
style={{ padding: '2px 6px' }}
|
||||
onClick={() => moveCategory(idx, -1)}
|
||||
disabled={idx === 0 || reorderCategories.isPending}
|
||||
title="Move up"
|
||||
>
|
||||
<ChevronUp size={13} strokeWidth={1.75} />
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-outline btn-sm"
|
||||
style={{ padding: '2px 6px' }}
|
||||
onClick={() => moveCategory(idx, 1)}
|
||||
disabled={idx === categories.length - 1 || reorderCategories.isPending}
|
||||
title="Move down"
|
||||
>
|
||||
<ChevronDown size={13} strokeWidth={1.75} />
|
||||
</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue