import { useState } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { Plus, Pencil, Trash2, Check, X } from 'lucide-react' import { listGlobalRenderPositions, createGlobalRenderPosition, updateGlobalRenderPosition, deleteGlobalRenderPosition, type GlobalRenderPosition, type GlobalRenderPositionCreate, } from '../../api/renderPositions' interface EditState { id: string | null name: string rotation_x: number rotation_y: number rotation_z: number is_default: boolean sort_order: number } const EMPTY_EDIT: EditState = { id: null, name: '', rotation_x: 0, rotation_y: 0, rotation_z: 0, is_default: false, sort_order: 0, } export default function GlobalRenderPositionsPanel() { const qc = useQueryClient() const [editing, setEditing] = useState(null) const [adding, setAdding] = useState(false) const { data: positions = [], isLoading } = useQuery({ queryKey: ['global-render-positions'], queryFn: listGlobalRenderPositions, }) const createMut = useMutation({ mutationFn: (body: GlobalRenderPositionCreate) => createGlobalRenderPosition(body), onSuccess: () => { qc.invalidateQueries({ queryKey: ['global-render-positions'] }); setAdding(false) }, }) const updateMut = useMutation({ mutationFn: ({ id, body }: { id: string; body: Partial }) => updateGlobalRenderPosition(id, body), onSuccess: () => { qc.invalidateQueries({ queryKey: ['global-render-positions'] }); setEditing(null) }, }) const deleteMut = useMutation({ mutationFn: (id: string) => deleteGlobalRenderPosition(id), onSuccess: () => qc.invalidateQueries({ queryKey: ['global-render-positions'] }), }) function startEdit(pos: GlobalRenderPosition) { setAdding(false) setEditing({ id: pos.id, name: pos.name, rotation_x: pos.rotation_x, rotation_y: pos.rotation_y, rotation_z: pos.rotation_z, is_default: pos.is_default, sort_order: pos.sort_order, }) } function saveEdit() { if (!editing) return if (editing.id) { const { id, ...body } = editing updateMut.mutate({ id, body }) } } function saveNew() { if (!editing) return const { id, ...body } = editing createMut.mutate(body) } function startAdd() { setEditing({ ...EMPTY_EDIT, sort_order: positions.length }) setAdding(true) } function cancelEdit() { setEditing(null) setAdding(false) } function rotField(label: string, field: keyof Pick) { if (!editing) return null return (
setEditing({ ...editing, [field]: parseFloat(e.target.value) || 0 })} />
) } if (isLoading) return

Loading…

return (

Global camera rotation presets applied to all products. Per-product positions take priority.

{positions.map((pos) => { const isEditingThis = editing && editing.id === pos.id return ( {isEditingThis ? ( <> ) : ( <> )} ) })} {/* New row */} {adding && editing && ( )}
Name Rot X° Rot Y° Rot Z° Default Order
setEditing({ ...editing!, name: e.target.value })} /> {rotField('', 'rotation_x')} {rotField('', 'rotation_y')} {rotField('', 'rotation_z')} setEditing({ ...editing!, is_default: e.target.checked })} /> setEditing({ ...editing!, sort_order: parseInt(e.target.value) || 0 })} /> {pos.name} {pos.rotation_x} {pos.rotation_y} {pos.rotation_z} {pos.is_default && } {pos.sort_order}
setEditing({ ...editing, name: e.target.value })} /> {rotField('', 'rotation_x')} {rotField('', 'rotation_y')} {rotField('', 'rotation_z')} setEditing({ ...editing, is_default: e.target.checked })} /> setEditing({ ...editing, sort_order: parseInt(e.target.value) || 0 })} />
) }