- Planning mode toggle: shift availability as background blocks on timeline (week view shows green=available, yellow=on-call; month view per-tech) - On-call/guard shift editor with RRULE recurrence on tech schedules - Uber-style job offer pool: broadcast/targeted/pool modes with pricing, SMS notifications, accept/decline flow, overload detection alerts - Shared resource group presets via ERPNext Dispatch Preset doctype (replaces localStorage, shared between supervisors) - Google Calendar-style RecurrenceSelector component with contextual quick options + custom RRULE editor, integrated in booking overlay and extra shift editor - Remove default "Repos" ghost chips — only visible in planning mode - Clean up debug console.logs across API, store, and page layers - Add extra_shifts Custom Field on Dispatch Technician doctype Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
47 lines
1.5 KiB
JavaScript
47 lines
1.5 KiB
JavaScript
// ── Dispatch Preset CRUD — shared resource group presets ─────────────────────
|
|
import { BASE_URL } from 'src/config/erpnext'
|
|
import { authFetch } from './auth'
|
|
|
|
async function apiGet (path) {
|
|
const res = await authFetch(BASE_URL + path)
|
|
const data = await res.json()
|
|
if (data.exc) throw new Error(data.exc)
|
|
return data
|
|
}
|
|
|
|
export async function fetchPresets () {
|
|
const data = await apiGet('/api/resource/Dispatch%20Preset?fields=["*"]&limit_page_length=100&order_by=creation+asc')
|
|
return data.data || []
|
|
}
|
|
|
|
export async function createPreset (payload) {
|
|
const res = await authFetch(
|
|
`${BASE_URL}/api/resource/Dispatch%20Preset`,
|
|
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) },
|
|
)
|
|
const data = await res.json()
|
|
if (data.exc) throw new Error(data.exc)
|
|
return data.data
|
|
}
|
|
|
|
export async function updatePreset (name, payload) {
|
|
const res = await authFetch(
|
|
`${BASE_URL}/api/resource/Dispatch%20Preset/${encodeURIComponent(name)}`,
|
|
{ method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) },
|
|
)
|
|
const data = await res.json()
|
|
if (data.exc) throw new Error(data.exc)
|
|
return data.data
|
|
}
|
|
|
|
export async function deletePreset (name) {
|
|
const res = await authFetch(
|
|
`${BASE_URL}/api/resource/Dispatch%20Preset/${encodeURIComponent(name)}`,
|
|
{ method: 'DELETE' },
|
|
)
|
|
if (!res.ok) {
|
|
const data = await res.json().catch(() => ({}))
|
|
throw new Error(data.exception || 'Delete failed')
|
|
}
|
|
}
|