Migrate all kitchen frontend fetch calls to /kitchen/api/ prefix (B5b)

All archive components were calling fetch('/api/...') directly. Replaced
all occurrences of /api/ URLs (string literals, template literals,
window.open, src attributes) with /kitchen/api/ across 37 source files.
The central axios instance in api.ts was already correct.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-12 12:56:11 +00:00
parent ecd63fc65f
commit 9905d0e0dd
51 changed files with 453 additions and 453 deletions

View file

@ -1,7 +1,7 @@
import axios from 'axios' import axios from 'axios'
// Central axios instance for new/migrated code. // Central axios instance for new/migrated code.
// Existing archive components still call fetch('/api/...') directly — // Existing archive components still call fetch('/kitchen/api/...') directly —
// see port log B5 for the migration tracker. // see port log B5 for the migration tracker.
const api = axios.create({ const api = axios.create({
baseURL: '/kitchen/api', baseURL: '/kitchen/api',

View file

@ -254,7 +254,7 @@ export default function AllowancesReport() {
const { data: summary, isLoading, error } = useQuery<AllowancesSummaryResponse>({ const { data: summary, isLoading, error } = useQuery<AllowancesSummaryResponse>({
queryKey: ['allowances-summary', submittedFromDate, submittedToDate], queryKey: ['allowances-summary', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/allowances/summary?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/reports/allowances/summary?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch allowances summary') if (!res.ok) throw new Error('Failed to fetch allowances summary')
@ -268,7 +268,7 @@ export default function AllowancesReport() {
const { data: chartData } = useQuery<DailyAllowanceChartResponse>({ const { data: chartData } = useQuery<DailyAllowanceChartResponse>({
queryKey: ['allowances-daily', submittedFromDate, submittedToDate], queryKey: ['allowances-daily', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/allowances/daily?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/reports/allowances/daily?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch chart data') if (!res.ok) throw new Error('Failed to fetch chart data')
@ -282,7 +282,7 @@ export default function AllowancesReport() {
const { data: disputes } = useQuery<DisputesSummaryResponse>({ const { data: disputes } = useQuery<DisputesSummaryResponse>({
queryKey: ['disputes-period-summary', submittedFromDate, submittedToDate], queryKey: ['disputes-period-summary', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/disputes/period-summary?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/reports/disputes/period-summary?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch disputes summary') if (!res.ok) throw new Error('Failed to fetch disputes summary')

View file

@ -254,7 +254,7 @@ export default function Budget() {
const { data: budgetData, isLoading, error, refetch } = useQuery<WeeklyBudgetResponse>({ const { data: budgetData, isLoading, error, refetch } = useQuery<WeeklyBudgetResponse>({
queryKey: ['budget', 'weekly', weekOffset], queryKey: ['budget', 'weekly', weekOffset],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/budget/weekly?week_offset=${weekOffset}`, { const res = await fetch(`/kitchen/api/budget/weekly?week_offset=${weekOffset}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch budget data') if (!res.ok) throw new Error('Failed to fetch budget data')
@ -267,7 +267,7 @@ export default function Budget() {
const { data: prevWeek1 } = useQuery<WeeklyBudgetResponse>({ const { data: prevWeek1 } = useQuery<WeeklyBudgetResponse>({
queryKey: ['budget', 'weekly', weekOffset - 1], queryKey: ['budget', 'weekly', weekOffset - 1],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/budget/weekly?week_offset=${weekOffset - 1}`, { const res = await fetch(`/kitchen/api/budget/weekly?week_offset=${weekOffset - 1}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return null if (!res.ok) return null
@ -278,7 +278,7 @@ export default function Budget() {
const { data: prevWeek2 } = useQuery<WeeklyBudgetResponse>({ const { data: prevWeek2 } = useQuery<WeeklyBudgetResponse>({
queryKey: ['budget', 'weekly', weekOffset - 2], queryKey: ['budget', 'weekly', weekOffset - 2],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/budget/weekly?week_offset=${weekOffset - 2}`, { const res = await fetch(`/kitchen/api/budget/weekly?week_offset=${weekOffset - 2}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return null if (!res.ok) return null
@ -298,7 +298,7 @@ export default function Budget() {
const { data: overrideData, refetch: refetchOverrides, isLoading: isOverrideLoading } = useQuery<WeeklyOverrideResponse>({ const { data: overrideData, refetch: refetchOverrides, isLoading: isOverrideLoading } = useQuery<WeeklyOverrideResponse>({
queryKey: ['cover-overrides', 'weekly', weekOffset], queryKey: ['cover-overrides', 'weekly', weekOffset],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/cover-overrides/weekly?week_offset=${weekOffset}`, { const res = await fetch(`/kitchen/api/cover-overrides/weekly?week_offset=${weekOffset}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch override data') if (!res.ok) throw new Error('Failed to fetch override data')
@ -312,7 +312,7 @@ export default function Budget() {
queryKey: ['cost-distributions', 'weekly', weekOffset, budgetData?.week_start, budgetData?.week_end], queryKey: ['cost-distributions', 'weekly', weekOffset, budgetData?.week_start, budgetData?.week_end],
queryFn: async () => { queryFn: async () => {
const res = await fetch( const res = await fetch(
`/api/cost-distributions/weekly?week_start=${budgetData!.week_start}&week_end=${budgetData!.week_end}`, `/kitchen/api/cost-distributions/weekly?week_start=${budgetData!.week_start}&week_end=${budgetData!.week_end}`,
{ headers: { Authorization: `Bearer ${token}` } } { headers: { Authorization: `Bearer ${token}` } }
) )
if (!res.ok) throw new Error('Failed to fetch distribution data') if (!res.ok) throw new Error('Failed to fetch distribution data')
@ -335,7 +335,7 @@ export default function Budget() {
queryKey: ['resos', 'resident-covers', budgetData?.week_start, budgetData?.week_end], queryKey: ['resos', 'resident-covers', budgetData?.week_start, budgetData?.week_end],
queryFn: async () => { queryFn: async () => {
const res = await fetch( const res = await fetch(
`/api/resos/resident-covers?start_date=${budgetData!.week_start}&end_date=${budgetData!.week_end}`, `/kitchen/api/resos/resident-covers?start_date=${budgetData!.week_start}&end_date=${budgetData!.week_end}`,
{ headers: { Authorization: `Bearer ${token}` } } { headers: { Authorization: `Bearer ${token}` } }
) )
if (!res.ok) return {} if (!res.ok) return {}
@ -347,7 +347,7 @@ export default function Budget() {
const snapshotMutation = useMutation({ const snapshotMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/cover-overrides/snapshot', { const res = await fetch('/kitchen/api/cover-overrides/snapshot', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ week_offset: weekOffset }), body: JSON.stringify({ week_offset: weekOffset }),
@ -383,7 +383,7 @@ export default function Budget() {
try { try {
await Promise.all(Object.entries(pendingOverrides).map(([key, value]) => { await Promise.all(Object.entries(pendingOverrides).map(([key, value]) => {
const [overrideDate, period] = key.split('|') const [overrideDate, period] = key.split('|')
return fetch('/api/cover-overrides', { return fetch('/kitchen/api/cover-overrides', {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ override_date: overrideDate, period, override_covers: value }), body: JSON.stringify({ override_date: overrideDate, period, override_covers: value }),
@ -398,7 +398,7 @@ export default function Budget() {
} }
const deleteOverride = async (id: number) => { const deleteOverride = async (id: number) => {
await fetch(`/api/cover-overrides/${id}`, { await fetch(`/kitchen/api/cover-overrides/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -407,7 +407,7 @@ export default function Budget() {
} }
const saveSpendRate = async (period: string, food: number | null, drinks: number | null) => { const saveSpendRate = async (period: string, food: number | null, drinks: number | null) => {
await fetch('/api/cover-overrides/spend-rates', { await fetch('/kitchen/api/cover-overrides/spend-rates', {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ week_offset: weekOffset, period, food_spend: food, drinks_spend: drinks }), body: JSON.stringify({ week_offset: weekOffset, period, food_spend: food, drinks_spend: drinks }),

View file

@ -65,7 +65,7 @@ export default function BulkAllergens() {
const { data: ingredients } = useQuery<IngredientItem[]>({ const { data: ingredients } = useQuery<IngredientItem[]>({
queryKey: ['ingredients-bulk'], queryKey: ['ingredients-bulk'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/ingredients?limit=9999', { const res = await fetch('/kitchen/api/ingredients?limit=9999', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch ingredients') if (!res.ok) throw new Error('Failed to fetch ingredients')
@ -78,7 +78,7 @@ export default function BulkAllergens() {
const { data: categories } = useQuery<IngredientCategory[]>({ const { data: categories } = useQuery<IngredientCategory[]>({
queryKey: ['ingredient-categories'], queryKey: ['ingredient-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/ingredients/categories', { const res = await fetch('/kitchen/api/ingredients/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -91,7 +91,7 @@ export default function BulkAllergens() {
const { data: flagCategories } = useQuery<FoodFlagCategoryItem[]>({ const { data: flagCategories } = useQuery<FoodFlagCategoryItem[]>({
queryKey: ['food-flag-categories-full'], queryKey: ['food-flag-categories-full'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/food-flags/categories', { const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch flag categories') if (!res.ok) throw new Error('Failed to fetch flag categories')
@ -104,7 +104,7 @@ export default function BulkAllergens() {
const { data: bulkNones } = useQuery<Record<number, number[]>>({ const { data: bulkNones } = useQuery<Record<number, number[]>>({
queryKey: ['bulk-nones'], queryKey: ['bulk-nones'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/ingredients/bulk-nones', { const res = await fetch('/kitchen/api/ingredients/bulk-nones', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return {} if (!res.ok) return {}
@ -117,7 +117,7 @@ export default function BulkAllergens() {
const { data: allSuggestions } = useQuery<Record<number, AllergenSuggestion[]>>({ const { data: allSuggestions } = useQuery<Record<number, AllergenSuggestion[]>>({
queryKey: ['bulk-suggestions'], queryKey: ['bulk-suggestions'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/food-flags/suggest/bulk', { const res = await fetch('/kitchen/api/food-flags/suggest/bulk', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return {} if (!res.ok) return {}
@ -140,7 +140,7 @@ export default function BulkAllergens() {
newFlagIds = currentFlagIds.filter(id => id !== flagId) newFlagIds = currentFlagIds.filter(id => id !== flagId)
} }
const res = await fetch(`/api/ingredients/${ingredientId}/flags`, { const res = await fetch(`/kitchen/api/ingredients/${ingredientId}/flags`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ food_flag_ids: newFlagIds }), body: JSON.stringify({ food_flag_ids: newFlagIds }),
@ -156,7 +156,7 @@ export default function BulkAllergens() {
// Toggle None for a category on an ingredient // Toggle None for a category on an ingredient
const toggleNoneMutation = useMutation({ const toggleNoneMutation = useMutation({
mutationFn: async ({ ingredientId, categoryId }: { ingredientId: number; categoryId: number }) => { mutationFn: async ({ ingredientId, categoryId }: { ingredientId: number; categoryId: number }) => {
const res = await fetch(`/api/ingredients/${ingredientId}/flags/none`, { const res = await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/none`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ category_id: categoryId }), body: JSON.stringify({ category_id: categoryId }),

View file

@ -31,7 +31,7 @@ export default function BulkPublishModal({ menuId, divisionId, divisionName, onC
const { data: dishes } = useQuery<DishItem[]>({ const { data: dishes } = useQuery<DishItem[]>({
queryKey: ['dishes-for-bulk'], queryKey: ['dishes-for-bulk'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes?recipe_type=dish', { const res = await fetch('/kitchen/api/recipes?recipe_type=dish', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed') if (!res.ok) throw new Error('Failed')
@ -46,7 +46,7 @@ export default function BulkPublishModal({ menuId, divisionId, divisionName, onC
queryFn: async () => { queryFn: async () => {
const results: Record<number, { ok: boolean; unassessed?: Array<{ name: string }> }> = {} const results: Record<number, { ok: boolean; unassessed?: Array<{ name: string }> }> = {}
for (const rid of selected) { for (const rid of selected) {
const res = await fetch(`/api/food-flags/recipes/${rid}/flags`, { const res = await fetch(`/kitchen/api/food-flags/recipes/${rid}/flags`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok) { if (res.ok) {
@ -76,7 +76,7 @@ export default function BulkPublishModal({ menuId, divisionId, divisionName, onC
price: editedPrices[id] ? parseFloat(editedPrices[id]) : (dish?.gross_sell_price || null), price: editedPrices[id] ? parseFloat(editedPrices[id]) : (dish?.gross_sell_price || null),
} }
}) })
const res = await fetch(`/api/menus/${menuId}/items/bulk`, { const res = await fetch(`/kitchen/api/menus/${menuId}/items/bulk`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({

View file

@ -123,7 +123,7 @@ export default function CostDistributionModal({ isOpen, onClose, onSaved, invoic
if (distributionId) { if (distributionId) {
// Load existing distribution // Load existing distribution
setLoading(true) setLoading(true)
fetch(`/api/cost-distributions/${distributionId}`, { fetch(`/kitchen/api/cost-distributions/${distributionId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
.then(r => { if (!r.ok) throw new Error('Failed to load distribution'); return r.json() }) .then(r => { if (!r.ok) throw new Error('Failed to load distribution'); return r.json() })
@ -136,7 +136,7 @@ export default function CostDistributionModal({ isOpen, onClose, onSaved, invoic
} else if (invoiceId) { } else if (invoiceId) {
// Load invoice availability // Load invoice availability
setLoading(true) setLoading(true)
fetch(`/api/cost-distributions/invoice/${invoiceId}/availability`, { fetch(`/kitchen/api/cost-distributions/invoice/${invoiceId}/availability`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
.then(r => { if (!r.ok) throw new Error('Failed to load invoice data'); return r.json() }) .then(r => { if (!r.ok) throw new Error('Failed to load invoice data'); return r.json() })
@ -276,7 +276,7 @@ export default function CostDistributionModal({ isOpen, onClose, onSaved, invoic
body.start_date = startDate body.start_date = startDate
} }
const res = await fetch('/api/cost-distributions/', { const res = await fetch('/kitchen/api/cost-distributions/', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body), body: JSON.stringify(body),
@ -300,7 +300,7 @@ export default function CostDistributionModal({ isOpen, onClose, onSaved, invoic
if (!token || !distributionId) return if (!token || !distributionId) return
setSaving(true) setSaving(true)
try { try {
const res = await fetch(`/api/cost-distributions/${distributionId}`, { const res = await fetch(`/kitchen/api/cost-distributions/${distributionId}`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ notes }), body: JSON.stringify({ notes }),
@ -320,7 +320,7 @@ export default function CostDistributionModal({ isOpen, onClose, onSaved, invoic
if (!confirm('Are you sure you want to cancel this distribution? This will remove all scheduled entries.')) return if (!confirm('Are you sure you want to cancel this distribution? This will remove all scheduled entries.')) return
setDeleting(true) setDeleting(true)
try { try {
const res = await fetch(`/api/cost-distributions/${distributionId}`, { const res = await fetch(`/kitchen/api/cost-distributions/${distributionId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -343,7 +343,7 @@ export default function CostDistributionModal({ isOpen, onClose, onSaved, invoic
try { try {
const body: any = { entry_date: settleDate } const body: any = { entry_date: settleDate }
if (!settleAll && settleAmount) body.amount = parseFloat(settleAmount) if (!settleAll && settleAmount) body.amount = parseFloat(settleAmount)
const res = await fetch(`/api/cost-distributions/${distributionId}/settle-early`, { const res = await fetch(`/kitchen/api/cost-distributions/${distributionId}/settle-early`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body), body: JSON.stringify(body),

View file

@ -69,7 +69,7 @@ export default function CreateDisputeModal({
const createMutation = useMutation({ const createMutation = useMutation({
mutationFn: async (data: CreateDisputeRequest) => { mutationFn: async (data: CreateDisputeRequest) => {
const res = await fetch('/api/disputes', { const res = await fetch('/kitchen/api/disputes', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View file

@ -136,7 +136,7 @@ export default function Dashboard() {
const { data: resosSettings } = useQuery<ResosSettings>({ const { data: resosSettings } = useQuery<ResosSettings>({
queryKey: ['resos-settings'], queryKey: ['resos-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/resos/settings', { const res = await fetch('/kitchen/api/resos/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch Resos settings') if (!res.ok) throw new Error('Failed to fetch Resos settings')
@ -148,7 +148,7 @@ export default function Dashboard() {
const { data, isLoading, error } = useQuery<DashboardData>({ const { data, isLoading, error } = useQuery<DashboardData>({
queryKey: ['dashboard'], queryKey: ['dashboard'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/reports/dashboard', { const res = await fetch('/kitchen/api/reports/dashboard', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch dashboard') if (!res.ok) throw new Error('Failed to fetch dashboard')
@ -159,7 +159,7 @@ export default function Dashboard() {
const { data: resosCovers } = useQuery<ResosCoversData>({ const { data: resosCovers } = useQuery<ResosCoversData>({
queryKey: ['resos-dashboard-covers'], queryKey: ['resos-dashboard-covers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/resos/dashboard/today-tomorrow', { const res = await fetch('/kitchen/api/resos/dashboard/today-tomorrow', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch Resos covers') if (!res.ok) throw new Error('Failed to fetch Resos covers')
@ -172,7 +172,7 @@ export default function Dashboard() {
const { data: arrivalStats } = useQuery<ArrivalDashboardData>({ const { data: arrivalStats } = useQuery<ArrivalDashboardData>({
queryKey: ['newbook-arrival-stats'], queryKey: ['newbook-arrival-stats'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/newbook/dashboard/arrivals?days=3', { const res = await fetch('/kitchen/api/newbook/dashboard/arrivals?days=3', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch arrival stats') if (!res.ok) throw new Error('Failed to fetch arrival stats')
@ -193,7 +193,7 @@ export default function Dashboard() {
}>({ }>({
queryKey: ['upcoming-events'], queryKey: ['upcoming-events'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/calendar-events/dashboard/upcoming', { const res = await fetch('/kitchen/api/calendar-events/dashboard/upcoming', {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (!res.ok) throw new Error('Failed to fetch upcoming events') if (!res.ok) throw new Error('Failed to fetch upcoming events')
@ -217,7 +217,7 @@ export default function Dashboard() {
}>({ }>({
queryKey: ['recipe-dashboard-stats'], queryKey: ['recipe-dashboard-stats'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes/dashboard-stats', { const res = await fetch('/kitchen/api/recipes/dashboard-stats', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch recipe stats') if (!res.ok) throw new Error('Failed to fetch recipe stats')
@ -230,7 +230,7 @@ export default function Dashboard() {
const { data: disputeStats } = useQuery<DisputeStats>({ const { data: disputeStats } = useQuery<DisputeStats>({
queryKey: ['dispute-stats'], queryKey: ['dispute-stats'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/disputes/stats/summary', { const res = await fetch('/kitchen/api/disputes/stats/summary', {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (!res.ok) throw new Error('Failed to fetch dispute stats') if (!res.ok) throw new Error('Failed to fetch dispute stats')

View file

@ -288,7 +288,7 @@ export default function DishEditor() {
const { data: recipe } = useQuery<RecipeDetail>({ const { data: recipe } = useQuery<RecipeDetail>({
queryKey: ['recipe', recipeId], queryKey: ['recipe', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Not found') if (!res.ok) throw new Error('Not found')
@ -301,7 +301,7 @@ export default function DishEditor() {
const { data: sections } = useQuery<MenuSection[]>({ const { data: sections } = useQuery<MenuSection[]>({
queryKey: ['dish-courses'], queryKey: ['dish-courses'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes/menu-sections?section_type=dish', { const res = await fetch('/kitchen/api/recipes/menu-sections?section_type=dish', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -313,7 +313,7 @@ export default function DishEditor() {
const { data: costData } = useQuery<CostData>({ const { data: costData } = useQuery<CostData>({
queryKey: ['recipe-cost', recipeId], queryKey: ['recipe-cost', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/costing`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/costing`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -325,7 +325,7 @@ export default function DishEditor() {
const { data: scaledCostData } = useQuery<CostData>({ const { data: scaledCostData } = useQuery<CostData>({
queryKey: ['recipe-cost-scaled', recipeId, scalePortions], queryKey: ['recipe-cost-scaled', recipeId, scalePortions],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/costing?scale_to=${scalePortions}`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/costing?scale_to=${scalePortions}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -337,7 +337,7 @@ export default function DishEditor() {
const { data: flagData } = useQuery<FlagState>({ const { data: flagData } = useQuery<FlagState>({
queryKey: ['recipe-flags', recipeId], queryKey: ['recipe-flags', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/food-flags/recipes/${recipeId}/flags`, { const res = await fetch(`/kitchen/api/food-flags/recipes/${recipeId}/flags`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -349,7 +349,7 @@ export default function DishEditor() {
const { data: flagCategories } = useQuery<Array<{ id: number; name: string; propagation_type: string; required: boolean }>>({ const { data: flagCategories } = useQuery<Array<{ id: number; name: string; propagation_type: string; required: boolean }>>({
queryKey: ['food-flag-categories'], queryKey: ['food-flag-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/food-flags/categories', { const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -361,7 +361,7 @@ export default function DishEditor() {
const { data: changeLog } = useQuery<ChangeLogEntry[]>({ const { data: changeLog } = useQuery<ChangeLogEntry[]>({
queryKey: ['recipe-changelog', recipeId], queryKey: ['recipe-changelog', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/change-log`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/change-log`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -373,7 +373,7 @@ export default function DishEditor() {
const { data: costTrendRaw } = useQuery<CostTrendResponse>({ const { data: costTrendRaw } = useQuery<CostTrendResponse>({
queryKey: ['recipe-cost-trend', recipeId], queryKey: ['recipe-cost-trend', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/cost-trend`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/cost-trend`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch cost trend') if (!res.ok) throw new Error('Failed to fetch cost trend')
@ -386,7 +386,7 @@ export default function DishEditor() {
const { data: dishMenus } = useQuery<Array<{ menu_id: number; menu_name: string; is_active: boolean }>>({ const { data: dishMenus } = useQuery<Array<{ menu_id: number; menu_name: string; is_active: boolean }>>({
queryKey: ['dish-menus', recipeId], queryKey: ['dish-menus', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/menus/dish/${recipeId}/menus`, { const res = await fetch(`/kitchen/api/menus/dish/${recipeId}/menus`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -399,7 +399,7 @@ export default function DishEditor() {
const { data: editIngData } = useQuery<EditingIngredient>({ const { data: editIngData } = useQuery<EditingIngredient>({
queryKey: ['ingredient-edit', editIngId], queryKey: ['ingredient-edit', editIngId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/ingredients/${editIngId}`, { const res = await fetch(`/kitchen/api/ingredients/${editIngId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Not found') if (!res.ok) throw new Error('Not found')
@ -425,7 +425,7 @@ export default function DishEditor() {
const { data: availableRecipes } = useQuery<Array<{ id: number; name: string; recipe_type: string; batch_portions: number; batch_output_type: string; batch_yield_qty: number | null; batch_yield_unit: string | null; output_unit: string }>>({ const { data: availableRecipes } = useQuery<Array<{ id: number; name: string; recipe_type: string; batch_portions: number; batch_output_type: string; batch_yield_qty: number | null; batch_yield_unit: string | null; output_unit: string }>>({
queryKey: ['recipes-list-for-sub'], queryKey: ['recipes-list-for-sub'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes?recipe_type=component', { const res = await fetch('/kitchen/api/recipes?recipe_type=component', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -438,7 +438,7 @@ export default function DishEditor() {
const { data: sambaposItems } = useQuery<SambaposMenuItem[]>({ const { data: sambaposItems } = useQuery<SambaposMenuItem[]>({
queryKey: ['sambapos-menu-items-portions'], queryKey: ['sambapos-menu-items-portions'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/sambapos/menu-items-with-portions', { const res = await fetch('/kitchen/api/sambapos/menu-items-with-portions', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -467,7 +467,7 @@ export default function DishEditor() {
if (!ingSearch || ingSearch.length < 2 || !token) return if (!ingSearch || ingSearch.length < 2 || !token) return
const timer = setTimeout(async () => { const timer = setTimeout(async () => {
try { try {
const res = await fetch(`/api/ingredients/suggest?description=${encodeURIComponent(ingSearch)}`, { const res = await fetch(`/kitchen/api/ingredients/suggest?description=${encodeURIComponent(ingSearch)}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok) { if (res.ok) {
@ -484,7 +484,7 @@ export default function DishEditor() {
// Mutations // Mutations
const updateMutation = useMutation({ const updateMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch(`/api/recipes/${recipeId}`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -502,7 +502,7 @@ export default function DishEditor() {
const addIngMutation = useMutation({ const addIngMutation = useMutation({
mutationFn: async (data: { ingredient_id: number; quantity: number; unit?: string; notes?: string }) => { mutationFn: async (data: { ingredient_id: number; quantity: number; unit?: string; notes?: string }) => {
const res = await fetch(`/api/recipes/${recipeId}/ingredients`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/ingredients`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -527,7 +527,7 @@ export default function DishEditor() {
const updateIngMutation = useMutation({ const updateIngMutation = useMutation({
mutationFn: async ({ riId, quantity, unit, yield_percent, notes }: { riId: number; quantity?: number; unit?: string; yield_percent?: number; notes?: string }) => { mutationFn: async ({ riId, quantity, unit, yield_percent, notes }: { riId: number; quantity?: number; unit?: string; yield_percent?: number; notes?: string }) => {
const res = await fetch(`/api/recipes/recipe-ingredients/${riId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-ingredients/${riId}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ quantity, unit, yield_percent, notes }), body: JSON.stringify({ quantity, unit, yield_percent, notes }),
@ -545,7 +545,7 @@ export default function DishEditor() {
const removeIngMutation = useMutation({ const removeIngMutation = useMutation({
mutationFn: async (riId: number) => { mutationFn: async (riId: number) => {
const res = await fetch(`/api/recipes/recipe-ingredients/${riId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-ingredients/${riId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -562,7 +562,7 @@ export default function DishEditor() {
const addSubMutation = useMutation({ const addSubMutation = useMutation({
mutationFn: async (data: { child_recipe_id: number; portions_needed: number; portions_needed_unit?: string }) => { mutationFn: async (data: { child_recipe_id: number; portions_needed: number; portions_needed_unit?: string }) => {
const res = await fetch(`/api/recipes/${recipeId}/sub-recipes`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/sub-recipes`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -583,7 +583,7 @@ export default function DishEditor() {
const removeSubMutation = useMutation({ const removeSubMutation = useMutation({
mutationFn: async (srId: number) => { mutationFn: async (srId: number) => {
const res = await fetch(`/api/recipes/recipe-sub-recipes/${srId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-sub-recipes/${srId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -599,7 +599,7 @@ export default function DishEditor() {
const addStepMutation = useMutation({ const addStepMutation = useMutation({
mutationFn: async (data: { title?: string; instruction: string; step_number: number; duration_minutes?: number }) => { mutationFn: async (data: { title?: string; instruction: string; step_number: number; duration_minutes?: number }) => {
const res = await fetch(`/api/recipes/${recipeId}/steps`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/steps`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -617,7 +617,7 @@ export default function DishEditor() {
const updateStepMutation = useMutation({ const updateStepMutation = useMutation({
mutationFn: async ({ stepId, data }: { stepId: number; data: { title?: string; instruction?: string; duration_minutes?: number } }) => { mutationFn: async ({ stepId, data }: { stepId: number; data: { title?: string; instruction?: string; duration_minutes?: number } }) => {
const res = await fetch(`/api/recipes/recipe-steps/${stepId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-steps/${stepId}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -636,7 +636,7 @@ export default function DishEditor() {
const removeStepMutation = useMutation({ const removeStepMutation = useMutation({
mutationFn: async (stepId: number) => { mutationFn: async (stepId: number) => {
const res = await fetch(`/api/recipes/recipe-steps/${stepId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-steps/${stepId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -652,7 +652,7 @@ export default function DishEditor() {
formData.append('file', file) formData.append('file', file)
formData.append('caption', caption) formData.append('caption', caption)
formData.append('image_type', image_type) formData.append('image_type', image_type)
const res = await fetch(`/api/recipes/${recipeId}/images`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/images`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
body: formData, body: formData,
@ -670,7 +670,7 @@ export default function DishEditor() {
// Delete image mutation // Delete image mutation
const deleteImageMutation = useMutation({ const deleteImageMutation = useMutation({
mutationFn: async (imageId: number) => { mutationFn: async (imageId: number) => {
const res = await fetch(`/api/recipes/${recipeId}/images/${imageId}`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/images/${imageId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -684,7 +684,7 @@ export default function DishEditor() {
// Batch reorder ingredients // Batch reorder ingredients
const reorderIngMutation = useMutation({ const reorderIngMutation = useMutation({
mutationFn: async (ingredientIds: number[]) => { mutationFn: async (ingredientIds: number[]) => {
const res = await fetch(`/api/recipes/${recipeId}/ingredients/reorder`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/ingredients/reorder`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ingredient_ids: ingredientIds }), body: JSON.stringify({ ingredient_ids: ingredientIds }),
@ -699,7 +699,7 @@ export default function DishEditor() {
// Batch reorder sub-recipes // Batch reorder sub-recipes
const reorderSubMutation = useMutation({ const reorderSubMutation = useMutation({
mutationFn: async (subRecipeIds: number[]) => { mutationFn: async (subRecipeIds: number[]) => {
const res = await fetch(`/api/recipes/${recipeId}/sub-recipes/reorder`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/sub-recipes/reorder`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ sub_recipe_ids: subRecipeIds }), body: JSON.stringify({ sub_recipe_ids: subRecipeIds }),
@ -714,7 +714,7 @@ export default function DishEditor() {
// Reorder steps mutation // Reorder steps mutation
const reorderStepsMutation = useMutation({ const reorderStepsMutation = useMutation({
mutationFn: async (stepIds: number[]) => { mutationFn: async (stepIds: number[]) => {
const res = await fetch(`/api/recipes/${recipeId}/steps/reorder`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/steps/reorder`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ step_ids: stepIds }), body: JSON.stringify({ step_ids: stepIds }),
@ -799,7 +799,7 @@ export default function DishEditor() {
} }
const handlePrint = (format: string) => { const handlePrint = (format: string) => {
window.open(`/api/recipes/${recipeId}/print?format=${format}&token=${token}`, '_blank') window.open(`/kitchen/api/recipes/${recipeId}/print?format=${format}&token=${token}`, '_blank')
} }
if (!recipe) return <div style={styles.loading}>Loading dish...</div> if (!recipe) return <div style={styles.loading}>Loading dish...</div>
@ -929,7 +929,7 @@ export default function DishEditor() {
style={{ marginLeft: 'auto', background: 'none', border: '1px solid #b4530955', borderRadius: '4px', color: '#b45309', cursor: 'pointer', padding: '0.15rem 0.5rem', fontSize: '0.8rem', whiteSpace: 'nowrap' }} style={{ marginLeft: 'auto', background: 'none', border: '1px solid #b4530955', borderRadius: '4px', color: '#b45309', cursor: 'pointer', padding: '0.15rem 0.5rem', fontSize: '0.8rem', whiteSpace: 'nowrap' }}
onClick={async () => { onClick={async () => {
try { try {
const res = await fetch(`/api/food-flags/recipes/${recipeId}/text-dismissals`, { const res = await fetch(`/kitchen/api/food-flags/recipes/${recipeId}/text-dismissals`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@ -1345,10 +1345,10 @@ export default function DishEditor() {
{recipe.images.map(img => ( {recipe.images.map(img => (
<div key={img.id} style={styles.imageCard}> <div key={img.id} style={styles.imageCard}>
<img <img
src={`/api/recipes/${recipeId}/images/${img.id}?token=${token}`} src={`/kitchen/api/recipes/${recipeId}/images/${img.id}?token=${token}`}
alt={img.caption || 'Dish image'} alt={img.caption || 'Dish image'}
style={{ ...styles.imageThumb, cursor: 'pointer' }} style={{ ...styles.imageThumb, cursor: 'pointer' }}
onClick={() => setLightboxImg(`/api/recipes/${recipeId}/images/${img.id}?token=${token}`)} onClick={() => setLightboxImg(`/kitchen/api/recipes/${recipeId}/images/${img.id}?token=${token}`)}
/> />
<div style={{ padding: '0.4rem' }}> <div style={{ padding: '0.4rem' }}>
{img.caption && <div style={{ fontSize: '0.8rem', color: '#333', marginTop: '2px' }}>{img.caption}</div>} {img.caption && <div style={{ fontSize: '0.8rem', color: '#333', marginTop: '2px' }}>{img.caption}</div>}

View file

@ -120,7 +120,7 @@ export default function DishList() {
const { data: sections } = useQuery<MenuSection[]>({ const { data: sections } = useQuery<MenuSection[]>({
queryKey: ['dish-courses'], queryKey: ['dish-courses'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes/menu-sections?section_type=dish', { const res = await fetch('/kitchen/api/recipes/menu-sections?section_type=dish', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch sections') if (!res.ok) throw new Error('Failed to fetch sections')
@ -137,7 +137,7 @@ export default function DishList() {
params.set('recipe_type', 'dish') params.set('recipe_type', 'dish')
if (sectionFilter) params.set('menu_section_id', sectionFilter) if (sectionFilter) params.set('menu_section_id', sectionFilter)
if (showArchived) params.set('archived', 'true') if (showArchived) params.set('archived', 'true')
const res = await fetch(`/api/recipes?${params}`, { const res = await fetch(`/kitchen/api/recipes?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch dishes') if (!res.ok) throw new Error('Failed to fetch dishes')
@ -150,7 +150,7 @@ export default function DishList() {
const { data: impactData } = useQuery<{ days: number; recipes: ImpactItem[] }>({ const { data: impactData } = useQuery<{ days: number; recipes: ImpactItem[] }>({
queryKey: ['price-impact-dishes', costChangeDays], queryKey: ['price-impact-dishes', costChangeDays],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/price-impact?days=${costChangeDays}`, { const res = await fetch(`/kitchen/api/recipes/price-impact?days=${costChangeDays}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch price impact') if (!res.ok) throw new Error('Failed to fetch price impact')
@ -167,7 +167,7 @@ export default function DishList() {
const { data: costTrendRaw } = useQuery<{ snapshots: CostTrendSnapshot[] }>({ const { data: costTrendRaw } = useQuery<{ snapshots: CostTrendSnapshot[] }>({
queryKey: ['cost-trend', expandedCostId], queryKey: ['cost-trend', expandedCostId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${expandedCostId}/cost-trend`, { const res = await fetch(`/kitchen/api/recipes/${expandedCostId}/cost-trend`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch cost trend') if (!res.ok) throw new Error('Failed to fetch cost trend')
@ -178,7 +178,7 @@ export default function DishList() {
const createMutation = useMutation({ const createMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/recipes', { const res = await fetch('/kitchen/api/recipes', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -195,7 +195,7 @@ export default function DishList() {
const duplicateMutation = useMutation({ const duplicateMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/${id}/duplicate`, { const res = await fetch(`/kitchen/api/recipes/${id}/duplicate`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -210,7 +210,7 @@ export default function DishList() {
const archiveMutation = useMutation({ const archiveMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/${id}`, { const res = await fetch(`/kitchen/api/recipes/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -221,7 +221,7 @@ export default function DishList() {
const unarchiveMutation = useMutation({ const unarchiveMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/${id}`, { const res = await fetch(`/kitchen/api/recipes/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ is_archived: false }), body: JSON.stringify({ is_archived: false }),
@ -233,7 +233,7 @@ export default function DishList() {
const createSectionMutation = useMutation({ const createSectionMutation = useMutation({
mutationFn: async (name: string) => { mutationFn: async (name: string) => {
const res = await fetch('/api/recipes/menu-sections', { const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, section_type: 'dish' }), body: JSON.stringify({ name, section_type: 'dish' }),
@ -250,7 +250,7 @@ export default function DishList() {
const updateSectionMutation = useMutation({ const updateSectionMutation = useMutation({
mutationFn: async ({ id, name }: { id: number; name: string }) => { mutationFn: async ({ id, name }: { id: number; name: string }) => {
const res = await fetch(`/api/recipes/menu-sections/${id}`, { const res = await fetch(`/kitchen/api/recipes/menu-sections/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name }), body: JSON.stringify({ name }),
@ -268,7 +268,7 @@ export default function DishList() {
const deleteSectionMutation = useMutation({ const deleteSectionMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/menu-sections/${id}`, { const res = await fetch(`/kitchen/api/recipes/menu-sections/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -284,7 +284,7 @@ export default function DishList() {
const { data: flagCategories } = useQuery<Array<{ id: number; name: string; flags: Array<{ id: number; name: string; code: string | null }> }>>({ const { data: flagCategories } = useQuery<Array<{ id: number; name: string; flags: Array<{ id: number; name: string; code: string | null }> }>>({
queryKey: ['food-flag-categories'], queryKey: ['food-flag-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/food-flags/categories', { const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch flag categories') if (!res.ok) throw new Error('Failed to fetch flag categories')

View file

@ -125,7 +125,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
const { data: settings } = useQuery<{ llm_enabled?: boolean; anthropic_api_key_set?: boolean }>({ const { data: settings } = useQuery<{ llm_enabled?: boolean; anthropic_api_key_set?: boolean }>({
queryKey: ['settings'], queryKey: ['settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings', { headers: { Authorization: `Bearer ${token}` } }) const res = await fetch('/kitchen/api/settings', { headers: { Authorization: `Bearer ${token}` } })
if (!res.ok) return {} if (!res.ok) return {}
return res.json() return res.json()
}, },
@ -136,7 +136,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
const { data: dispute, isLoading, error } = useQuery<DisputeDetail>({ const { data: dispute, isLoading, error } = useQuery<DisputeDetail>({
queryKey: ['dispute', disputeId], queryKey: ['dispute', disputeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/disputes/${disputeId}`, { const res = await fetch(`/kitchen/api/disputes/${disputeId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch dispute') if (!res.ok) throw new Error('Failed to fetch dispute')
@ -147,7 +147,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
const updateMutation = useMutation({ const updateMutation = useMutation({
mutationFn: async (data: { status?: string; priority?: string; supplier_response?: string; supplier_contact_name?: string; title?: string; description?: string }) => { mutationFn: async (data: { status?: string; priority?: string; supplier_response?: string; supplier_contact_name?: string; title?: string; description?: string }) => {
const res = await fetch(`/api/disputes/${disputeId}`, { const res = await fetch(`/kitchen/api/disputes/${disputeId}`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -172,7 +172,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
const deleteMutation = useMutation({ const deleteMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch(`/api/disputes/${disputeId}`, { const res = await fetch(`/kitchen/api/disputes/${disputeId}`, {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -251,7 +251,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
setAiEmailSubject('') setAiEmailSubject('')
setAiEmailBody('') setAiEmailBody('')
try { try {
const res = await fetch(`/api/disputes/${disputeId}/draft-email`, { const res = await fetch(`/kitchen/api/disputes/${disputeId}/draft-email`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -290,7 +290,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
params.append('description', uploadDescription.trim()) params.append('description', uploadDescription.trim())
} }
const res = await fetch(`/api/disputes/${disputeId}/attachments?${params}`, { const res = await fetch(`/kitchen/api/disputes/${disputeId}/attachments?${params}`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,

View file

@ -59,7 +59,7 @@ export default function Disputes() {
const { data: suppliersData } = useQuery<{ suppliers: Array<{ id: number; name: string }> }>({ const { data: suppliersData } = useQuery<{ suppliers: Array<{ id: number; name: string }> }>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch suppliers') if (!res.ok) throw new Error('Failed to fetch suppliers')
@ -83,7 +83,7 @@ export default function Disputes() {
const { data, isLoading, error } = useQuery<DisputeListResponse>({ const { data, isLoading, error } = useQuery<DisputeListResponse>({
queryKey: ['disputes', statusFilter, priorityFilter, supplierFilter, dateFilter], queryKey: ['disputes', statusFilter, priorityFilter, supplierFilter, dateFilter],
queryFn: async () => { queryFn: async () => {
const url = queryString ? `/api/disputes?${queryString}` : '/api/disputes' const url = queryString ? `/kitchen/api/disputes?${queryString}` : '/kitchen/api/disputes'
const res = await fetch(url, { const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })

View file

@ -128,7 +128,7 @@ export default function EventOrderEditor() {
const { data: order } = useQuery<EventOrderDetail>({ const { data: order } = useQuery<EventOrderDetail>({
queryKey: ['event-order', orderId], queryKey: ['event-order', orderId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/event-orders/${orderId}`, { const res = await fetch(`/kitchen/api/event-orders/${orderId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Not found') if (!res.ok) throw new Error('Not found')
@ -142,7 +142,7 @@ export default function EventOrderEditor() {
const { data: recipes } = useQuery<RecipeOption[]>({ const { data: recipes } = useQuery<RecipeOption[]>({
queryKey: ['recipes-for-event', recipeType], queryKey: ['recipes-for-event', recipeType],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes?recipe_type=${recipeType}`, { const res = await fetch(`/kitchen/api/recipes?recipe_type=${recipeType}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed') if (!res.ok) throw new Error('Failed')
@ -155,7 +155,7 @@ export default function EventOrderEditor() {
const { data: menus } = useQuery<MenuOption[]>({ const { data: menus } = useQuery<MenuOption[]>({
queryKey: ['menus-for-event'], queryKey: ['menus-for-event'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/menus', { const res = await fetch('/kitchen/api/menus', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed') if (!res.ok) throw new Error('Failed')
@ -168,7 +168,7 @@ export default function EventOrderEditor() {
const { data: menuDetail } = useQuery<MenuDetail>({ const { data: menuDetail } = useQuery<MenuDetail>({
queryKey: ['menu-detail-for-event', selectedMenuId], queryKey: ['menu-detail-for-event', selectedMenuId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/menus/${selectedMenuId}`, { const res = await fetch(`/kitchen/api/menus/${selectedMenuId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed') if (!res.ok) throw new Error('Failed')
@ -181,7 +181,7 @@ export default function EventOrderEditor() {
queryKey: ['event-shopping-list', orderId, groupBySupplier], queryKey: ['event-shopping-list', orderId, groupBySupplier],
queryFn: async () => { queryFn: async () => {
const params = groupBySupplier ? '?group_by_supplier=true' : '' const params = groupBySupplier ? '?group_by_supplier=true' : ''
const res = await fetch(`/api/event-orders/${orderId}/shopping-list${params}`, { const res = await fetch(`/kitchen/api/event-orders/${orderId}/shopping-list${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -191,7 +191,7 @@ export default function EventOrderEditor() {
const addItemMutation = useMutation({ const addItemMutation = useMutation({
mutationFn: async (data: { recipe_id: number; quantity: number }) => { mutationFn: async (data: { recipe_id: number; quantity: number }) => {
const res = await fetch(`/api/event-orders/${orderId}/items`, { const res = await fetch(`/kitchen/api/event-orders/${orderId}/items`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -207,7 +207,7 @@ export default function EventOrderEditor() {
const bulkAddMutation = useMutation({ const bulkAddMutation = useMutation({
mutationFn: async (items: Array<{ recipe_id: number; quantity: number; notes?: string }>) => { mutationFn: async (items: Array<{ recipe_id: number; quantity: number; notes?: string }>) => {
const res = await fetch(`/api/event-orders/${orderId}/items/bulk`, { const res = await fetch(`/kitchen/api/event-orders/${orderId}/items/bulk`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ items }), body: JSON.stringify({ items }),
@ -224,7 +224,7 @@ export default function EventOrderEditor() {
const removeItemMutation = useMutation({ const removeItemMutation = useMutation({
mutationFn: async (itemId: number) => { mutationFn: async (itemId: number) => {
const res = await fetch(`/api/event-orders/items/${itemId}`, { const res = await fetch(`/kitchen/api/event-orders/items/${itemId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -238,7 +238,7 @@ export default function EventOrderEditor() {
const updateStatusMutation = useMutation({ const updateStatusMutation = useMutation({
mutationFn: async (status: string) => { mutationFn: async (status: string) => {
const res = await fetch(`/api/event-orders/${orderId}`, { const res = await fetch(`/kitchen/api/event-orders/${orderId}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ status }), body: JSON.stringify({ status }),

View file

@ -28,7 +28,7 @@ export default function EventOrders() {
const { data: orders, isLoading } = useQuery<EventOrderItem[]>({ const { data: orders, isLoading } = useQuery<EventOrderItem[]>({
queryKey: ['event-orders'], queryKey: ['event-orders'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/event-orders', { const res = await fetch('/kitchen/api/event-orders', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed') if (!res.ok) throw new Error('Failed')
@ -39,7 +39,7 @@ export default function EventOrders() {
const createMutation = useMutation({ const createMutation = useMutation({
mutationFn: async (data: { name: string; event_date?: string; notes?: string }) => { mutationFn: async (data: { name: string; event_date?: string; notes?: string }) => {
const res = await fetch('/api/event-orders', { const res = await fetch('/kitchen/api/event-orders', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -56,7 +56,7 @@ export default function EventOrders() {
const deleteMutation = useMutation({ const deleteMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/event-orders/${id}`, { const res = await fetch(`/kitchen/api/event-orders/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })

View file

@ -317,7 +317,7 @@ export default function GPReport() {
const { data, isLoading, error } = useQuery<DateRangeGPResponse>({ const { data, isLoading, error } = useQuery<DateRangeGPResponse>({
queryKey: ['gp-range', submittedFromDate, submittedToDate], queryKey: ['gp-range', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/gp/range?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/reports/gp/range?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch GP data') if (!res.ok) throw new Error('Failed to fetch GP data')
@ -331,7 +331,7 @@ export default function GPReport() {
const { data: chartData } = useQuery<DailyChartData>({ const { data: chartData } = useQuery<DailyChartData>({
queryKey: ['gp-daily', submittedFromDate, submittedToDate], queryKey: ['gp-daily', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/gp/daily?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/reports/gp/daily?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch chart data') if (!res.ok) throw new Error('Failed to fetch chart data')
@ -345,7 +345,7 @@ export default function GPReport() {
const { data: topSellers, isLoading: topSellersLoading } = useQuery<TopSellersResponse>({ const { data: topSellers, isLoading: topSellersLoading } = useQuery<TopSellersResponse>({
queryKey: ['gp-top-sellers', submittedFromDate, submittedToDate], queryKey: ['gp-top-sellers', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/gp/top-sellers?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/reports/gp/top-sellers?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) { if (!res.ok) {

View file

@ -83,7 +83,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
const { data: categories } = useQuery<FlagCategory[]>({ const { data: categories } = useQuery<FlagCategory[]>({
queryKey: ['food-flag-categories'], queryKey: ['food-flag-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/food-flags/categories', { const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -96,7 +96,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
const { data: currentFlags } = useQuery<IngredientFlagInfo[]>({ const { data: currentFlags } = useQuery<IngredientFlagInfo[]>({
queryKey: ['ingredient-flags', ingredientId], queryKey: ['ingredient-flags', ingredientId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/ingredients/${ingredientId}/flags`, { const res = await fetch(`/kitchen/api/ingredients/${ingredientId}/flags`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -109,7 +109,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
const { data: currentNones } = useQuery<{ none_category_ids: number[] }>({ const { data: currentNones } = useQuery<{ none_category_ids: number[] }>({
queryKey: ['ingredient-flag-nones', ingredientId], queryKey: ['ingredient-flag-nones', ingredientId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/ingredients/${ingredientId}/flags/nones`, { const res = await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/nones`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return { none_category_ids: [] } if (!res.ok) return { none_category_ids: [] }
@ -122,7 +122,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
const { data: currentDismissals } = useQuery<DismissalInfo[]>({ const { data: currentDismissals } = useQuery<DismissalInfo[]>({
queryKey: ['ingredient-flag-dismissals', ingredientId], queryKey: ['ingredient-flag-dismissals', ingredientId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/ingredients/${ingredientId}/flags/dismissals`, { const res = await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/dismissals`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -139,7 +139,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
if (debouncedName) params.set('name', debouncedName) if (debouncedName) params.set('name', debouncedName)
if (debouncedLineItem) params.set('line_item', debouncedLineItem) if (debouncedLineItem) params.set('line_item', debouncedLineItem)
if (debouncedText) params.set('text', debouncedText) if (debouncedText) params.set('text', debouncedText)
const res = await fetch(`/api/food-flags/suggest?${params}`, { const res = await fetch(`/kitchen/api/food-flags/suggest?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -216,7 +216,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
// For edit mode, persist to API // For edit mode, persist to API
if (ingredientId) { if (ingredientId) {
fetch(`/api/ingredients/${ingredientId}/flags`, { fetch(`/kitchen/api/ingredients/${ingredientId}/flags`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ food_flag_ids: [...newFlags] }), body: JSON.stringify({ food_flag_ids: [...newFlags] }),
@ -253,7 +253,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
const catFlags = categories.find(c => c.id === catId)?.flags || [] const catFlags = categories.find(c => c.id === catId)?.flags || []
const hasActiveFlags = catFlags.some(f => newFlags.has(f.id)) const hasActiveFlags = catFlags.some(f => newFlags.has(f.id))
if (!hasActiveFlags) { if (!hasActiveFlags) {
fetch(`/api/ingredients/${ingredientId}/flags/none`, { fetch(`/kitchen/api/ingredients/${ingredientId}/flags/none`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ category_id: catId }), body: JSON.stringify({ category_id: catId }),
@ -325,7 +325,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
if (ingredientId) { if (ingredientId) {
setSaving(true) setSaving(true)
try { try {
await fetch(`/api/ingredients/${ingredientId}/flags`, { await fetch(`/kitchen/api/ingredients/${ingredientId}/flags`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ food_flag_ids: [...newFlags] }), body: JSON.stringify({ food_flag_ids: [...newFlags] }),
@ -356,7 +356,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
if (ingredientId) { if (ingredientId) {
setSaving(true) setSaving(true)
try { try {
await fetch(`/api/ingredients/${ingredientId}/flags/none`, { await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/none`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ category_id: categoryId }), body: JSON.stringify({ category_id: categoryId }),
@ -393,7 +393,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
// Edit mode: persist immediately // Edit mode: persist immediately
if (ingredientId) { if (ingredientId) {
try { try {
const res = await fetch(`/api/ingredients/${ingredientId}/flags/dismissals`, { const res = await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/dismissals`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(dismissal), body: JSON.stringify(dismissal),
@ -421,7 +421,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
// Edit mode: delete from API // Edit mode: delete from API
if (ingredientId && dismissal.id) { if (ingredientId && dismissal.id) {
try { try {
await fetch(`/api/ingredients/${ingredientId}/flags/dismissals/${dismissal.id}`, { await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/dismissals/${dismissal.id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -452,7 +452,7 @@ export default function IngredientFlagEditor({ ingredientId, token, onChange, on
if (ingredientId) { if (ingredientId) {
setSaving(true) setSaving(true)
try { try {
await fetch(`/api/ingredients/${ingredientId}/flags`, { await fetch(`/kitchen/api/ingredients/${ingredientId}/flags`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ food_flag_ids: [...newFlags] }), body: JSON.stringify({ food_flag_ids: [...newFlags] }),

View file

@ -30,11 +30,11 @@ const SUPPLIER_LOOKUPS: SupplierLookup[] = [
namePattern: /brakes/i, namePattern: /brakes/i,
label: 'Fetch Brakes', label: 'Fetch Brakes',
color: '#f59e0b', color: '#f59e0b',
endpoint: '/api/food-flags/brakes-lookup', endpoint: '/kitchen/api/food-flags/brakes-lookup',
paramName: 'product_code', paramName: 'product_code',
}, },
// To add another supplier, add an entry here: // To add another supplier, add an entry here:
// { key: 'bidfood', namePattern: /bidfood/i, label: 'Fetch Bidfood', color: '#3b82f6', endpoint: '/api/food-flags/bidfood-lookup', paramName: 'product_code' }, // { key: 'bidfood', namePattern: /bidfood/i, label: 'Fetch Bidfood', color: '#3b82f6', endpoint: '/kitchen/api/food-flags/bidfood-lookup', paramName: 'product_code' },
] ]
function getSupplierLookup(supplierName: string | null | undefined): SupplierLookup | null { function getSupplierLookup(supplierName: string | null | undefined): SupplierLookup | null {
@ -165,7 +165,7 @@ export default function IngredientModal({
const { data: categories } = useQuery<IngredientCategory[]>({ const { data: categories } = useQuery<IngredientCategory[]>({
queryKey: ['ingredient-categories'], queryKey: ['ingredient-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/ingredients/categories', { const res = await fetch('/kitchen/api/ingredients/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch categories') if (!res.ok) throw new Error('Failed to fetch categories')
@ -177,7 +177,7 @@ export default function IngredientModal({
const { data: liSuppliers } = useQuery<Array<{ id: number; name: string }>>({ const { data: liSuppliers } = useQuery<Array<{ id: number; name: string }>>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { headers: { Authorization: `Bearer ${token}` } }) const res = await fetch('/kitchen/api/suppliers/', { headers: { Authorization: `Bearer ${token}` } })
if (!res.ok) return [] if (!res.ok) return []
const data = await res.json() const data = await res.json()
return data.suppliers || data || [] return data.suppliers || data || []
@ -199,7 +199,7 @@ export default function IngredientModal({
}>>({ }>>({
queryKey: ['ingredient-sources', editingIngredient?.id], queryKey: ['ingredient-sources', editingIngredient?.id],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/ingredients/${editingIngredient!.id}/sources`, { const res = await fetch(`/kitchen/api/ingredients/${editingIngredient!.id}/sources`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -216,7 +216,7 @@ export default function IngredientModal({
if (debouncedLiSearch) params.set('q', debouncedLiSearch) if (debouncedLiSearch) params.set('q', debouncedLiSearch)
if (liSupplierId) params.set('supplier_id', liSupplierId) if (liSupplierId) params.set('supplier_id', liSupplierId)
params.set('limit', '100') params.set('limit', '100')
const res = await fetch(`/api/search/line-items?${params}`, { const res = await fetch(`/kitchen/api/search/line-items?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return { items: [], total_count: 0 } if (!res.ok) return { items: [], total_count: 0 }
@ -230,7 +230,7 @@ export default function IngredientModal({
const { data: settingsData } = useQuery<{ llm_enabled: boolean }>({ const { data: settingsData } = useQuery<{ llm_enabled: boolean }>({
queryKey: ['settings-llm-check'], queryKey: ['settings-llm-check'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/', { const res = await fetch('/kitchen/api/settings/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return { llm_enabled: false } if (!res.ok) return { llm_enabled: false }
@ -252,7 +252,7 @@ export default function IngredientModal({
const runAnalysis = async () => { const runAnalysis = async () => {
setLlmAnalysing(true) setLlmAnalysing(true)
try { try {
const res = await fetch('/api/food-flags/analyse-label', { const res = await fetch('/kitchen/api/food-flags/analyse-label', {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -294,7 +294,7 @@ export default function IngredientModal({
const fetchYield = async () => { const fetchYield = async () => {
setYieldHintLoading(true) setYieldHintLoading(true)
try { try {
const res = await fetch(`/api/ingredients/ai-estimate-yield?name=${encodeURIComponent(debouncedFormName.trim())}`, { const res = await fetch(`/kitchen/api/ingredients/ai-estimate-yield?name=${encodeURIComponent(debouncedFormName.trim())}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok && !cancelled) { if (res.ok && !cancelled) {
@ -434,8 +434,8 @@ export default function IngredientModal({
reader.onload = (e) => setLabelPreview(e.target?.result as string) reader.onload = (e) => setLabelPreview(e.target?.result as string)
reader.readAsDataURL(file) reader.readAsDataURL(file)
const url = editingIngredient const url = editingIngredient
? `/api/food-flags/scan-label/${editingIngredient.id}` ? `/kitchen/api/food-flags/scan-label/${editingIngredient.id}`
: '/api/food-flags/scan-label' : '/kitchen/api/food-flags/scan-label'
const res = await fetch(url, { const res = await fetch(url, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
@ -467,7 +467,7 @@ export default function IngredientModal({
} }
if (selectedLi.most_recent_price) sourceData.latest_unit_price = selectedLi.most_recent_price if (selectedLi.most_recent_price) sourceData.latest_unit_price = selectedLi.most_recent_price
if (selectedLi.most_recent_invoice_id) sourceData.invoice_id = selectedLi.most_recent_invoice_id if (selectedLi.most_recent_invoice_id) sourceData.invoice_id = selectedLi.most_recent_invoice_id
const srcRes = await fetch(`/api/ingredients/${ingredientId}/sources`, { const srcRes = await fetch(`/kitchen/api/ingredients/${ingredientId}/sources`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(sourceData), body: JSON.stringify(sourceData),
@ -484,7 +484,7 @@ export default function IngredientModal({
const applyPendingFlags = async (ingredientId: number) => { const applyPendingFlags = async (ingredientId: number) => {
if (pendingFlagIds.length > 0) { if (pendingFlagIds.length > 0) {
try { try {
await fetch(`/api/ingredients/${ingredientId}/flags`, { await fetch(`/kitchen/api/ingredients/${ingredientId}/flags`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ food_flag_ids: pendingFlagIds }), body: JSON.stringify({ food_flag_ids: pendingFlagIds }),
@ -493,7 +493,7 @@ export default function IngredientModal({
} }
for (const catId of pendingNoneCatIds) { for (const catId of pendingNoneCatIds) {
try { try {
await fetch(`/api/ingredients/${ingredientId}/flags/none`, { await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/none`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ category_id: catId }), body: JSON.stringify({ category_id: catId }),
@ -503,7 +503,7 @@ export default function IngredientModal({
// Batch persist dismissals from create mode // Batch persist dismissals from create mode
if (pendingDismissals.length > 0) { if (pendingDismissals.length > 0) {
try { try {
await fetch(`/api/ingredients/${ingredientId}/flags/dismissals/batch`, { await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/dismissals/batch`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ dismissals: pendingDismissals }), body: JSON.stringify({ dismissals: pendingDismissals }),
@ -529,7 +529,7 @@ export default function IngredientModal({
setFormFree(editingIngredient.is_free || false) setFormFree(editingIngredient.is_free || false)
setFormPrepackaged(editingIngredient.is_prepackaged || false) setFormPrepackaged(editingIngredient.is_prepackaged || false)
setFormProductIngredients(editingIngredient.product_ingredients || '') setFormProductIngredients(editingIngredient.product_ingredients || '')
setLabelPreview(editingIngredient.has_label_image ? `/api/ingredients/${editingIngredient.id}/label-image?token=${encodeURIComponent(token || '')}` : null) setLabelPreview(editingIngredient.has_label_image ? `/kitchen/api/ingredients/${editingIngredient.id}/label-image?token=${encodeURIComponent(token || '')}` : null)
setLiSearch(editingIngredient.name) setLiSearch(editingIngredient.name)
} else { } else {
const name = prePopulateName || '' const name = prePopulateName || ''
@ -550,7 +550,7 @@ export default function IngredientModal({
} else if (preSelectLineItem.description) { } else if (preSelectLineItem.description) {
// LLM FEATURE — AI pack size deduction when regex can't parse // LLM FEATURE — AI pack size deduction when regex can't parse
setAiPackLoading(true) setAiPackLoading(true)
fetch(`/api/ingredients/ai-pack-size?description=${encodeURIComponent(preSelectLineItem.description)}`, { fetch(`/kitchen/api/ingredients/ai-pack-size?description=${encodeURIComponent(preSelectLineItem.description)}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}).then(res => res.ok ? res.json() : null).then(data => { }).then(res => res.ok ? res.json() : null).then(data => {
if (data?.pack_quantity && data?.unit_size) { if (data?.pack_quantity && data?.unit_size) {
@ -589,7 +589,7 @@ export default function IngredientModal({
} }
const timer = setTimeout(async () => { const timer = setTimeout(async () => {
try { try {
const res = await fetch(`/api/ingredients/check-duplicate?name=${encodeURIComponent(formName)}`, { const res = await fetch(`/kitchen/api/ingredients/check-duplicate?name=${encodeURIComponent(formName)}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok) { if (res.ok) {
@ -605,7 +605,7 @@ export default function IngredientModal({
const createMutation = useMutation({ const createMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/ingredients', { const res = await fetch('/kitchen/api/ingredients', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -628,7 +628,7 @@ export default function IngredientModal({
const updateMutation = useMutation({ const updateMutation = useMutation({
mutationFn: async ({ id, data }: { id: number; data: Record<string, unknown> }) => { mutationFn: async ({ id, data }: { id: number; data: Record<string, unknown> }) => {
const res = await fetch(`/api/ingredients/${id}`, { const res = await fetch(`/kitchen/api/ingredients/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -988,7 +988,7 @@ export default function IngredientModal({
title="Click to enlarge" title="Click to enlarge"
> >
<img <img
src={`/api/invoices/${selectedLi.most_recent_invoice_id}/line-items/${selectedLi.most_recent_line_number}/preview?token=${encodeURIComponent(token || '')}`} src={`/kitchen/api/invoices/${selectedLi.most_recent_invoice_id}/line-items/${selectedLi.most_recent_line_number}/preview?token=${encodeURIComponent(token || '')}`}
alt="Invoice line item" alt="Invoice line item"
style={{ width: '100%', height: 'auto', display: 'block' }} style={{ width: '100%', height: 'auto', display: 'block' }}
onError={(e) => { (e.target as HTMLImageElement).parentElement!.style.display = 'none' }} onError={(e) => { (e.target as HTMLImageElement).parentElement!.style.display = 'none' }}
@ -1058,7 +1058,7 @@ export default function IngredientModal({
{selectedLi.most_recent_line_number != null && ( {selectedLi.most_recent_line_number != null && (
<div style={{ flex: '0 0 auto', maxWidth: '120px', borderRadius: '4px', overflow: 'hidden', border: '1px solid #e0e0e0' }}> <div style={{ flex: '0 0 auto', maxWidth: '120px', borderRadius: '4px', overflow: 'hidden', border: '1px solid #e0e0e0' }}>
<img <img
src={`/api/invoices/${selectedLi.most_recent_invoice_id}/line-items/${selectedLi.most_recent_line_number}/preview/field/product_code?token=${encodeURIComponent(token || '')}`} src={`/kitchen/api/invoices/${selectedLi.most_recent_invoice_id}/line-items/${selectedLi.most_recent_line_number}/preview/field/product_code?token=${encodeURIComponent(token || '')}`}
alt="Product code from invoice" alt="Product code from invoice"
style={{ width: '100%', height: 'auto', display: 'block' }} style={{ width: '100%', height: 'auto', display: 'block' }}
onError={(e) => { (e.target as HTMLImageElement).parentElement!.style.display = 'none' }} onError={(e) => { (e.target as HTMLImageElement).parentElement!.style.display = 'none' }}
@ -1246,7 +1246,7 @@ export default function IngredientModal({
{'\u2715'} {'\u2715'}
</button> </button>
<img <img
src={`/api/invoices/${selectedLi.most_recent_invoice_id}/line-items/${selectedLi.most_recent_line_number}/preview?token=${encodeURIComponent(token || '')}`} src={`/kitchen/api/invoices/${selectedLi.most_recent_invoice_id}/line-items/${selectedLi.most_recent_line_number}/preview?token=${encodeURIComponent(token || '')}`}
alt="Invoice line item" alt="Invoice line item"
style={{ maxWidth: '95vw', maxHeight: '90vh', borderRadius: '8px', boxShadow: '0 4px 20px rgba(0,0,0,0.3)' }} style={{ maxWidth: '95vw', maxHeight: '90vh', borderRadius: '8px', boxShadow: '0 4px 20px rgba(0,0,0,0.3)' }}
/> />

View file

@ -66,7 +66,7 @@ export default function Ingredients() {
const { data: categories } = useQuery<IngredientCategory[]>({ const { data: categories } = useQuery<IngredientCategory[]>({
queryKey: ['ingredient-categories'], queryKey: ['ingredient-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/ingredients/categories', { const res = await fetch('/kitchen/api/ingredients/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch categories') if (!res.ok) throw new Error('Failed to fetch categories')
@ -84,7 +84,7 @@ export default function Ingredients() {
if (categoryFilter) params.set('category_id', categoryFilter) if (categoryFilter) params.set('category_id', categoryFilter)
if (showUnmapped) params.set('unmapped', 'true') if (showUnmapped) params.set('unmapped', 'true')
if (showArchived) params.set('archived', 'true') if (showArchived) params.set('archived', 'true')
const res = await fetch(`/api/ingredients?${params}`, { const res = await fetch(`/kitchen/api/ingredients?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch ingredients') if (!res.ok) throw new Error('Failed to fetch ingredients')
@ -97,7 +97,7 @@ export default function Ingredients() {
const { data: sources } = useQuery<SourceItem[]>({ const { data: sources } = useQuery<SourceItem[]>({
queryKey: ['ingredient-sources', expandedId], queryKey: ['ingredient-sources', expandedId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/ingredients/${expandedId}/sources`, { const res = await fetch(`/kitchen/api/ingredients/${expandedId}/sources`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch sources') if (!res.ok) throw new Error('Failed to fetch sources')
@ -108,7 +108,7 @@ export default function Ingredients() {
const archiveMutation = useMutation({ const archiveMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/ingredients/${id}`, { const res = await fetch(`/kitchen/api/ingredients/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -119,7 +119,7 @@ export default function Ingredients() {
const unarchiveMutation = useMutation({ const unarchiveMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/ingredients/${id}`, { const res = await fetch(`/kitchen/api/ingredients/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ is_archived: false }), body: JSON.stringify({ is_archived: false }),

View file

@ -100,7 +100,7 @@ export default function InvoiceList() {
const { data: suppliers } = useQuery<Supplier[]>({ const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -119,7 +119,7 @@ export default function InvoiceList() {
const { data, isLoading, error } = useQuery<InvoiceListResponse>({ const { data, isLoading, error } = useQuery<InvoiceListResponse>({
queryKey: ['invoices', statusFilter, supplierFilter, dateFrom, dateTo], queryKey: ['invoices', statusFilter, supplierFilter, dateFrom, dateTo],
queryFn: async () => { queryFn: async () => {
const url = queryString ? `/api/invoices/?${queryString}` : '/api/invoices/' const url = queryString ? `/kitchen/api/invoices/?${queryString}` : '/kitchen/api/invoices/'
const res = await fetch(url, { const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -137,7 +137,7 @@ export default function InvoiceList() {
params.set('status', 'confirmed') params.set('status', 'confirmed')
params.set('limit', '20') params.set('limit', '20')
params.set('sort', 'recent') params.set('sort', 'recent')
const res = await fetch(`/api/invoices/?${params}`, { const res = await fetch(`/kitchen/api/invoices/?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch completed invoices') if (!res.ok) throw new Error('Failed to fetch completed invoices')

View file

@ -87,7 +87,7 @@ export default function LineItemHistoryModal({
if (dateFrom) params.set('date_from', dateFrom) if (dateFrom) params.set('date_from', dateFrom)
if (dateTo) params.set('date_to', dateTo) if (dateTo) params.set('date_to', dateTo)
const res = await fetch(`/api/search/line-items/history?${params}`, { const res = await fetch(`/kitchen/api/search/line-items/history?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch history') if (!res.ok) throw new Error('Failed to fetch history')
@ -99,7 +99,7 @@ export default function LineItemHistoryModal({
// Acknowledge price mutation // Acknowledge price mutation
const acknowledgeMutation = useMutation({ const acknowledgeMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/search/line-items/acknowledge-price', { const res = await fetch('/kitchen/api/search/line-items/acknowledge-price', {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,

View file

@ -64,7 +64,7 @@ export default function LinkDisputeModal({
const { data: disputes, isLoading } = useQuery<OpenDispute[]>({ const { data: disputes, isLoading } = useQuery<OpenDispute[]>({
queryKey: ['open-disputes', supplierId], queryKey: ['open-disputes', supplierId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/disputes/supplier/${supplierId}/open`, { const res = await fetch(`/kitchen/api/disputes/supplier/${supplierId}/open`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch disputes') if (!res.ok) throw new Error('Failed to fetch disputes')
@ -78,7 +78,7 @@ export default function LinkDisputeModal({
mutationFn: async () => { mutationFn: async () => {
if (!selectedDisputeId) throw new Error('No dispute selected') if (!selectedDisputeId) throw new Error('No dispute selected')
const res = await fetch(`/api/disputes/${selectedDisputeId}/link-credit-note`, { const res = await fetch(`/kitchen/api/disputes/${selectedDisputeId}/link-credit-note`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View file

@ -95,7 +95,7 @@ export default function MapLineItemsModal({ ingredient, onClose, onSaved }: MapL
const { data: suppliers } = useQuery<Supplier[]>({ const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { headers: { Authorization: `Bearer ${token}` } }) const res = await fetch('/kitchen/api/suppliers/', { headers: { Authorization: `Bearer ${token}` } })
if (!res.ok) return [] if (!res.ok) return []
const data = await res.json() const data = await res.json()
return data.suppliers || data || [] return data.suppliers || data || []
@ -112,7 +112,7 @@ export default function MapLineItemsModal({ ingredient, onClose, onSaved }: MapL
params.set('date_from', dateFrom) params.set('date_from', dateFrom)
params.set('date_to', dateTo) params.set('date_to', dateTo)
params.set('limit', '50') params.set('limit', '50')
const res = await fetch(`/api/search/line-items?${params}`, { const res = await fetch(`/kitchen/api/search/line-items?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return { items: [], total_count: 0 } if (!res.ok) return { items: [], total_count: 0 }
@ -206,7 +206,7 @@ export default function MapLineItemsModal({ ingredient, onClose, onSaved }: MapL
sourceData.invoice_id = selectedItem.most_recent_invoice_id sourceData.invoice_id = selectedItem.most_recent_invoice_id
} }
const res = await fetch(`/api/ingredients/${ingredient.id}/sources`, { const res = await fetch(`/kitchen/api/ingredients/${ingredient.id}/sources`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(sourceData), body: JSON.stringify(sourceData),
@ -233,7 +233,7 @@ export default function MapLineItemsModal({ ingredient, onClose, onSaved }: MapL
// Preview URL for the selected line item // Preview URL for the selected line item
const previewUrl = selectedItem?.most_recent_invoice_id && selectedItem?.most_recent_line_number != null const previewUrl = selectedItem?.most_recent_invoice_id && selectedItem?.most_recent_line_number != null
? `/api/invoices/${selectedItem.most_recent_invoice_id}/line-items/${selectedItem.most_recent_line_number}/preview?token=${token}` ? `/kitchen/api/invoices/${selectedItem.most_recent_invoice_id}/line-items/${selectedItem.most_recent_line_number}/preview?token=${token}`
: null : null
return ( return (

View file

@ -84,7 +84,7 @@ export default function MenuEditor() {
const { data: menu, isLoading } = useQuery<MenuDetail>({ const { data: menu, isLoading } = useQuery<MenuDetail>({
queryKey: ['menu', menuId], queryKey: ['menu', menuId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/menus/${menuId}`, { const res = await fetch(`/kitchen/api/menus/${menuId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch menu') if (!res.ok) throw new Error('Failed to fetch menu')
@ -97,7 +97,7 @@ export default function MenuEditor() {
// Mutations // Mutations
const updateMenuMutation = useMutation({ const updateMenuMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch(`/api/menus/${menuId}`, { const res = await fetch(`/kitchen/api/menus/${menuId}`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -109,7 +109,7 @@ export default function MenuEditor() {
const addDivMutation = useMutation({ const addDivMutation = useMutation({
mutationFn: async (name: string) => { mutationFn: async (name: string) => {
const res = await fetch(`/api/menus/${menuId}/divisions`, { const res = await fetch(`/kitchen/api/menus/${menuId}/divisions`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name }), body: JSON.stringify({ name }),
@ -125,7 +125,7 @@ export default function MenuEditor() {
const updateDivMutation = useMutation({ const updateDivMutation = useMutation({
mutationFn: async ({ divId, name }: { divId: number; name: string }) => { mutationFn: async ({ divId, name }: { divId: number; name: string }) => {
const res = await fetch(`/api/menus/${menuId}/divisions/${divId}`, { const res = await fetch(`/kitchen/api/menus/${menuId}/divisions/${divId}`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name }), body: JSON.stringify({ name }),
@ -140,7 +140,7 @@ export default function MenuEditor() {
const deleteDivMutation = useMutation({ const deleteDivMutation = useMutation({
mutationFn: async (divId: number) => { mutationFn: async (divId: number) => {
const res = await fetch(`/api/menus/${menuId}/divisions/${divId}`, { const res = await fetch(`/kitchen/api/menus/${menuId}/divisions/${divId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -151,7 +151,7 @@ export default function MenuEditor() {
const reorderDivsMutation = useMutation({ const reorderDivsMutation = useMutation({
mutationFn: async (ids: number[]) => { mutationFn: async (ids: number[]) => {
const res = await fetch(`/api/menus/${menuId}/divisions/reorder`, { const res = await fetch(`/kitchen/api/menus/${menuId}/divisions/reorder`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ids }), body: JSON.stringify({ ids }),
@ -163,7 +163,7 @@ export default function MenuEditor() {
const updateItemMutation = useMutation({ const updateItemMutation = useMutation({
mutationFn: async ({ itemId, data }: { itemId: number; data: Record<string, unknown> }) => { mutationFn: async ({ itemId, data }: { itemId: number; data: Record<string, unknown> }) => {
const res = await fetch(`/api/menus/${menuId}/items/${itemId}`, { const res = await fetch(`/kitchen/api/menus/${menuId}/items/${itemId}`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -178,7 +178,7 @@ export default function MenuEditor() {
const deleteItemMutation = useMutation({ const deleteItemMutation = useMutation({
mutationFn: async (itemId: number) => { mutationFn: async (itemId: number) => {
const res = await fetch(`/api/menus/${menuId}/items/${itemId}`, { const res = await fetch(`/kitchen/api/menus/${menuId}/items/${itemId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -189,7 +189,7 @@ export default function MenuEditor() {
const republishMutation = useMutation({ const republishMutation = useMutation({
mutationFn: async ({ itemId, confirmed_by_name }: { itemId: number; confirmed_by_name: string }) => { mutationFn: async ({ itemId, confirmed_by_name }: { itemId: number; confirmed_by_name: string }) => {
const res = await fetch(`/api/menus/${menuId}/items/${itemId}/republish`, { const res = await fetch(`/kitchen/api/menus/${menuId}/items/${itemId}/republish`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ confirmed_by_name }), body: JSON.stringify({ confirmed_by_name }),
@ -201,7 +201,7 @@ export default function MenuEditor() {
const reorderItemsMutation = useMutation({ const reorderItemsMutation = useMutation({
mutationFn: async (ids: number[]) => { mutationFn: async (ids: number[]) => {
const res = await fetch(`/api/menus/${menuId}/items/reorder`, { const res = await fetch(`/kitchen/api/menus/${menuId}/items/reorder`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ids }), body: JSON.stringify({ ids }),
@ -213,7 +213,7 @@ export default function MenuEditor() {
const batchRepublishMutation = useMutation({ const batchRepublishMutation = useMutation({
mutationFn: async (body: { confirmed_by_name: string; items: Array<{ id: number; confirmed: boolean }> }) => { mutationFn: async (body: { confirmed_by_name: string; items: Array<{ id: number; confirmed: boolean }> }) => {
const res = await fetch(`/api/menus/${menuId}/republish-stale`, { const res = await fetch(`/kitchen/api/menus/${menuId}/republish-stale`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body), body: JSON.stringify(body),
@ -231,7 +231,7 @@ export default function MenuEditor() {
mutationFn: async ({ itemId, file }: { itemId: number; file: File }) => { mutationFn: async ({ itemId, file }: { itemId: number; file: File }) => {
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
const res = await fetch(`/api/menus/${menuId}/items/${itemId}/image`, { const res = await fetch(`/kitchen/api/menus/${menuId}/items/${itemId}/image`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
body: formData, body: formData,
@ -243,7 +243,7 @@ export default function MenuEditor() {
const deleteImageMutation = useMutation({ const deleteImageMutation = useMutation({
mutationFn: async (itemId: number) => { mutationFn: async (itemId: number) => {
const res = await fetch(`/api/menus/${menuId}/items/${itemId}/image`, { const res = await fetch(`/kitchen/api/menus/${menuId}/items/${itemId}/image`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -471,7 +471,7 @@ export default function MenuEditor() {
{/* Image thumbnail */} {/* Image thumbnail */}
{item.has_image ? ( {item.has_image ? (
<img <img
src={`/api/menus/${menuId}/items/${item.id}/image?token=${token}`} src={`/kitchen/api/menus/${menuId}/items/${item.id}/image?token=${token}`}
alt="" alt=""
style={styles.thumbnail} style={styles.thumbnail}
/> />

View file

@ -39,7 +39,7 @@ export default function MenuFlagMatrix({ menuId, menuName, onClose }: Props) {
const { data, isLoading } = useQuery<MatrixData>({ const { data, isLoading } = useQuery<MatrixData>({
queryKey: ['menu-flag-matrix', menuId], queryKey: ['menu-flag-matrix', menuId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/menus/${menuId}/flags`, { const res = await fetch(`/kitchen/api/menus/${menuId}/flags`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed') if (!res.ok) throw new Error('Failed')

View file

@ -37,7 +37,7 @@ export default function MenuList() {
const { data: menus, isLoading } = useQuery<MenuListItem[]>({ const { data: menus, isLoading } = useQuery<MenuListItem[]>({
queryKey: ['menus'], queryKey: ['menus'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/menus', { const res = await fetch('/kitchen/api/menus', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch menus') if (!res.ok) throw new Error('Failed to fetch menus')
@ -49,7 +49,7 @@ export default function MenuList() {
const createMutation = useMutation({ const createMutation = useMutation({
mutationFn: async (data: { name: string; description: string | null; notes: string | null; preset_divisions: boolean }) => { mutationFn: async (data: { name: string; description: string | null; notes: string | null; preset_divisions: boolean }) => {
const res = await fetch('/api/menus', { const res = await fetch('/kitchen/api/menus', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -72,7 +72,7 @@ export default function MenuList() {
const toggleActiveMutation = useMutation({ const toggleActiveMutation = useMutation({
mutationFn: async ({ id, is_active }: { id: number; is_active: boolean }) => { mutationFn: async ({ id, is_active }: { id: number; is_active: boolean }) => {
const res = await fetch(`/api/menus/${id}`, { const res = await fetch(`/kitchen/api/menus/${id}`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ is_active }), body: JSON.stringify({ is_active }),
@ -84,7 +84,7 @@ export default function MenuList() {
const deleteMutation = useMutation({ const deleteMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/menus/${id}`, { const res = await fetch(`/kitchen/api/menus/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -95,7 +95,7 @@ export default function MenuList() {
const duplicateMutation = useMutation({ const duplicateMutation = useMutation({
mutationFn: async ({ id, name }: { id: number; name: string }) => { mutationFn: async ({ id, name }: { id: number; name: string }) => {
const res = await fetch(`/api/menus/${id}/duplicate`, { const res = await fetch(`/kitchen/api/menus/${id}/duplicate`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name }), body: JSON.stringify({ name }),
@ -116,7 +116,7 @@ export default function MenuList() {
const reorderMutation = useMutation({ const reorderMutation = useMutation({
mutationFn: async (ids: number[]) => { mutationFn: async (ids: number[]) => {
const res = await fetch('/api/menus/reorder', { const res = await fetch('/kitchen/api/menus/reorder', {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ids }), body: JSON.stringify({ ids }),

View file

@ -48,7 +48,7 @@ export default function PriceImpact() {
const { data, isLoading } = useQuery<ImpactData>({ const { data, isLoading } = useQuery<ImpactData>({
queryKey: ['price-impact', days], queryKey: ['price-impact', days],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/price-impact?days=${days}`, { const res = await fetch(`/kitchen/api/recipes/price-impact?days=${days}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch price impact') if (!res.ok) throw new Error('Failed to fetch price impact')

View file

@ -58,7 +58,7 @@ export default function PublishToMenuModal({
const { data: llmSettings } = useQuery<{ llm_enabled: boolean; anthropic_api_key_set: boolean }>({ const { data: llmSettings } = useQuery<{ llm_enabled: boolean; anthropic_api_key_set: boolean }>({
queryKey: ['settings'], queryKey: ['settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/', { headers: { Authorization: `Bearer ${token}` } }) const res = await fetch('/kitchen/api/settings/', { headers: { Authorization: `Bearer ${token}` } })
if (!res.ok) return { llm_enabled: false, anthropic_api_key_set: false } if (!res.ok) return { llm_enabled: false, anthropic_api_key_set: false }
return res.json() return res.json()
}, },
@ -70,7 +70,7 @@ export default function PublishToMenuModal({
if (!recipeIdToUse) return if (!recipeIdToUse) return
setAiDescLoading(true) setAiDescLoading(true)
try { try {
const res = await fetch('/api/menus/generate-description', { const res = await fetch('/kitchen/api/menus/generate-description', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ recipe_id: recipeIdToUse, recipe_name: displayName || recipeName || '', ingredients: [], allergen_flags: [] }), body: JSON.stringify({ recipe_id: recipeIdToUse, recipe_name: displayName || recipeName || '', ingredients: [], allergen_flags: [] }),
@ -87,7 +87,7 @@ export default function PublishToMenuModal({
const { data: dishes } = useQuery<Array<{ id: number; name: string; description: string | null; gross_sell_price: number | null }>>({ const { data: dishes } = useQuery<Array<{ id: number; name: string; description: string | null; gross_sell_price: number | null }>>({
queryKey: ['dishes-for-menu'], queryKey: ['dishes-for-menu'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes?recipe_type=dish', { const res = await fetch('/kitchen/api/recipes?recipe_type=dish', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch dishes') if (!res.ok) throw new Error('Failed to fetch dishes')
@ -100,7 +100,7 @@ export default function PublishToMenuModal({
const { data: menus } = useQuery<Array<{ id: number; name: string; is_active: boolean }>>({ const { data: menus } = useQuery<Array<{ id: number; name: string; is_active: boolean }>>({
queryKey: ['menus-for-publish'], queryKey: ['menus-for-publish'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/menus', { const res = await fetch('/kitchen/api/menus', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch menus') if (!res.ok) throw new Error('Failed to fetch menus')
@ -113,7 +113,7 @@ export default function PublishToMenuModal({
const { data: menuDetail } = useQuery<{ divisions: Division[] }>({ const { data: menuDetail } = useQuery<{ divisions: Division[] }>({
queryKey: ['menu-divisions', selectedMenuId], queryKey: ['menu-divisions', selectedMenuId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/menus/${selectedMenuId}`, { const res = await fetch(`/kitchen/api/menus/${selectedMenuId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed') if (!res.ok) throw new Error('Failed')
@ -129,7 +129,7 @@ export default function PublishToMenuModal({
}>({ }>({
queryKey: ['recipe-flags-for-publish', selectedRecipeId], queryKey: ['recipe-flags-for-publish', selectedRecipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/food-flags/recipes/${selectedRecipeId}/flags`, { const res = await fetch(`/kitchen/api/food-flags/recipes/${selectedRecipeId}/flags`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed') if (!res.ok) throw new Error('Failed')
@ -158,7 +158,7 @@ export default function PublishToMenuModal({
const publishMutation = useMutation({ const publishMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch(`/api/menus/${selectedMenuId}/items`, { const res = await fetch(`/kitchen/api/menus/${selectedMenuId}/items`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({

View file

@ -35,7 +35,7 @@ export default function PurchaseOrderList() {
const { data: suppliersData } = useQuery<{ suppliers: Array<{ id: number; name: string }> }>({ const { data: suppliersData } = useQuery<{ suppliers: Array<{ id: number; name: string }> }>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch suppliers') if (!res.ok) throw new Error('Failed to fetch suppliers')
@ -52,7 +52,7 @@ export default function PurchaseOrderList() {
const { data: poList, refetch } = useQuery<PurchaseOrderSummary[]>({ const { data: poList, refetch } = useQuery<PurchaseOrderSummary[]>({
queryKey: ['purchase-orders', statusFilter, supplierFilter], queryKey: ['purchase-orders', statusFilter, supplierFilter],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/purchase-orders/?${params}`, { const res = await fetch(`/kitchen/api/purchase-orders/?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch purchase orders') if (!res.ok) throw new Error('Failed to fetch purchase orders')

View file

@ -64,7 +64,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
// Load suppliers (including order_email for email button visibility) // Load suppliers (including order_email for email button visibility)
useEffect(() => { useEffect(() => {
if (!token) return if (!token) return
fetch('/api/suppliers/', { headers: { Authorization: `Bearer ${token}` } }) fetch('/kitchen/api/suppliers/', { headers: { Authorization: `Bearer ${token}` } })
.then(r => r.json()) .then(r => r.json())
.then(data => setSuppliers(data.suppliers || data || [])) .then(data => setSuppliers(data.suppliers || data || []))
.catch(() => {}) .catch(() => {})
@ -73,7 +73,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
// Check if SMTP is configured (for email button visibility) // Check if SMTP is configured (for email button visibility)
useEffect(() => { useEffect(() => {
if (!token) return if (!token) return
fetch('/api/settings/', { headers: { Authorization: `Bearer ${token}` } }) fetch('/kitchen/api/settings/', { headers: { Authorization: `Bearer ${token}` } })
.then(r => r.json()) .then(r => r.json())
.then(data => setSmtpConfigured(!!(data.smtp_host && data.smtp_from_email))) .then(data => setSmtpConfigured(!!(data.smtp_host && data.smtp_from_email)))
.catch(() => setSmtpConfigured(false)) .catch(() => setSmtpConfigured(false))
@ -83,7 +83,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
useEffect(() => { useEffect(() => {
if (!poId || !token) return if (!poId || !token) return
setLoading(true) setLoading(true)
fetch(`/api/purchase-orders/${poId}`, { headers: { Authorization: `Bearer ${token}` } }) fetch(`/kitchen/api/purchase-orders/${poId}`, { headers: { Authorization: `Bearer ${token}` } })
.then(r => { .then(r => {
if (!r.ok) throw new Error('Failed to load') if (!r.ok) throw new Error('Failed to load')
return r.json() return r.json()
@ -144,7 +144,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
searchTimeout.current = setTimeout(() => { searchTimeout.current = setTimeout(() => {
const params = new URLSearchParams({ query: searchQuery }) const params = new URLSearchParams({ query: searchQuery })
if (supplierId) params.append('supplier_id', String(supplierId)) if (supplierId) params.append('supplier_id', String(supplierId))
fetch(`/api/purchase-orders/products/search?${params}`, { fetch(`/kitchen/api/purchase-orders/products/search?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
.then(r => r.json()) .then(r => r.json())
@ -243,7 +243,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
} }
try { try {
const url = poId ? `/api/purchase-orders/${poId}` : '/api/purchase-orders/' const url = poId ? `/kitchen/api/purchase-orders/${poId}` : '/kitchen/api/purchase-orders/'
const method = poId ? 'PUT' : 'POST' const method = poId ? 'PUT' : 'POST'
const res = await fetch(url, { const res = await fetch(url, {
method, method,
@ -269,7 +269,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
const form = new FormData() const form = new FormData()
form.append('file', file) form.append('file', file)
try { try {
const res = await fetch(`/api/purchase-orders/${poId}/attachment`, { const res = await fetch(`/kitchen/api/purchase-orders/${poId}/attachment`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
body: form, body: form,
@ -285,7 +285,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
const handleRemoveAttachment = async () => { const handleRemoveAttachment = async () => {
if (!poId || !token) return if (!poId || !token) return
try { try {
await fetch(`/api/purchase-orders/${poId}/attachment`, { await fetch(`/kitchen/api/purchase-orders/${poId}/attachment`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -299,7 +299,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
if (!poId || !token) return if (!poId || !token) return
if (!confirm('Delete this purchase order?')) return if (!confirm('Delete this purchase order?')) return
try { try {
const res = await fetch(`/api/purchase-orders/${poId}`, { const res = await fetch(`/kitchen/api/purchase-orders/${poId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -346,14 +346,14 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
...(orderType === 'single_value' ? { total_amount: totalAmount } : {}), ...(orderType === 'single_value' ? { total_amount: totalAmount } : {}),
} }
try { try {
const res = await fetch('/api/purchase-orders/', { const res = await fetch('/kitchen/api/purchase-orders/', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body), body: JSON.stringify(body),
}) })
if (!res.ok) throw new Error('Failed to save') if (!res.ok) throw new Error('Failed to save')
const data = await res.json() const data = await res.json()
window.open(`/api/purchase-orders/${data.id}/preview?token=${encodeURIComponent(token || '')}`, '_blank') window.open(`/kitchen/api/purchase-orders/${data.id}/preview?token=${encodeURIComponent(token || '')}`, '_blank')
onSaved() onSaved()
onClose() onClose()
} catch (e: any) { } catch (e: any) {
@ -364,7 +364,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
} else { } else {
// Existing PO — save current state then preview // Existing PO — save current state then preview
await handleSave() await handleSave()
window.open(`/api/purchase-orders/${poId}/preview?token=${encodeURIComponent(token || '')}`, '_blank') window.open(`/kitchen/api/purchase-orders/${poId}/preview?token=${encodeURIComponent(token || '')}`, '_blank')
} }
} }
@ -400,7 +400,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
} }
try { try {
const url = poId ? `/api/purchase-orders/${poId}` : '/api/purchase-orders/' const url = poId ? `/kitchen/api/purchase-orders/${poId}` : '/kitchen/api/purchase-orders/'
const method = poId ? 'PUT' : 'POST' const method = poId ? 'PUT' : 'POST'
const saveRes = await fetch(url, { const saveRes = await fetch(url, {
method, method,
@ -411,7 +411,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
const savedPo = await saveRes.json() const savedPo = await saveRes.json()
// Now send the email // Now send the email
const emailRes = await fetch(`/api/purchase-orders/${savedPo.id}/send-email`, { const emailRes = await fetch(`/kitchen/api/purchase-orders/${savedPo.id}/send-email`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -712,7 +712,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
</> </>
)} )}
{!isEditable && poId && ( {!isEditable && poId && (
<button style={styles.previewBtn} onClick={() => window.open(`/api/purchase-orders/${poId}/preview?token=${encodeURIComponent(token || '')}`, '_blank')}> <button style={styles.previewBtn} onClick={() => window.open(`/kitchen/api/purchase-orders/${poId}/preview?token=${encodeURIComponent(token || '')}`, '_blank')}>
Preview Preview
</button> </button>
)} )}

View file

@ -281,7 +281,7 @@ export default function Purchases() {
const { data, isLoading, error } = useQuery<DateRangePurchasesResponse>({ const { data, isLoading, error } = useQuery<DateRangePurchasesResponse>({
queryKey: ['purchases-range', submittedFromDate, submittedToDate], queryKey: ['purchases-range', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/purchases/range?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/reports/purchases/range?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch purchases') if (!res.ok) throw new Error('Failed to fetch purchases')
@ -293,7 +293,7 @@ export default function Purchases() {
const { data: disputeStats } = useQuery<DailyDisputeStats>({ const { data: disputeStats } = useQuery<DailyDisputeStats>({
queryKey: ['daily-dispute-stats', submittedFromDate, submittedToDate], queryKey: ['daily-dispute-stats', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/disputes/stats/daily?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/disputes/stats/daily?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch dispute stats') if (!res.ok) throw new Error('Failed to fetch dispute stats')
@ -305,7 +305,7 @@ export default function Purchases() {
const { data: allowanceStats } = useQuery<DailyLogbookStats>({ const { data: allowanceStats } = useQuery<DailyLogbookStats>({
queryKey: ['daily-allowance-stats', submittedFromDate, submittedToDate], queryKey: ['daily-allowance-stats', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/logbook/daily-stats?date_from=${submittedFromDate}&date_to=${submittedToDate}`, { const res = await fetch(`/kitchen/api/logbook/daily-stats?date_from=${submittedFromDate}&date_to=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch allowance stats') if (!res.ok) throw new Error('Failed to fetch allowance stats')
@ -379,7 +379,7 @@ export default function Purchases() {
const { data: weeklyChartData, isLoading: weeklyChartLoading, error: weeklyChartError } = useQuery<DailyGPChartResponse>({ const { data: weeklyChartData, isLoading: weeklyChartLoading, error: weeklyChartError } = useQuery<DailyGPChartResponse>({
queryKey: ['weekly-chart-data', weeklyChartDateRange.from, weeklyChartDateRange.to], queryKey: ['weekly-chart-data', weeklyChartDateRange.from, weeklyChartDateRange.to],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/gp/daily?from_date=${weeklyChartDateRange.from}&to_date=${weeklyChartDateRange.to}`, { const res = await fetch(`/kitchen/api/reports/gp/daily?from_date=${weeklyChartDateRange.from}&to_date=${weeklyChartDateRange.to}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch weekly chart data') if (!res.ok) throw new Error('Failed to fetch weekly chart data')

View file

@ -270,7 +270,7 @@ export default function PurchasesReport() {
const { data: summary, isLoading, error } = useQuery<PurchasesSummaryResponse>({ const { data: summary, isLoading, error } = useQuery<PurchasesSummaryResponse>({
queryKey: ['purchases-summary', submittedFromDate, submittedToDate], queryKey: ['purchases-summary', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/purchases/summary?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/reports/purchases/summary?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch purchases summary') if (!res.ok) throw new Error('Failed to fetch purchases summary')
@ -284,7 +284,7 @@ export default function PurchasesReport() {
const { data: chartData } = useQuery<DailySupplierChartResponse>({ const { data: chartData } = useQuery<DailySupplierChartResponse>({
queryKey: ['purchases-daily-supplier', submittedFromDate, submittedToDate], queryKey: ['purchases-daily-supplier', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/purchases/daily-by-supplier?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/reports/purchases/daily-by-supplier?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch chart data') if (!res.ok) throw new Error('Failed to fetch chart data')
@ -298,7 +298,7 @@ export default function PurchasesReport() {
const { data: topItems } = useQuery<TopItemsResponse>({ const { data: topItems } = useQuery<TopItemsResponse>({
queryKey: ['purchases-top-items', submittedFromDate, submittedToDate, topItemsSupplierFilter], queryKey: ['purchases-top-items', submittedFromDate, submittedToDate, topItemsSupplierFilter],
queryFn: async () => { queryFn: async () => {
let url = `/api/reports/purchases/top-items?from_date=${submittedFromDate}&to_date=${submittedToDate}` let url = `/kitchen/api/reports/purchases/top-items?from_date=${submittedFromDate}&to_date=${submittedToDate}`
if (topItemsSupplierFilter !== null) { if (topItemsSupplierFilter !== null) {
url += `&supplier_id=${topItemsSupplierFilter}` url += `&supplier_id=${topItemsSupplierFilter}`
} }

View file

@ -284,7 +284,7 @@ export default function RecipeEditor() {
const { data: recipe } = useQuery<RecipeDetail>({ const { data: recipe } = useQuery<RecipeDetail>({
queryKey: ['recipe', recipeId], queryKey: ['recipe', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Not found') if (!res.ok) throw new Error('Not found')
@ -297,7 +297,7 @@ export default function RecipeEditor() {
const { data: sections } = useQuery<MenuSection[]>({ const { data: sections } = useQuery<MenuSection[]>({
queryKey: ['recipe-sections'], queryKey: ['recipe-sections'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes/menu-sections?section_type=recipe', { const res = await fetch('/kitchen/api/recipes/menu-sections?section_type=recipe', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -309,7 +309,7 @@ export default function RecipeEditor() {
const { data: costData } = useQuery<CostData>({ const { data: costData } = useQuery<CostData>({
queryKey: ['recipe-cost', recipeId], queryKey: ['recipe-cost', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/costing`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/costing`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -321,7 +321,7 @@ export default function RecipeEditor() {
const { data: scaledCostData } = useQuery<CostData>({ const { data: scaledCostData } = useQuery<CostData>({
queryKey: ['recipe-cost-scaled', recipeId, scalePortions], queryKey: ['recipe-cost-scaled', recipeId, scalePortions],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/costing?scale_to=${scalePortions}`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/costing?scale_to=${scalePortions}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -333,7 +333,7 @@ export default function RecipeEditor() {
const { data: flagData } = useQuery<FlagState>({ const { data: flagData } = useQuery<FlagState>({
queryKey: ['recipe-flags', recipeId], queryKey: ['recipe-flags', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/food-flags/recipes/${recipeId}/flags`, { const res = await fetch(`/kitchen/api/food-flags/recipes/${recipeId}/flags`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -345,7 +345,7 @@ export default function RecipeEditor() {
const { data: flagCategories } = useQuery<Array<{ id: number; name: string; propagation_type: string; required: boolean }>>({ const { data: flagCategories } = useQuery<Array<{ id: number; name: string; propagation_type: string; required: boolean }>>({
queryKey: ['food-flag-categories'], queryKey: ['food-flag-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/food-flags/categories', { const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -357,7 +357,7 @@ export default function RecipeEditor() {
const { data: changeLog } = useQuery<ChangeLogEntry[]>({ const { data: changeLog } = useQuery<ChangeLogEntry[]>({
queryKey: ['recipe-changelog', recipeId], queryKey: ['recipe-changelog', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/change-log`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/change-log`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -369,7 +369,7 @@ export default function RecipeEditor() {
const { data: costTrendRaw } = useQuery<CostTrendResponse>({ const { data: costTrendRaw } = useQuery<CostTrendResponse>({
queryKey: ['recipe-cost-trend', recipeId], queryKey: ['recipe-cost-trend', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/cost-trend`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/cost-trend`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch cost trend') if (!res.ok) throw new Error('Failed to fetch cost trend')
@ -382,7 +382,7 @@ export default function RecipeEditor() {
const { data: editIngData } = useQuery<EditingIngredient>({ const { data: editIngData } = useQuery<EditingIngredient>({
queryKey: ['ingredient-edit', editIngId], queryKey: ['ingredient-edit', editIngId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/ingredients/${editIngId}`, { const res = await fetch(`/kitchen/api/ingredients/${editIngId}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Not found') if (!res.ok) throw new Error('Not found')
@ -408,7 +408,7 @@ export default function RecipeEditor() {
const { data: availableRecipes } = useQuery<Array<{ id: number; name: string; recipe_type: string; batch_portions: number; batch_output_type: string; batch_yield_qty: number | null; batch_yield_unit: string | null; output_unit: string }>>({ const { data: availableRecipes } = useQuery<Array<{ id: number; name: string; recipe_type: string; batch_portions: number; batch_output_type: string; batch_yield_qty: number | null; batch_yield_unit: string | null; output_unit: string }>>({
queryKey: ['recipes-list-for-sub'], queryKey: ['recipes-list-for-sub'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes?recipe_type=component', { const res = await fetch('/kitchen/api/recipes?recipe_type=component', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
return res.json() return res.json()
@ -438,7 +438,7 @@ export default function RecipeEditor() {
if (!ingSearch || ingSearch.length < 2 || !token) return if (!ingSearch || ingSearch.length < 2 || !token) return
const timer = setTimeout(async () => { const timer = setTimeout(async () => {
try { try {
const res = await fetch(`/api/ingredients/suggest?description=${encodeURIComponent(ingSearch)}`, { const res = await fetch(`/kitchen/api/ingredients/suggest?description=${encodeURIComponent(ingSearch)}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok) { if (res.ok) {
@ -455,7 +455,7 @@ export default function RecipeEditor() {
// Mutations // Mutations
const updateMutation = useMutation({ const updateMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch(`/api/recipes/${recipeId}`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -473,7 +473,7 @@ export default function RecipeEditor() {
const addIngMutation = useMutation({ const addIngMutation = useMutation({
mutationFn: async (data: { ingredient_id: number; quantity: number; unit?: string; notes?: string }) => { mutationFn: async (data: { ingredient_id: number; quantity: number; unit?: string; notes?: string }) => {
const res = await fetch(`/api/recipes/${recipeId}/ingredients`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/ingredients`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -498,7 +498,7 @@ export default function RecipeEditor() {
const updateIngMutation = useMutation({ const updateIngMutation = useMutation({
mutationFn: async ({ riId, quantity, unit, yield_percent, notes }: { riId: number; quantity?: number; unit?: string; yield_percent?: number; notes?: string }) => { mutationFn: async ({ riId, quantity, unit, yield_percent, notes }: { riId: number; quantity?: number; unit?: string; yield_percent?: number; notes?: string }) => {
const res = await fetch(`/api/recipes/recipe-ingredients/${riId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-ingredients/${riId}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ quantity, unit, yield_percent, notes }), body: JSON.stringify({ quantity, unit, yield_percent, notes }),
@ -516,7 +516,7 @@ export default function RecipeEditor() {
const removeIngMutation = useMutation({ const removeIngMutation = useMutation({
mutationFn: async (riId: number) => { mutationFn: async (riId: number) => {
const res = await fetch(`/api/recipes/recipe-ingredients/${riId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-ingredients/${riId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -533,7 +533,7 @@ export default function RecipeEditor() {
const addSubMutation = useMutation({ const addSubMutation = useMutation({
mutationFn: async (data: { child_recipe_id: number; portions_needed: number; portions_needed_unit?: string }) => { mutationFn: async (data: { child_recipe_id: number; portions_needed: number; portions_needed_unit?: string }) => {
const res = await fetch(`/api/recipes/${recipeId}/sub-recipes`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/sub-recipes`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -554,7 +554,7 @@ export default function RecipeEditor() {
const removeSubMutation = useMutation({ const removeSubMutation = useMutation({
mutationFn: async (srId: number) => { mutationFn: async (srId: number) => {
const res = await fetch(`/api/recipes/recipe-sub-recipes/${srId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-sub-recipes/${srId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -570,7 +570,7 @@ export default function RecipeEditor() {
const addStepMutation = useMutation({ const addStepMutation = useMutation({
mutationFn: async (data: { title?: string; instruction: string; step_number: number; duration_minutes?: number }) => { mutationFn: async (data: { title?: string; instruction: string; step_number: number; duration_minutes?: number }) => {
const res = await fetch(`/api/recipes/${recipeId}/steps`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/steps`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -588,7 +588,7 @@ export default function RecipeEditor() {
const updateStepMutation = useMutation({ const updateStepMutation = useMutation({
mutationFn: async ({ stepId, data }: { stepId: number; data: { title?: string; instruction?: string; duration_minutes?: number } }) => { mutationFn: async ({ stepId, data }: { stepId: number; data: { title?: string; instruction?: string; duration_minutes?: number } }) => {
const res = await fetch(`/api/recipes/recipe-steps/${stepId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-steps/${stepId}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -607,7 +607,7 @@ export default function RecipeEditor() {
const removeStepMutation = useMutation({ const removeStepMutation = useMutation({
mutationFn: async (stepId: number) => { mutationFn: async (stepId: number) => {
const res = await fetch(`/api/recipes/recipe-steps/${stepId}`, { const res = await fetch(`/kitchen/api/recipes/recipe-steps/${stepId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -623,7 +623,7 @@ export default function RecipeEditor() {
formData.append('file', file) formData.append('file', file)
formData.append('caption', caption) formData.append('caption', caption)
formData.append('image_type', image_type) formData.append('image_type', image_type)
const res = await fetch(`/api/recipes/${recipeId}/images`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/images`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
body: formData, body: formData,
@ -641,7 +641,7 @@ export default function RecipeEditor() {
// Delete image mutation // Delete image mutation
const deleteImageMutation = useMutation({ const deleteImageMutation = useMutation({
mutationFn: async (imageId: number) => { mutationFn: async (imageId: number) => {
const res = await fetch(`/api/recipes/${recipeId}/images/${imageId}`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/images/${imageId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -655,7 +655,7 @@ export default function RecipeEditor() {
// Batch reorder ingredients // Batch reorder ingredients
const reorderIngMutation = useMutation({ const reorderIngMutation = useMutation({
mutationFn: async (ingredientIds: number[]) => { mutationFn: async (ingredientIds: number[]) => {
const res = await fetch(`/api/recipes/${recipeId}/ingredients/reorder`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/ingredients/reorder`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ingredient_ids: ingredientIds }), body: JSON.stringify({ ingredient_ids: ingredientIds }),
@ -670,7 +670,7 @@ export default function RecipeEditor() {
// Batch reorder sub-recipes // Batch reorder sub-recipes
const reorderSubMutation = useMutation({ const reorderSubMutation = useMutation({
mutationFn: async (subRecipeIds: number[]) => { mutationFn: async (subRecipeIds: number[]) => {
const res = await fetch(`/api/recipes/${recipeId}/sub-recipes/reorder`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/sub-recipes/reorder`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ sub_recipe_ids: subRecipeIds }), body: JSON.stringify({ sub_recipe_ids: subRecipeIds }),
@ -685,7 +685,7 @@ export default function RecipeEditor() {
// Reorder steps mutation // Reorder steps mutation
const reorderStepsMutation = useMutation({ const reorderStepsMutation = useMutation({
mutationFn: async (stepIds: number[]) => { mutationFn: async (stepIds: number[]) => {
const res = await fetch(`/api/recipes/${recipeId}/steps/reorder`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}/steps/reorder`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ step_ids: stepIds }), body: JSON.stringify({ step_ids: stepIds }),
@ -769,7 +769,7 @@ export default function RecipeEditor() {
} }
const handlePrint = (format: string) => { const handlePrint = (format: string) => {
window.open(`/api/recipes/${recipeId}/print?format=${format}&token=${token}`, '_blank') window.open(`/kitchen/api/recipes/${recipeId}/print?format=${format}&token=${token}`, '_blank')
} }
if (!recipe) return <div style={styles.loading}>Loading recipe...</div> if (!recipe) return <div style={styles.loading}>Loading recipe...</div>
@ -893,7 +893,7 @@ export default function RecipeEditor() {
style={{ marginLeft: 'auto', background: 'none', border: '1px solid #b4530955', borderRadius: '4px', color: '#b45309', cursor: 'pointer', padding: '0.15rem 0.5rem', fontSize: '0.8rem', whiteSpace: 'nowrap' }} style={{ marginLeft: 'auto', background: 'none', border: '1px solid #b4530955', borderRadius: '4px', color: '#b45309', cursor: 'pointer', padding: '0.15rem 0.5rem', fontSize: '0.8rem', whiteSpace: 'nowrap' }}
onClick={async () => { onClick={async () => {
try { try {
const res = await fetch(`/api/food-flags/recipes/${recipeId}/text-dismissals`, { const res = await fetch(`/kitchen/api/food-flags/recipes/${recipeId}/text-dismissals`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@ -1309,10 +1309,10 @@ export default function RecipeEditor() {
{recipe.images.map(img => ( {recipe.images.map(img => (
<div key={img.id} style={styles.imageCard}> <div key={img.id} style={styles.imageCard}>
<img <img
src={`/api/recipes/${recipeId}/images/${img.id}?token=${token}`} src={`/kitchen/api/recipes/${recipeId}/images/${img.id}?token=${token}`}
alt={img.caption || 'Recipe image'} alt={img.caption || 'Recipe image'}
style={{ ...styles.imageThumb, cursor: 'pointer' }} style={{ ...styles.imageThumb, cursor: 'pointer' }}
onClick={() => setLightboxImg(`/api/recipes/${recipeId}/images/${img.id}?token=${token}`)} onClick={() => setLightboxImg(`/kitchen/api/recipes/${recipeId}/images/${img.id}?token=${token}`)}
/> />
<div style={{ padding: '0.4rem' }}> <div style={{ padding: '0.4rem' }}>
{img.caption && <div style={{ fontSize: '0.8rem', color: '#333', marginTop: '2px' }}>{img.caption}</div>} {img.caption && <div style={{ fontSize: '0.8rem', color: '#333', marginTop: '2px' }}>{img.caption}</div>}

View file

@ -45,7 +45,7 @@ export default function RecipeFlagMatrix({ recipeId, categoryId }: Props) {
const { data: rawData, isLoading } = useQuery<MatrixData>({ const { data: rawData, isLoading } = useQuery<MatrixData>({
queryKey: ['recipe-flag-matrix', recipeId], queryKey: ['recipe-flag-matrix', recipeId],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/food-flags/recipes/${recipeId}/flags/matrix`, { const res = await fetch(`/kitchen/api/food-flags/recipes/${recipeId}/flags/matrix`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch matrix') if (!res.ok) throw new Error('Failed to fetch matrix')
@ -62,7 +62,7 @@ export default function RecipeFlagMatrix({ recipeId, categoryId }: Props) {
const toggleMutation = useMutation({ const toggleMutation = useMutation({
mutationFn: async ({ ingredientId, flagId, hasFlag }: { ingredientId: number; flagId: number; hasFlag: boolean }) => { mutationFn: async ({ ingredientId, flagId, hasFlag }: { ingredientId: number; flagId: number; hasFlag: boolean }) => {
const res = await fetch(`/api/food-flags/recipes/${recipeId}/flags/matrix`, { const res = await fetch(`/kitchen/api/food-flags/recipes/${recipeId}/flags/matrix`, {
method: 'PUT', method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ updates: [{ ingredient_id: ingredientId, food_flag_id: flagId, has_flag: hasFlag }] }), body: JSON.stringify({ updates: [{ ingredient_id: ingredientId, food_flag_id: flagId, has_flag: hasFlag }] }),
@ -86,7 +86,7 @@ export default function RecipeFlagMatrix({ recipeId, categoryId }: Props) {
const toggleNoneMutation = useMutation({ const toggleNoneMutation = useMutation({
mutationFn: async ({ ingredientId, catId }: { ingredientId: number; catId: number }) => { mutationFn: async ({ ingredientId, catId }: { ingredientId: number; catId: number }) => {
const res = await fetch(`/api/food-flags/recipes/${recipeId}/flags/matrix/none`, { const res = await fetch(`/kitchen/api/food-flags/recipes/${recipeId}/flags/matrix/none`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ingredient_id: ingredientId, category_id: catId }), body: JSON.stringify({ ingredient_id: ingredientId, category_id: catId }),

View file

@ -81,7 +81,7 @@ export default function RecipeList() {
const { data: sections } = useQuery<MenuSection[]>({ const { data: sections } = useQuery<MenuSection[]>({
queryKey: ['recipe-sections'], queryKey: ['recipe-sections'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes/menu-sections?section_type=recipe', { const res = await fetch('/kitchen/api/recipes/menu-sections?section_type=recipe', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch sections') if (!res.ok) throw new Error('Failed to fetch sections')
@ -98,7 +98,7 @@ export default function RecipeList() {
if (search) params.set('search', search) if (search) params.set('search', search)
if (sectionFilter) params.set('menu_section_id', sectionFilter) if (sectionFilter) params.set('menu_section_id', sectionFilter)
if (showArchived) params.set('archived', 'true') if (showArchived) params.set('archived', 'true')
const res = await fetch(`/api/recipes?${params}`, { const res = await fetch(`/kitchen/api/recipes?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch recipes') if (!res.ok) throw new Error('Failed to fetch recipes')
@ -109,7 +109,7 @@ export default function RecipeList() {
const createMutation = useMutation({ const createMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/recipes', { const res = await fetch('/kitchen/api/recipes', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -126,7 +126,7 @@ export default function RecipeList() {
const duplicateMutation = useMutation({ const duplicateMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/${id}/duplicate`, { const res = await fetch(`/kitchen/api/recipes/${id}/duplicate`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -141,7 +141,7 @@ export default function RecipeList() {
const archiveMutation = useMutation({ const archiveMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/${id}`, { const res = await fetch(`/kitchen/api/recipes/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -152,7 +152,7 @@ export default function RecipeList() {
const unarchiveMutation = useMutation({ const unarchiveMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/${id}`, { const res = await fetch(`/kitchen/api/recipes/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ is_archived: false }), body: JSON.stringify({ is_archived: false }),
@ -164,7 +164,7 @@ export default function RecipeList() {
const createSectionMutation = useMutation({ const createSectionMutation = useMutation({
mutationFn: async (name: string) => { mutationFn: async (name: string) => {
const res = await fetch('/api/recipes/menu-sections', { const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, section_type: 'recipe' }), body: JSON.stringify({ name, section_type: 'recipe' }),
@ -181,7 +181,7 @@ export default function RecipeList() {
const updateSectionMutation = useMutation({ const updateSectionMutation = useMutation({
mutationFn: async ({ id, name }: { id: number; name: string }) => { mutationFn: async ({ id, name }: { id: number; name: string }) => {
const res = await fetch(`/api/recipes/menu-sections/${id}`, { const res = await fetch(`/kitchen/api/recipes/menu-sections/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name }), body: JSON.stringify({ name }),
@ -199,7 +199,7 @@ export default function RecipeList() {
const deleteSectionMutation = useMutation({ const deleteSectionMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/menu-sections/${id}`, { const res = await fetch(`/kitchen/api/recipes/menu-sections/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -215,7 +215,7 @@ export default function RecipeList() {
const { data: flagCategories } = useQuery<Array<{ id: number; name: string; flags: Array<{ id: number; name: string; code: string | null }> }>>({ const { data: flagCategories } = useQuery<Array<{ id: number; name: string; flags: Array<{ id: number; name: string; code: string | null }> }>>({
queryKey: ['food-flag-categories'], queryKey: ['food-flag-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/food-flags/categories', { const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch flag categories') if (!res.ok) throw new Error('Failed to fetch flag categories')

View file

@ -83,7 +83,7 @@ export default function ReconcilePurchases() {
mutationFn: async (file: File) => { mutationFn: async (file: File) => {
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
const res = await fetch('/api/reports/purchases/reconcile', { const res = await fetch('/kitchen/api/reports/purchases/reconcile', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
body: formData, body: formData,

View file

@ -541,7 +541,7 @@ export default function Review() {
const { data: invoice, isLoading, refetch: refetchInvoice } = useQuery<Invoice>({ const { data: invoice, isLoading, refetch: refetchInvoice } = useQuery<Invoice>({
queryKey: ['invoice', id], queryKey: ['invoice', id],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/invoices/${id}`, { const res = await fetch(`/kitchen/api/invoices/${id}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch invoice') if (!res.ok) throw new Error('Failed to fetch invoice')
@ -553,13 +553,13 @@ export default function Review() {
// Direct URL with token - simpler approach // Direct URL with token - simpler approach
const imageUrl = invoice const imageUrl = invoice
? `/api/invoices/${id}/file?token=${encodeURIComponent(token || '')}#toolbar=0&navpanes=0&view=FitH` ? `/kitchen/api/invoices/${id}/file?token=${encodeURIComponent(token || '')}#toolbar=0&navpanes=0&view=FitH`
: null : null
const { data: lineItems, refetch: refetchLineItems } = useQuery<LineItem[]>({ const { data: lineItems, refetch: refetchLineItems } = useQuery<LineItem[]>({
queryKey: ['invoice-line-items', id], queryKey: ['invoice-line-items', id],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/invoices/${id}/line-items`, { const res = await fetch(`/kitchen/api/invoices/${id}/line-items`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch line items') if (!res.ok) throw new Error('Failed to fetch line items')
@ -576,7 +576,7 @@ export default function Review() {
}>>({ }>>({
queryKey: ['invoice-stock-history', id], queryKey: ['invoice-stock-history', id],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/invoices/${id}/stock-history`, { const res = await fetch(`/kitchen/api/invoices/${id}/stock-history`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch stock history') if (!res.ok) throw new Error('Failed to fetch stock history')
@ -588,7 +588,7 @@ export default function Review() {
const { data: duplicateInfo } = useQuery<DuplicateCompare>({ const { data: duplicateInfo } = useQuery<DuplicateCompare>({
queryKey: ['invoice-duplicates', id], queryKey: ['invoice-duplicates', id],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/invoices/${id}/duplicates`, { const res = await fetch(`/kitchen/api/invoices/${id}/duplicates`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch duplicates') if (!res.ok) throw new Error('Failed to fetch duplicates')
@ -600,7 +600,7 @@ export default function Review() {
const { data: rawOcrData } = useQuery<{ raw_json: any; raw_text: string }>({ const { data: rawOcrData } = useQuery<{ raw_json: any; raw_text: string }>({
queryKey: ['invoice-ocr-data', id], queryKey: ['invoice-ocr-data', id],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/invoices/${id}/ocr-data`, { const res = await fetch(`/kitchen/api/invoices/${id}/ocr-data`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch OCR data') if (!res.ok) throw new Error('Failed to fetch OCR data')
@ -612,7 +612,7 @@ export default function Review() {
const { data: settings } = useQuery<Settings>({ const { data: settings } = useQuery<Settings>({
queryKey: ['settings'], queryKey: ['settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/', { const res = await fetch('/kitchen/api/settings/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch settings') if (!res.ok) throw new Error('Failed to fetch settings')
@ -637,7 +637,7 @@ export default function Review() {
const uniqueItems = Array.from(new Map(items.map(i => [i.description.toLowerCase(), i])).values()) const uniqueItems = Array.from(new Map(items.map(i => [i.description.toLowerCase(), i])).values())
if (uniqueItems.length === 0) return if (uniqueItems.length === 0) return
fetch('/api/ingredients/sources/alias-suggestions', { fetch('/kitchen/api/ingredients/sources/alias-suggestions', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ supplier_id: parseInt(supplierId), items: uniqueItems }), body: JSON.stringify({ supplier_id: parseInt(supplierId), items: uniqueItems }),
@ -885,7 +885,7 @@ export default function Review() {
const { data: suppliers } = useQuery<Supplier[]>({ const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -915,7 +915,7 @@ export default function Review() {
}>({ }>({
queryKey: ['po-match', id], queryKey: ['po-match', id],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/purchase-orders/matching/for-invoice?invoice_id=${id}`, { const res = await fetch(`/kitchen/api/purchase-orders/matching/for-invoice?invoice_id=${id}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return { matches: [], linked_po: null } if (!res.ok) return { matches: [], linked_po: null }
@ -944,7 +944,7 @@ export default function Review() {
const pollInterval = setInterval(async () => { const pollInterval = setInterval(async () => {
try { try {
const checkRes = await fetch(`/api/invoices/${id}`, { const checkRes = await fetch(`/kitchen/api/invoices/${id}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (checkRes.ok) { if (checkRes.ok) {
@ -971,7 +971,7 @@ export default function Review() {
try { try {
// Fetch the PDF // Fetch the PDF
const pdfUrl = `/api/invoices/${id}/file?token=${encodeURIComponent(token)}` const pdfUrl = `/kitchen/api/invoices/${id}/file?token=${encodeURIComponent(token)}`
const response = await fetch(pdfUrl) const response = await fetch(pdfUrl)
const arrayBuffer = await response.arrayBuffer() const arrayBuffer = await response.arrayBuffer()
@ -1041,7 +1041,7 @@ export default function Review() {
const updateMutation = useMutation({ const updateMutation = useMutation({
mutationFn: async (data: Partial<Invoice>) => { mutationFn: async (data: Partial<Invoice>) => {
const res = await fetch(`/api/invoices/${id}`, { const res = await fetch(`/kitchen/api/invoices/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1067,7 +1067,7 @@ export default function Review() {
const deleteMutation = useMutation({ const deleteMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch(`/api/invoices/${id}`, { const res = await fetch(`/kitchen/api/invoices/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1082,7 +1082,7 @@ export default function Review() {
const updateLineItemMutation = useMutation({ const updateLineItemMutation = useMutation({
mutationFn: async ({ itemId, data }: { itemId: number; data: Partial<LineItem> }) => { mutationFn: async ({ itemId, data }: { itemId: number; data: Partial<LineItem> }) => {
const res = await fetch(`/api/invoices/${id}/line-items/${itemId}`, { const res = await fetch(`/kitchen/api/invoices/${id}/line-items/${itemId}`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1104,7 +1104,7 @@ export default function Review() {
const createLineItemMutation = useMutation({ const createLineItemMutation = useMutation({
mutationFn: async (data: Partial<LineItem>) => { mutationFn: async (data: Partial<LineItem>) => {
const res = await fetch(`/api/invoices/${id}/line-items`, { const res = await fetch(`/kitchen/api/invoices/${id}/line-items`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1125,7 +1125,7 @@ export default function Review() {
const deleteLineItemMutation = useMutation({ const deleteLineItemMutation = useMutation({
mutationFn: async (itemId: number) => { mutationFn: async (itemId: number) => {
const res = await fetch(`/api/invoices/${id}/line-items/${itemId}`, { const res = await fetch(`/kitchen/api/invoices/${id}/line-items/${itemId}`, {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1143,7 +1143,7 @@ export default function Review() {
const saveDefinitionMutation = useMutation({ const saveDefinitionMutation = useMutation({
mutationFn: async ({ itemId, portionDesc }: { itemId: number; portionDesc?: string }) => { mutationFn: async ({ itemId, portionDesc }: { itemId: number; portionDesc?: string }) => {
const res = await fetch(`/api/invoices/${id}/line-items/${itemId}/save-definition`, { const res = await fetch(`/kitchen/api/invoices/${id}/line-items/${itemId}/save-definition`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1161,7 +1161,7 @@ export default function Review() {
const createSupplierMutation = useMutation({ const createSupplierMutation = useMutation({
mutationFn: async (name: string) => { mutationFn: async (name: string) => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1182,7 +1182,7 @@ export default function Review() {
const addAliasMutation = useMutation({ const addAliasMutation = useMutation({
mutationFn: async ({ supplierId, alias, invoiceId }: { supplierId: number; alias: string; invoiceId?: number }) => { mutationFn: async ({ supplierId, alias, invoiceId }: { supplierId: number; alias: string; invoiceId?: number }) => {
const res = await fetch(`/api/suppliers/${supplierId}/aliases`, { const res = await fetch(`/kitchen/api/suppliers/${supplierId}/aliases`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1201,7 +1201,7 @@ export default function Review() {
const addDescriptionAliasMutation = useMutation({ const addDescriptionAliasMutation = useMutation({
mutationFn: async ({ sourceId, alias }: { sourceId: number; alias: string }) => { mutationFn: async ({ sourceId, alias }: { sourceId: number; alias: string }) => {
const res = await fetch(`/api/ingredients/sources/${sourceId}/aliases`, { const res = await fetch(`/kitchen/api/ingredients/sources/${sourceId}/aliases`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1228,7 +1228,7 @@ export default function Review() {
// PO link/unlink handlers // PO link/unlink handlers
const handleLinkPo = async (poId: number) => { const handleLinkPo = async (poId: number) => {
try { try {
const res = await fetch(`/api/purchase-orders/${poId}/link`, { const res = await fetch(`/kitchen/api/purchase-orders/${poId}/link`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ invoice_id: parseInt(id!) }), body: JSON.stringify({ invoice_id: parseInt(id!) }),
@ -1242,7 +1242,7 @@ export default function Review() {
const handleUnlinkPo = async (poId: number) => { const handleUnlinkPo = async (poId: number) => {
try { try {
const res = await fetch(`/api/purchase-orders/${poId}/unlink`, { const res = await fetch(`/kitchen/api/purchase-orders/${poId}/unlink`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1386,7 +1386,7 @@ export default function Review() {
setAdminOperationResult(null) setAdminOperationResult(null)
try { try {
const res = await fetch(`/api/invoices/${id}/mark-dext-sent`, { const res = await fetch(`/kitchen/api/invoices/${id}/mark-dext-sent`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1423,7 +1423,7 @@ export default function Review() {
setAdminOperationResult(null) setAdminOperationResult(null)
try { try {
const res = await fetch(`/api/invoices/${id}/reprocess`, { const res = await fetch(`/kitchen/api/invoices/${id}/reprocess`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1457,7 +1457,7 @@ export default function Review() {
setShowDatePickerModal(true) setShowDatePickerModal(true)
try { try {
const res = await fetch(`/api/invoices/${id}/parse-dates`, { const res = await fetch(`/kitchen/api/invoices/${id}/parse-dates`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1485,7 +1485,7 @@ export default function Review() {
setInvoiceNumberExamples([]) setInvoiceNumberExamples([])
setShowInvoiceNumberModal(true) setShowInvoiceNumberModal(true)
try { try {
const res = await fetch(`/api/invoices/${id}/parse-invoice-number`, { const res = await fetch(`/kitchen/api/invoices/${id}/parse-invoice-number`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to search for invoice number') if (!res.ok) throw new Error('Failed to search for invoice number')
@ -1513,7 +1513,7 @@ export default function Review() {
setAdminOperationResult(null) setAdminOperationResult(null)
try { try {
const res = await fetch(`/api/invoices/${id}/resend-to-azure`, { const res = await fetch(`/kitchen/api/invoices/${id}/resend-to-azure`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1532,7 +1532,7 @@ export default function Review() {
// Poll for completion // Poll for completion
const pollInterval = setInterval(async () => { const pollInterval = setInterval(async () => {
try { try {
const checkRes = await fetch(`/api/invoices/${id}`, { const checkRes = await fetch(`/kitchen/api/invoices/${id}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (checkRes.ok) { if (checkRes.ok) {
@ -1565,7 +1565,7 @@ export default function Review() {
setAdminOperationResult(null) setAdminOperationResult(null)
try { try {
const res = await fetch(`/api/invoices/${id}/regenerate-highlights`, { const res = await fetch(`/kitchen/api/invoices/${id}/regenerate-highlights`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1756,7 +1756,7 @@ export default function Review() {
if (!query || query.length < 2) return if (!query || query.length < 2) return
setSearchLoading(true) setSearchLoading(true)
try { try {
const res = await fetch('/api/invoices/line-items/search', { const res = await fetch('/kitchen/api/invoices/line-items/search', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -1781,7 +1781,7 @@ export default function Review() {
try { try {
// Update all line items // Update all line items
const promises = lineItems.map(item => const promises = lineItems.map(item =>
fetch(`/api/invoices/${id}/line-items/${item.id}`, { fetch(`/kitchen/api/invoices/${id}/line-items/${item.id}`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1805,7 +1805,7 @@ export default function Review() {
setAiMatchLoading(true) setAiMatchLoading(true)
setAiMatchResults([]) setAiMatchResults([])
try { try {
const res = await fetch(`/api/ingredients/ai-match?description=${encodeURIComponent(description)}`, { const res = await fetch(`/kitchen/api/ingredients/ai-match?description=${encodeURIComponent(description)}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok) { if (res.ok) {
@ -1827,7 +1827,7 @@ export default function Review() {
setAiDismissedCorrections(new Set()) setAiDismissedCorrections(new Set())
try { try {
const res = await fetch(`/api/invoices/${id}/ai-assist`, { const res = await fetch(`/kitchen/api/invoices/${id}/ai-assist`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1906,7 +1906,7 @@ export default function Review() {
// Fetch saved definition // Fetch saved definition
setDefinitionLoading(true) setDefinitionLoading(true)
try { try {
const res = await fetch(`/api/invoices/${id}/line-items/${item.id}/definition`, { const res = await fetch(`/kitchen/api/invoices/${id}/line-items/${item.id}/definition`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok) { if (res.ok) {
@ -1927,7 +1927,7 @@ export default function Review() {
if (!item.pack_quantity && !item.unit_size) { if (!item.pack_quantity && !item.unit_size) {
setAiPackSizeLoading(true) setAiPackSizeLoading(true)
try { try {
const packRes = await fetch(`/api/invoices/${id}/line-items/${item.id}/ai-pack-size`, { const packRes = await fetch(`/kitchen/api/invoices/${id}/line-items/${item.id}/ai-pack-size`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (packRes.ok) { if (packRes.ok) {
@ -1961,7 +1961,7 @@ export default function Review() {
} }
setIngredientSearchLoading(true) setIngredientSearchLoading(true)
try { try {
const res = await fetch(`/api/ingredients/suggest?description=${encodeURIComponent(query)}`, { const res = await fetch(`/kitchen/api/ingredients/suggest?description=${encodeURIComponent(query)}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok) { if (res.ok) {
@ -2053,7 +2053,7 @@ export default function Review() {
if (selectedIngredientId) { if (selectedIngredientId) {
try { try {
// Set ingredient_id on line item // Set ingredient_id on line item
await fetch(`/api/invoices/${id}/line-items/${itemId}`, { await fetch(`/kitchen/api/invoices/${id}/line-items/${itemId}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ingredient_id: selectedIngredientId }), body: JSON.stringify({ ingredient_id: selectedIngredientId }),
@ -2081,7 +2081,7 @@ export default function Review() {
if (id) { if (id) {
sourceData.invoice_id = parseInt(id as string) sourceData.invoice_id = parseInt(id as string)
} }
const srcRes = await fetch(`/api/ingredients/${selectedIngredientId}/sources`, { const srcRes = await fetch(`/kitchen/api/ingredients/${selectedIngredientId}/sources`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(sourceData), body: JSON.stringify(sourceData),
@ -2610,7 +2610,7 @@ export default function Review() {
)} )}
{isPDF && imageUrl && ( {isPDF && imageUrl && (
<a <a
href={`/api/invoices/${id}/file?token=${encodeURIComponent(token || '')}`} href={`/kitchen/api/invoices/${id}/file?token=${encodeURIComponent(token || '')}`}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
style={styles.openPdfLink} style={styles.openPdfLink}
@ -3092,7 +3092,7 @@ export default function Review() {
onChange={(e) => setInvoiceNotes(e.target.value)} onChange={(e) => setInvoiceNotes(e.target.value)}
onBlur={async () => { onBlur={async () => {
try { try {
await fetch(`/api/invoices/${id}`, { await fetch(`/kitchen/api/invoices/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -4673,7 +4673,7 @@ export default function Review() {
<button <button
onClick={async () => { onClick={async () => {
try { try {
const res = await fetch(`/api/invoices/${id}/send-to-dext`, { const res = await fetch(`/kitchen/api/invoices/${id}/send-to-dext`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })

View file

@ -75,7 +75,7 @@ export default function SalesGPReport() {
const { data: report, isLoading, error } = useQuery<SalesGPResponse>({ const { data: report, isLoading, error } = useQuery<SalesGPResponse>({
queryKey: ['sales-gp', submittedFrom, submittedTo], queryKey: ['sales-gp', submittedFrom, submittedTo],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/reports/sales-gp?from_date=${submittedFrom}&to_date=${submittedTo}`, { const res = await fetch(`/kitchen/api/reports/sales-gp?from_date=${submittedFrom}&to_date=${submittedTo}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) { if (!res.ok) {
@ -91,7 +91,7 @@ export default function SalesGPReport() {
const { data: dishRecipes } = useQuery<DishRecipe[]>({ const { data: dishRecipes } = useQuery<DishRecipe[]>({
queryKey: ['recipes-for-mapping', recipeSearch], queryKey: ['recipes-for-mapping', recipeSearch],
queryFn: async () => { queryFn: async () => {
const url = `/api/recipes?recipe_type=dish${recipeSearch ? `&search=${encodeURIComponent(recipeSearch)}` : ''}` const url = `/kitchen/api/recipes?recipe_type=dish${recipeSearch ? `&search=${encodeURIComponent(recipeSearch)}` : ''}`
const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } }) const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } })
return res.json() return res.json()
}, },
@ -101,7 +101,7 @@ export default function SalesGPReport() {
// Map unmapped item to recipe // Map unmapped item to recipe
const mapMutation = useMutation({ const mapMutation = useMutation({
mutationFn: async ({ recipeId, menuItemName, portionName }: { recipeId: number; menuItemName: string; portionName: string }) => { mutationFn: async ({ recipeId, menuItemName, portionName }: { recipeId: number; menuItemName: string; portionName: string }) => {
const res = await fetch(`/api/recipes/${recipeId}`, { const res = await fetch(`/kitchen/api/recipes/${recipeId}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({

View file

@ -104,7 +104,7 @@ export default function SearchDefinitions() {
const { data: suppliers } = useQuery<Supplier[]>({ const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch suppliers') if (!res.ok) throw new Error('Failed to fetch suppliers')
@ -123,7 +123,7 @@ export default function SearchDefinitions() {
if (hasPortions === 'no') params.set('has_portions', 'false') if (hasPortions === 'no') params.set('has_portions', 'false')
params.set('limit', '200') params.set('limit', '200')
const res = await fetch(`/api/search/definitions?${params}`, { const res = await fetch(`/kitchen/api/search/definitions?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Search failed') if (!res.ok) throw new Error('Search failed')
@ -136,7 +136,7 @@ export default function SearchDefinitions() {
const { data: lineItems } = useQuery<LineItem[]>({ const { data: lineItems } = useQuery<LineItem[]>({
queryKey: ['invoice-line-items', editingDef?.source_invoice_id], queryKey: ['invoice-line-items', editingDef?.source_invoice_id],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/invoices/${editingDef!.source_invoice_id}/line-items`, { const res = await fetch(`/kitchen/api/invoices/${editingDef!.source_invoice_id}/line-items`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch line items') if (!res.ok) throw new Error('Failed to fetch line items')
@ -149,7 +149,7 @@ export default function SearchDefinitions() {
const { data: ocrData } = useQuery<OcrData>({ const { data: ocrData } = useQuery<OcrData>({
queryKey: ['invoice-ocr-data', editingDef?.source_invoice_id], queryKey: ['invoice-ocr-data', editingDef?.source_invoice_id],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/invoices/${editingDef!.source_invoice_id}/ocr-data`, { const res = await fetch(`/kitchen/api/invoices/${editingDef!.source_invoice_id}/ocr-data`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch OCR data') if (!res.ok) throw new Error('Failed to fetch OCR data')
@ -161,7 +161,7 @@ export default function SearchDefinitions() {
// Update definition mutation // Update definition mutation
const updateMutation = useMutation({ const updateMutation = useMutation({
mutationFn: async (data: { id: number; updates: typeof editFormData }) => { mutationFn: async (data: { id: number; updates: typeof editFormData }) => {
const res = await fetch(`/api/search/definitions/${data.id}`, { const res = await fetch(`/kitchen/api/search/definitions/${data.id}`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -191,7 +191,7 @@ export default function SearchDefinitions() {
return return
} }
const url = `/api/invoices/${editingDef.source_invoice_id}/image` const url = `/kitchen/api/invoices/${editingDef.source_invoice_id}/image`
setInvoiceImageUrl(url) setInvoiceImageUrl(url)
// Check if PDF by fetching headers // Check if PDF by fetching headers

View file

@ -72,7 +72,7 @@ export default function SearchInvoices() {
const { data: suppliers } = useQuery<Supplier[]>({ const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch suppliers') if (!res.ok) throw new Error('Failed to fetch suppliers')
@ -103,7 +103,7 @@ export default function SearchInvoices() {
if (groupBy) params.set('group_by', groupBy) if (groupBy) params.set('group_by', groupBy)
params.set('limit', '200') params.set('limit', '200')
const res = await fetch(`/api/search/invoices?${params}`, { const res = await fetch(`/kitchen/api/search/invoices?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Search failed') if (!res.ok) throw new Error('Search failed')

View file

@ -144,7 +144,7 @@ export default function SearchLineItems() {
const { data: suppliers } = useQuery<Supplier[]>({ const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch suppliers') if (!res.ok) throw new Error('Failed to fetch suppliers')
@ -156,7 +156,7 @@ export default function SearchLineItems() {
const { data: _searchSettings } = useQuery<SearchSettings>({ const { data: _searchSettings } = useQuery<SearchSettings>({
queryKey: ['search-settings'], queryKey: ['search-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/search/settings', { const res = await fetch('/kitchen/api/search/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch search settings') if (!res.ok) throw new Error('Failed to fetch search settings')
@ -178,7 +178,7 @@ export default function SearchLineItems() {
if (mappedFilter) params.set('mapped', mappedFilter) if (mappedFilter) params.set('mapped', mappedFilter)
params.set('limit', '200') params.set('limit', '200')
const res = await fetch(`/api/search/line-items?${params}`, { const res = await fetch(`/kitchen/api/search/line-items?${params}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Search failed') if (!res.ok) throw new Error('Search failed')
@ -205,7 +205,7 @@ export default function SearchLineItems() {
const allSuggestions: typeof aliasSuggestions = {} const allSuggestions: typeof aliasSuggestions = {}
const promises = Array.from(bySupplier.entries()).map(([sid, items]) => const promises = Array.from(bySupplier.entries()).map(([sid, items]) =>
fetch('/api/ingredients/sources/alias-suggestions', { fetch('/kitchen/api/ingredients/sources/alias-suggestions', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ supplier_id: sid, items }), body: JSON.stringify({ supplier_id: sid, items }),
@ -223,7 +223,7 @@ export default function SearchLineItems() {
const addDescriptionAliasMutation = useMutation({ const addDescriptionAliasMutation = useMutation({
mutationFn: async ({ sourceId, alias }: { sourceId: number; alias: string }) => { mutationFn: async ({ sourceId, alias }: { sourceId: number; alias: string }) => {
const res = await fetch(`/api/ingredients/sources/${sourceId}/aliases`, { const res = await fetch(`/kitchen/api/ingredients/sources/${sourceId}/aliases`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -300,7 +300,7 @@ export default function SearchLineItems() {
} }
setIngredientSearchLoading(true) setIngredientSearchLoading(true)
try { try {
const res = await fetch(`/api/ingredients/suggest?description=${encodeURIComponent(query)}`, { const res = await fetch(`/kitchen/api/ingredients/suggest?description=${encodeURIComponent(query)}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok) setIngredientSuggestions(await res.json()) if (res.ok) setIngredientSuggestions(await res.json())
@ -371,7 +371,7 @@ export default function SearchLineItems() {
try { try {
// Update the most recent line item's pack fields if we have one // Update the most recent line item's pack fields if we have one
if (modalItem.most_recent_line_item_id && modalItem.most_recent_invoice_id) { if (modalItem.most_recent_line_item_id && modalItem.most_recent_invoice_id) {
await fetch(`/api/invoices/${modalItem.most_recent_invoice_id}/line-items/${modalItem.most_recent_line_item_id}`, { await fetch(`/kitchen/api/invoices/${modalItem.most_recent_invoice_id}/line-items/${modalItem.most_recent_line_item_id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@ -399,7 +399,7 @@ export default function SearchLineItems() {
if (costEdits.unit_price) sourceData.latest_unit_price = costEdits.unit_price if (costEdits.unit_price) sourceData.latest_unit_price = costEdits.unit_price
if (modalItem.most_recent_invoice_id) sourceData.invoice_id = modalItem.most_recent_invoice_id if (modalItem.most_recent_invoice_id) sourceData.invoice_id = modalItem.most_recent_invoice_id
await fetch(`/api/ingredients/${selectedIngredientId}/sources`, { await fetch(`/kitchen/api/ingredients/${selectedIngredientId}/sources`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(sourceData), body: JSON.stringify(sourceData),

View file

@ -31,7 +31,7 @@ export default function Suppliers() {
const { data: suppliers, isLoading } = useQuery<Supplier[]>({ const { data: suppliers, isLoading } = useQuery<Supplier[]>({
queryKey: ['suppliers'], queryKey: ['suppliers'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch suppliers') if (!res.ok) throw new Error('Failed to fetch suppliers')
@ -41,7 +41,7 @@ export default function Suppliers() {
const createMutation = useMutation({ const createMutation = useMutation({
mutationFn: async ({ name, aliases, skip_dext, order_email, account_number }: { name: string; aliases: string[]; skip_dext: boolean; order_email: string; account_number: string }) => { mutationFn: async ({ name, aliases, skip_dext, order_email, account_number }: { name: string; aliases: string[]; skip_dext: boolean; order_email: string; account_number: string }) => {
const res = await fetch('/api/suppliers/', { const res = await fetch('/kitchen/api/suppliers/', {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -66,7 +66,7 @@ export default function Suppliers() {
const updateMutation = useMutation({ const updateMutation = useMutation({
mutationFn: async ({ id, name, aliases, skip_dext, order_email, account_number }: { id: number; name: string; aliases: string[]; skip_dext: boolean; order_email: string; account_number: string }) => { mutationFn: async ({ id, name, aliases, skip_dext, order_email, account_number }: { id: number; name: string; aliases: string[]; skip_dext: boolean; order_email: string; account_number: string }) => {
const res = await fetch(`/api/suppliers/${id}`, { const res = await fetch(`/kitchen/api/suppliers/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -91,7 +91,7 @@ export default function Suppliers() {
const deleteMutation = useMutation({ const deleteMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/suppliers/${id}`, { const res = await fetch(`/kitchen/api/suppliers/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })

View file

@ -18,7 +18,7 @@ export default function SupportButton() {
const { data: supportStatus } = useQuery<SupportEnabledResponse>({ const { data: supportStatus } = useQuery<SupportEnabledResponse>({
queryKey: ['support-enabled'], queryKey: ['support-enabled'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/support/enabled', { const res = await fetch('/kitchen/api/support/enabled', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return { enabled: false } if (!res.ok) return { enabled: false }
@ -31,7 +31,7 @@ export default function SupportButton() {
// Submit support request // Submit support request
const submitMutation = useMutation({ const submitMutation = useMutation({
mutationFn: async (data: { description: string; screenshot: string }) => { mutationFn: async (data: { description: string; screenshot: string }) => {
const res = await fetch('/api/support/request', { const res = await fetch('/kitchen/api/support/request', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View file

@ -159,7 +159,7 @@ export default function Upload() {
item.id === queueId ? { ...item, status: 'processing' as const } : item item.id === queueId ? { ...item, status: 'processing' as const } : item
)) ))
const res = await fetch('/api/invoices/upload', { const res = await fetch('/kitchen/api/invoices/upload', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
body: formData, body: formData,

View file

@ -107,7 +107,7 @@ export default function UsageVarianceReport() {
setError(null) setError(null)
try { try {
const res = await fetch( const res = await fetch(
`/api/reports/usage-variance?from_date=${fromDate}&to_date=${toDate}`, `/kitchen/api/reports/usage-variance?from_date=${fromDate}&to_date=${toDate}`,
{ headers: { Authorization: `Bearer ${token}` } } { headers: { Authorization: `Bearer ${token}` } }
) )
if (!res.ok) { if (!res.ok) {

View file

@ -151,7 +151,7 @@ export default function BookingsStats() {
const { data: stats, isLoading } = useQuery<StatsData>({ const { data: stats, isLoading } = useQuery<StatsData>({
queryKey: ['resos-stats', submittedFromDate, submittedToDate], queryKey: ['resos-stats', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/resos/stats?from_date=${submittedFromDate}&to_date=${submittedToDate}`, { const res = await fetch(`/kitchen/api/resos/stats?from_date=${submittedFromDate}&to_date=${submittedToDate}`, {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (!res.ok) throw new Error('Failed to fetch stats') if (!res.ok) throw new Error('Failed to fetch stats')
@ -182,7 +182,7 @@ export default function BookingsStats() {
queryKey: ['resos-stats-previous', submittedFromDate, submittedToDate], queryKey: ['resos-stats-previous', submittedFromDate, submittedToDate],
queryFn: async () => { queryFn: async () => {
const prevDates = getPreviousPeriodDates() const prevDates = getPreviousPeriodDates()
const res = await fetch(`/api/resos/stats?from_date=${prevDates.from}&to_date=${prevDates.to}`, { const res = await fetch(`/kitchen/api/resos/stats?from_date=${prevDates.from}&to_date=${prevDates.to}`, {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (!res.ok) throw new Error('Failed to fetch previous stats') if (!res.ok) throw new Error('Failed to fetch previous stats')
@ -195,7 +195,7 @@ export default function BookingsStats() {
const { data: selectedDayBookings } = useQuery<Booking[]>({ const { data: selectedDayBookings } = useQuery<Booking[]>({
queryKey: ['resos-bookings', selectedDate], queryKey: ['resos-bookings', selectedDate],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/resos/bookings/${selectedDate}`, { const res = await fetch(`/kitchen/api/resos/bookings/${selectedDate}`, {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (!res.ok) throw new Error('Failed to fetch bookings') if (!res.ok) throw new Error('Failed to fetch bookings')

View file

@ -51,7 +51,7 @@ export default function NewbookData() {
const { data: settings } = useQuery<Settings>({ const { data: settings } = useQuery<Settings>({
queryKey: ['settings'], queryKey: ['settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/', { const res = await fetch('/kitchen/api/settings/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch settings') if (!res.ok) throw new Error('Failed to fetch settings')
@ -65,7 +65,7 @@ export default function NewbookData() {
const { data: calendarData, isLoading } = useQuery<CalendarData>({ const { data: calendarData, isLoading } = useQuery<CalendarData>({
queryKey: ['newbook-calendar', year, month], queryKey: ['newbook-calendar', year, month],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/newbook/calendar/${year}/${month}`, { const res = await fetch(`/kitchen/api/newbook/calendar/${year}/${month}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch calendar data') if (!res.ok) throw new Error('Failed to fetch calendar data')

View file

@ -66,7 +66,7 @@ export default function ResidentsTableChart() {
const { data, isLoading } = useQuery<ChartData>({ const { data, isLoading } = useQuery<ChartData>({
queryKey: ['residents-table-chart', 'v2', startDate], // v2 to invalidate old cache queryKey: ['residents-table-chart', 'v2', startDate], // v2 to invalidate old cache
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/residents-table-chart?start_date=${startDate}`, { const res = await fetch(`/kitchen/api/residents-table-chart?start_date=${startDate}`, {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (!res.ok) throw new Error('Failed to fetch chart data') if (!res.ok) throw new Error('Failed to fetch chart data')

View file

@ -115,7 +115,7 @@ export default function ResosData() {
const { data: settings } = useQuery<ResosSettings>({ const { data: settings } = useQuery<ResosSettings>({
queryKey: ['resos-settings'], queryKey: ['resos-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/resos/settings', { const res = await fetch('/kitchen/api/resos/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch settings') if (!res.ok) throw new Error('Failed to fetch settings')
@ -132,7 +132,7 @@ export default function ResosData() {
const lastDay = new Date(year, month, 0) const lastDay = new Date(year, month, 0)
const toDate = `${year}-${String(month).padStart(2, '0')}-${String(lastDay.getDate()).padStart(2, '0')}` const toDate = `${year}-${String(month).padStart(2, '0')}-${String(lastDay.getDate()).padStart(2, '0')}`
const res = await fetch(`/api/resos/daily-stats?from_date=${firstDay}&to_date=${toDate}`, { const res = await fetch(`/kitchen/api/resos/daily-stats?from_date=${firstDay}&to_date=${toDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch daily stats') if (!res.ok) throw new Error('Failed to fetch daily stats')
@ -151,7 +151,7 @@ export default function ResosData() {
const lastDay = new Date(prevYear, prevMonth, 0) const lastDay = new Date(prevYear, prevMonth, 0)
const toDate = `${prevYear}-${String(prevMonth).padStart(2, '0')}-${String(lastDay.getDate()).padStart(2, '0')}` const toDate = `${prevYear}-${String(prevMonth).padStart(2, '0')}-${String(lastDay.getDate()).padStart(2, '0')}`
const res = await fetch(`/api/resos/daily-stats?from_date=${firstDay}&to_date=${toDate}`, { const res = await fetch(`/kitchen/api/resos/daily-stats?from_date=${firstDay}&to_date=${toDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch previous month stats') if (!res.ok) throw new Error('Failed to fetch previous month stats')
@ -167,7 +167,7 @@ export default function ResosData() {
const firstDay = `${year}-${String(month).padStart(2, '0')}-01` const firstDay = `${year}-${String(month).padStart(2, '0')}-01`
const lastDay = new Date(year, month, 0) const lastDay = new Date(year, month, 0)
const toDate = `${year}-${String(month).padStart(2, '0')}-${String(lastDay.getDate()).padStart(2, '0')}` const toDate = `${year}-${String(month).padStart(2, '0')}-${String(lastDay.getDate()).padStart(2, '0')}`
const res = await fetch(`/api/calendar-events/?from_date=${firstDay}&to_date=${toDate}`, { const res = await fetch(`/kitchen/api/calendar-events/?from_date=${firstDay}&to_date=${toDate}`, {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (!res.ok) throw new Error('Failed to fetch calendar events') if (!res.ok) throw new Error('Failed to fetch calendar events')
@ -181,7 +181,7 @@ export default function ResosData() {
queryKey: ['resos-bookings', selectedDate], queryKey: ['resos-bookings', selectedDate],
queryFn: async () => { queryFn: async () => {
if (!selectedDate) return [] if (!selectedDate) return []
const res = await fetch(`/api/resos/bookings/${selectedDate}`, { const res = await fetch(`/kitchen/api/resos/bookings/${selectedDate}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch bookings') if (!res.ok) throw new Error('Failed to fetch bookings')
@ -194,7 +194,7 @@ export default function ResosData() {
const { data: allOpeningHoursData } = useQuery<{ opening_hours: any[] }>({ const { data: allOpeningHoursData } = useQuery<{ opening_hours: any[] }>({
queryKey: ['resos-all-opening-hours'], queryKey: ['resos-all-opening-hours'],
queryFn: async () => { queryFn: async () => {
const res = await fetch(`/api/resos/opening-hours`, { const res = await fetch(`/kitchen/api/resos/opening-hours`, {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (!res.ok) throw new Error('Failed to fetch opening hours') if (!res.ok) throw new Error('Failed to fetch opening hours')
@ -230,7 +230,7 @@ export default function ResosData() {
queryKey: ['resos-opening-hours', selectedDate], queryKey: ['resos-opening-hours', selectedDate],
queryFn: async () => { queryFn: async () => {
if (!selectedDate) return [] if (!selectedDate) return []
const res = await fetch(`/api/resos/opening-hours/${selectedDate}`, { const res = await fetch(`/kitchen/api/resos/opening-hours/${selectedDate}`, {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (!res.ok) throw new Error('Failed to fetch opening hours') if (!res.ok) throw new Error('Failed to fetch opening hours')
@ -1322,7 +1322,7 @@ export default function ResosData() {
<button <button
onClick={async () => { onClick={async () => {
if (confirm('Delete this event?')) { if (confirm('Delete this event?')) {
await fetch(`/api/calendar-events/${editingEvent.id}`, { await fetch(`/kitchen/api/calendar-events/${editingEvent.id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -1359,8 +1359,8 @@ export default function ResosData() {
<button <button
onClick={async () => { onClick={async () => {
const url = editingEvent const url = editingEvent
? `/api/calendar-events/${editingEvent.id}` ? `/kitchen/api/calendar-events/${editingEvent.id}`
: '/api/calendar-events/' : '/kitchen/api/calendar-events/'
const method = editingEvent ? 'PUT' : 'POST' const method = editingEvent ? 'PUT' : 'POST'
await fetch(url, { await fetch(url, {

View file

@ -530,7 +530,7 @@ export default function Settings() {
const { data: settings, isLoading } = useQuery<SettingsData>({ const { data: settings, isLoading } = useQuery<SettingsData>({
queryKey: ['settings'], queryKey: ['settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/', { const res = await fetch('/kitchen/api/settings/', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch settings') if (!res.ok) throw new Error('Failed to fetch settings')
@ -542,7 +542,7 @@ export default function Settings() {
const { data: newbookSettings, error: newbookError, isLoading: newbookLoading } = useQuery<NewbookSettingsData>({ const { data: newbookSettings, error: newbookError, isLoading: newbookLoading } = useQuery<NewbookSettingsData>({
queryKey: ['newbook-settings'], queryKey: ['newbook-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/newbook/settings', { const res = await fetch('/kitchen/api/newbook/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) { if (!res.ok) {
@ -561,7 +561,7 @@ export default function Settings() {
const { data: resosSettings, error: resosError, isLoading: resosLoading } = useQuery<ResosSettingsData>({ const { data: resosSettings, error: resosError, isLoading: resosLoading } = useQuery<ResosSettingsData>({
queryKey: ['resos-settings'], queryKey: ['resos-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/resos/settings', { const res = await fetch('/kitchen/api/resos/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) { if (!res.ok) {
@ -579,7 +579,7 @@ export default function Settings() {
const { data: glAccounts, refetch: refetchGLAccounts } = useQuery<GLAccount[]>({ const { data: glAccounts, refetch: refetchGLAccounts } = useQuery<GLAccount[]>({
queryKey: ['gl-accounts'], queryKey: ['gl-accounts'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/newbook/gl-accounts', { const res = await fetch('/kitchen/api/newbook/gl-accounts', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -591,7 +591,7 @@ export default function Settings() {
const { data: roomCategories, refetch: refetchRoomCategories } = useQuery<RoomCategory[]>({ const { data: roomCategories, refetch: refetchRoomCategories } = useQuery<RoomCategory[]>({
queryKey: ['room-categories'], queryKey: ['room-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/newbook/room-categories', { const res = await fetch('/kitchen/api/newbook/room-categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -619,7 +619,7 @@ export default function Settings() {
const { data: sambaSettings } = useQuery<SambaPOSSettingsData>({ const { data: sambaSettings } = useQuery<SambaPOSSettingsData>({
queryKey: ['sambapos-settings'], queryKey: ['sambapos-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/sambapos/settings', { const res = await fetch('/kitchen/api/sambapos/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch SambaPOS settings') if (!res.ok) throw new Error('Failed to fetch SambaPOS settings')
@ -632,7 +632,7 @@ export default function Settings() {
const { data: sambaCategories, refetch: refetchSambaCategories, isLoading: sambaCategoriesLoading, error: sambaCategoriesError } = useQuery<SambaPOSCategory[]>({ const { data: sambaCategories, refetch: refetchSambaCategories, isLoading: sambaCategoriesLoading, error: sambaCategoriesError } = useQuery<SambaPOSCategory[]>({
queryKey: ['sambapos-categories'], queryKey: ['sambapos-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/sambapos/categories', { const res = await fetch('/kitchen/api/sambapos/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) { if (!res.ok) {
@ -649,7 +649,7 @@ export default function Settings() {
const { data: sambaGroupCodes, refetch: refetchSambaGroupCodes, isLoading: sambaGroupCodesLoading } = useQuery<SambaPOSGroupCode[]>({ const { data: sambaGroupCodes, refetch: refetchSambaGroupCodes, isLoading: sambaGroupCodesLoading } = useQuery<SambaPOSGroupCode[]>({
queryKey: ['sambapos-group-codes'], queryKey: ['sambapos-group-codes'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/sambapos/group-codes', { const res = await fetch('/kitchen/api/sambapos/group-codes', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) { if (!res.ok) {
@ -666,7 +666,7 @@ export default function Settings() {
const { data: sambaGLCodes, refetch: refetchSambaGLCodes, isLoading: sambaGLCodesLoading } = useQuery<SambaPOSGLCode[]>({ const { data: sambaGLCodes, refetch: refetchSambaGLCodes, isLoading: sambaGLCodesLoading } = useQuery<SambaPOSGLCode[]>({
queryKey: ['sambapos-gl-codes'], queryKey: ['sambapos-gl-codes'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/sambapos/gl-codes', { const res = await fetch('/kitchen/api/sambapos/gl-codes', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) { if (!res.ok) {
@ -683,7 +683,7 @@ export default function Settings() {
const { data: selectedGLCodes } = useQuery<{ food_codes: string[]; beverage_codes: string[] }>({ const { data: selectedGLCodes } = useQuery<{ food_codes: string[]; beverage_codes: string[] }>({
queryKey: ['sambapos-selected-gl-codes'], queryKey: ['sambapos-selected-gl-codes'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/sambapos/gl-codes/selected', { const res = await fetch('/kitchen/api/sambapos/gl-codes/selected', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch selected GL codes') if (!res.ok) throw new Error('Failed to fetch selected GL codes')
@ -696,7 +696,7 @@ export default function Settings() {
const { data: kdsSettings } = useQuery<KDSSettingsData>({ const { data: kdsSettings } = useQuery<KDSSettingsData>({
queryKey: ['kds-settings'], queryKey: ['kds-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/kds/settings', { const res = await fetch('/kitchen/api/kds/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch KDS settings') if (!res.ok) throw new Error('Failed to fetch KDS settings')
@ -719,7 +719,7 @@ export default function Settings() {
const { data: kitchenDetails } = useQuery<KitchenDetailsData>({ const { data: kitchenDetails } = useQuery<KitchenDetailsData>({
queryKey: ['kitchen-details'], queryKey: ['kitchen-details'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/kitchen-details', { const res = await fetch('/kitchen/api/settings/kitchen-details', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch kitchen details') if (!res.ok) throw new Error('Failed to fetch kitchen details')
@ -739,7 +739,7 @@ export default function Settings() {
const { data: budgetSettings } = useQuery<BudgetSettingsData>({ const { data: budgetSettings } = useQuery<BudgetSettingsData>({
queryKey: ['budget-settings'], queryKey: ['budget-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/budget/settings', { const res = await fetch('/kitchen/api/budget/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch Budget settings') if (!res.ok) throw new Error('Failed to fetch Budget settings')
@ -752,7 +752,7 @@ export default function Settings() {
const { data: pageRestrictions } = useQuery<{ restricted_pages: string[] }>({ const { data: pageRestrictions } = useQuery<{ restricted_pages: string[] }>({
queryKey: ['page-restrictions'], queryKey: ['page-restrictions'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/page-restrictions', { const res = await fetch('/kitchen/api/settings/page-restrictions', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch page restrictions') if (!res.ok) throw new Error('Failed to fetch page restrictions')
@ -765,7 +765,7 @@ export default function Settings() {
const { data: nextcloudSettings } = useQuery<NextcloudSettingsData>({ const { data: nextcloudSettings } = useQuery<NextcloudSettingsData>({
queryKey: ['nextcloud-settings'], queryKey: ['nextcloud-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/nextcloud', { const res = await fetch('/kitchen/api/settings/nextcloud', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch Nextcloud settings') if (!res.ok) throw new Error('Failed to fetch Nextcloud settings')
@ -778,7 +778,7 @@ export default function Settings() {
const { data: nextcloudStats } = useQuery<NextcloudStatsData>({ const { data: nextcloudStats } = useQuery<NextcloudStatsData>({
queryKey: ['nextcloud-stats'], queryKey: ['nextcloud-stats'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/nextcloud/stats', { const res = await fetch('/kitchen/api/settings/nextcloud/stats', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch Nextcloud stats') if (!res.ok) throw new Error('Failed to fetch Nextcloud stats')
@ -791,7 +791,7 @@ export default function Settings() {
const { data: backupSettings } = useQuery<BackupSettingsData>({ const { data: backupSettings } = useQuery<BackupSettingsData>({
queryKey: ['backup-settings'], queryKey: ['backup-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/backup/settings', { const res = await fetch('/kitchen/api/backup/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch backup settings') if (!res.ok) throw new Error('Failed to fetch backup settings')
@ -804,7 +804,7 @@ export default function Settings() {
const { data: backupHistory } = useQuery<BackupHistoryEntry[]>({ const { data: backupHistory } = useQuery<BackupHistoryEntry[]>({
queryKey: ['backup-history'], queryKey: ['backup-history'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/backup/history', { const res = await fetch('/kitchen/api/backup/history', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch backup history') if (!res.ok) throw new Error('Failed to fetch backup history')
@ -817,7 +817,7 @@ export default function Settings() {
const { data: searchSettings } = useQuery<SearchSettingsData>({ const { data: searchSettings } = useQuery<SearchSettingsData>({
queryKey: ['search-settings'], queryKey: ['search-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/search/settings', { const res = await fetch('/kitchen/api/search/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch search settings') if (!res.ok) throw new Error('Failed to fetch search settings')
@ -830,7 +830,7 @@ export default function Settings() {
const { data: imapSettings } = useQuery<ImapSettingsData>({ const { data: imapSettings } = useQuery<ImapSettingsData>({
queryKey: ['imap-settings'], queryKey: ['imap-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/imap/settings', { const res = await fetch('/kitchen/api/imap/settings', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch IMAP settings') if (!res.ok) throw new Error('Failed to fetch IMAP settings')
@ -843,7 +843,7 @@ export default function Settings() {
const { data: imapLogs } = useQuery<ImapLogEntry[]>({ const { data: imapLogs } = useQuery<ImapLogEntry[]>({
queryKey: ['imap-logs'], queryKey: ['imap-logs'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/imap/logs?limit=20', { const res = await fetch('/kitchen/api/imap/logs?limit=20', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch IMAP logs') if (!res.ok) throw new Error('Failed to fetch IMAP logs')
@ -856,7 +856,7 @@ export default function Settings() {
const { data: imapStats } = useQuery<ImapSyncStats>({ const { data: imapStats } = useQuery<ImapSyncStats>({
queryKey: ['imap-stats'], queryKey: ['imap-stats'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/imap/logs/stats', { const res = await fetch('/kitchen/api/imap/logs/stats', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) throw new Error('Failed to fetch IMAP stats') if (!res.ok) throw new Error('Failed to fetch IMAP stats')
@ -1065,7 +1065,7 @@ export default function Settings() {
// Auto-fetch custom fields if mapping exists but fields list is empty // Auto-fetch custom fields if mapping exists but fields list is empty
if (resosSettings.resos_custom_field_mapping && Object.keys(resosSettings.resos_custom_field_mapping).length > 0 && customFields.length === 0) { if (resosSettings.resos_custom_field_mapping && Object.keys(resosSettings.resos_custom_field_mapping).length > 0 && customFields.length === 0) {
fetch('/api/resos/custom-fields', { fetch('/kitchen/api/resos/custom-fields', {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
.then(res => res.json()) .then(res => res.json())
@ -1075,7 +1075,7 @@ export default function Settings() {
// Auto-fetch opening hours if mapping exists but hours list is empty // Auto-fetch opening hours if mapping exists but hours list is empty
if (resosSettings.resos_opening_hours_mapping && resosSettings.resos_opening_hours_mapping.length > 0 && openingHours.length === 0) { if (resosSettings.resos_opening_hours_mapping && resosSettings.resos_opening_hours_mapping.length > 0 && openingHours.length === 0) {
fetch('/api/resos/opening-hours', { fetch('/kitchen/api/resos/opening-hours', {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
.then(res => res.json()) .then(res => res.json())
@ -1089,7 +1089,7 @@ export default function Settings() {
const { data: foodFlagCategories, refetch: refetchFoodFlags } = useQuery<FoodFlagCategoryData[]>({ const { data: foodFlagCategories, refetch: refetchFoodFlags } = useQuery<FoodFlagCategoryData[]>({
queryKey: ['food-flag-categories'], queryKey: ['food-flag-categories'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/food-flags/categories', { const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -1101,7 +1101,7 @@ export default function Settings() {
const { data: apiAccessSettings } = useQuery<ApiAccessData>({ const { data: apiAccessSettings } = useQuery<ApiAccessData>({
queryKey: ['api-access-settings'], queryKey: ['api-access-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/api-access', { const res = await fetch('/kitchen/api/settings/api-access', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return { api_key: null, api_key_enabled: false } if (!res.ok) return { api_key: null, api_key_enabled: false }
@ -1120,7 +1120,7 @@ export default function Settings() {
// Food Flag mutations // Food Flag mutations
const createCategoryMutation = useMutation({ const createCategoryMutation = useMutation({
mutationFn: async (data: { name: string; propagation_type: string }) => { mutationFn: async (data: { name: string; propagation_type: string }) => {
const res = await fetch('/api/food-flags/categories', { const res = await fetch('/kitchen/api/food-flags/categories', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -1141,7 +1141,7 @@ export default function Settings() {
const updateCategoryMutation = useMutation({ const updateCategoryMutation = useMutation({
mutationFn: async ({ id, data }: { id: number; data: { name?: string; propagation_type?: string; required?: boolean } }) => { mutationFn: async ({ id, data }: { id: number; data: { name?: string; propagation_type?: string; required?: boolean } }) => {
const res = await fetch(`/api/food-flags/categories/${id}`, { const res = await fetch(`/kitchen/api/food-flags/categories/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -1160,7 +1160,7 @@ export default function Settings() {
const deleteCategoryMutation = useMutation({ const deleteCategoryMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/food-flags/categories/${id}`, { const res = await fetch(`/kitchen/api/food-flags/categories/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1177,7 +1177,7 @@ export default function Settings() {
const createFlagMutation = useMutation({ const createFlagMutation = useMutation({
mutationFn: async (data: { category_id: number; name: string; code?: string; icon?: string }) => { mutationFn: async (data: { category_id: number; name: string; code?: string; icon?: string }) => {
const res = await fetch('/api/food-flags/flags', { const res = await fetch('/kitchen/api/food-flags/flags', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -1199,7 +1199,7 @@ export default function Settings() {
const updateFlagMutation = useMutation({ const updateFlagMutation = useMutation({
mutationFn: async ({ id, data }: { id: number; data: { name?: string; code?: string; icon?: string } }) => { mutationFn: async ({ id, data }: { id: number; data: { name?: string; code?: string; icon?: string } }) => {
const res = await fetch(`/api/food-flags/flags/${id}`, { const res = await fetch(`/kitchen/api/food-flags/flags/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -1218,7 +1218,7 @@ export default function Settings() {
const deleteFlagMutation = useMutation({ const deleteFlagMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/food-flags/flags/${id}`, { const res = await fetch(`/kitchen/api/food-flags/flags/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1250,7 +1250,7 @@ export default function Settings() {
const { data: allergenKeywords, refetch: refetchAllergenKeywords } = useQuery<AllergenKeywordGroup[]>({ const { data: allergenKeywords, refetch: refetchAllergenKeywords } = useQuery<AllergenKeywordGroup[]>({
queryKey: ['allergen-keywords'], queryKey: ['allergen-keywords'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/food-flags/keywords', { const res = await fetch('/kitchen/api/food-flags/keywords', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -1261,7 +1261,7 @@ export default function Settings() {
const addKeywordMutation = useMutation({ const addKeywordMutation = useMutation({
mutationFn: async ({ food_flag_id, keyword }: { food_flag_id: number; keyword: string }) => { mutationFn: async ({ food_flag_id, keyword }: { food_flag_id: number; keyword: string }) => {
const res = await fetch('/api/food-flags/keywords', { const res = await fetch('/kitchen/api/food-flags/keywords', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ food_flag_id, keyword }), body: JSON.stringify({ food_flag_id, keyword }),
@ -1286,7 +1286,7 @@ export default function Settings() {
const deleteKeywordMutation = useMutation({ const deleteKeywordMutation = useMutation({
mutationFn: async (keywordId: number) => { mutationFn: async (keywordId: number) => {
const res = await fetch(`/api/food-flags/keywords/${keywordId}`, { const res = await fetch(`/kitchen/api/food-flags/keywords/${keywordId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1299,7 +1299,7 @@ export default function Settings() {
const resetKeywordsMutation = useMutation({ const resetKeywordsMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/food-flags/keywords/reset-defaults', { const res = await fetch('/kitchen/api/food-flags/keywords/reset-defaults', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1323,7 +1323,7 @@ export default function Settings() {
const { data: ingCategories, refetch: refetchIngCategories } = useQuery<IngredientCategoryItem[]>({ const { data: ingCategories, refetch: refetchIngCategories } = useQuery<IngredientCategoryItem[]>({
queryKey: ['ingredient-categories-settings'], queryKey: ['ingredient-categories-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/ingredients/categories', { const res = await fetch('/kitchen/api/ingredients/categories', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -1334,7 +1334,7 @@ export default function Settings() {
const createIngCatMutation = useMutation({ const createIngCatMutation = useMutation({
mutationFn: async (data: { name: string; sort_order: number }) => { mutationFn: async (data: { name: string; sort_order: number }) => {
const res = await fetch('/api/ingredients/categories', { const res = await fetch('/kitchen/api/ingredients/categories', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -1355,7 +1355,7 @@ export default function Settings() {
const updateIngCatMutation = useMutation({ const updateIngCatMutation = useMutation({
mutationFn: async ({ id, data }: { id: number; data: { name?: string; sort_order?: number } }) => { mutationFn: async ({ id, data }: { id: number; data: { name?: string; sort_order?: number } }) => {
const res = await fetch(`/api/ingredients/categories/${id}`, { const res = await fetch(`/kitchen/api/ingredients/categories/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -1374,7 +1374,7 @@ export default function Settings() {
const deleteIngCatMutation = useMutation({ const deleteIngCatMutation = useMutation({
mutationFn: async (id: number) => { mutationFn: async (id: number) => {
const res = await fetch(`/api/ingredients/categories/${id}`, { const res = await fetch(`/kitchen/api/ingredients/categories/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1405,7 +1405,7 @@ export default function Settings() {
const { data: recipeSections, refetch: refetchRecipeSections } = useQuery<{ id: number; name: string; sort_order: number; section_type: string; recipe_count: number }[]>({ const { data: recipeSections, refetch: refetchRecipeSections } = useQuery<{ id: number; name: string; sort_order: number; section_type: string; recipe_count: number }[]>({
queryKey: ['recipe-sections-settings'], queryKey: ['recipe-sections-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes/menu-sections?section_type=recipe', { const res = await fetch('/kitchen/api/recipes/menu-sections?section_type=recipe', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -1418,7 +1418,7 @@ export default function Settings() {
const { data: dishCourses, refetch: refetchDishCourses } = useQuery<{ id: number; name: string; sort_order: number; section_type: string; recipe_count: number }[]>({ const { data: dishCourses, refetch: refetchDishCourses } = useQuery<{ id: number; name: string; sort_order: number; section_type: string; recipe_count: number }[]>({
queryKey: ['dish-courses-settings'], queryKey: ['dish-courses-settings'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/recipes/menu-sections?section_type=dish', { const res = await fetch('/kitchen/api/recipes/menu-sections?section_type=dish', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return [] if (!res.ok) return []
@ -1430,7 +1430,7 @@ export default function Settings() {
// API Access mutations // API Access mutations
const saveApiAccessMutation = useMutation({ const saveApiAccessMutation = useMutation({
mutationFn: async (data: { api_key_enabled: boolean }) => { mutationFn: async (data: { api_key_enabled: boolean }) => {
const res = await fetch('/api/settings/api-access', { const res = await fetch('/kitchen/api/settings/api-access', {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -1449,7 +1449,7 @@ export default function Settings() {
const regenerateApiKeyMutation = useMutation({ const regenerateApiKeyMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/settings/api-access/regenerate', { const res = await fetch('/kitchen/api/settings/api-access/regenerate', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1474,7 +1474,7 @@ export default function Settings() {
}>({ }>({
queryKey: ['llm-usage'], queryKey: ['llm-usage'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/llm-usage', { const res = await fetch('/kitchen/api/settings/llm-usage', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return { total_calls: 0, successful_calls: 0, failed_calls: 0, total_input_tokens: 0, total_output_tokens: 0, total_tokens: 0, estimated_cost_usd: 0, cache_entries_this_month: 0 } if (!res.ok) return { total_calls: 0, successful_calls: 0, failed_calls: 0, total_input_tokens: 0, total_output_tokens: 0, total_tokens: 0, estimated_cost_usd: 0, cache_entries_this_month: 0 }
@ -1492,7 +1492,7 @@ export default function Settings() {
}>({ }>({
queryKey: ['llm-models'], queryKey: ['llm-models'],
queryFn: async () => { queryFn: async () => {
const res = await fetch('/api/settings/llm-models', { const res = await fetch('/kitchen/api/settings/llm-models', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (!res.ok) return { models: [], default: 'claude-haiku-4-5-20251001', current: 'claude-haiku-4-5-20251001' } if (!res.ok) return { models: [], default: 'claude-haiku-4-5-20251001', current: 'claude-haiku-4-5-20251001' }
@ -1504,7 +1504,7 @@ export default function Settings() {
const saveLlmSettingsMutation = useMutation({ const saveLlmSettingsMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/settings/', { const res = await fetch('/kitchen/api/settings/', {
method: 'PATCH', method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data), body: JSON.stringify(data),
@ -1523,7 +1523,7 @@ export default function Settings() {
const llmTestMutation = useMutation({ const llmTestMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/settings/test-llm', { const res = await fetch('/kitchen/api/settings/test-llm', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1559,7 +1559,7 @@ export default function Settings() {
// Mutations // Mutations
const updateMutation = useMutation({ const updateMutation = useMutation({
mutationFn: async (data: Partial<SettingsData & { azure_key?: string }>) => { mutationFn: async (data: Partial<SettingsData & { azure_key?: string }>) => {
const res = await fetch('/api/settings/', { const res = await fetch('/kitchen/api/settings/', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1583,7 +1583,7 @@ export default function Settings() {
const azureTestMutation = useMutation({ const azureTestMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/settings/test-azure', { const res = await fetch('/kitchen/api/settings/test-azure', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1683,7 +1683,7 @@ export default function Settings() {
const savePageRestrictionsMutation = useMutation({ const savePageRestrictionsMutation = useMutation({
mutationFn: async (pages: string[]) => { mutationFn: async (pages: string[]) => {
const res = await fetch('/api/settings/page-restrictions', { const res = await fetch('/kitchen/api/settings/page-restrictions', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1706,7 +1706,7 @@ export default function Settings() {
const reprocessMutation = useMutation({ const reprocessMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/invoices/reprocess-all', { const res = await fetch('/kitchen/api/invoices/reprocess-all', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1728,7 +1728,7 @@ export default function Settings() {
const cleanupPriceChangesMutation = useMutation({ const cleanupPriceChangesMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/recipes/cleanup-false-price-changes', { const res = await fetch('/kitchen/api/recipes/cleanup-false-price-changes', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1749,7 +1749,7 @@ export default function Settings() {
const backfillInvoiceRefsMutation = useMutation({ const backfillInvoiceRefsMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/recipes/backfill-invoice-references', { const res = await fetch('/kitchen/api/recipes/backfill-invoice-references', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1770,7 +1770,7 @@ export default function Settings() {
const rematchFuzzyMutation = useMutation({ const rematchFuzzyMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/suppliers/rematch-fuzzy', { const res = await fetch('/kitchen/api/suppliers/rematch-fuzzy', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1794,7 +1794,7 @@ export default function Settings() {
const updateNewbookMutation = useMutation({ const updateNewbookMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
console.log('[Newbook] Sending PATCH with data:', data) console.log('[Newbook] Sending PATCH with data:', data)
const res = await fetch('/api/newbook/settings', { const res = await fetch('/kitchen/api/newbook/settings', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1826,7 +1826,7 @@ export default function Settings() {
const newbookTestMutation = useMutation({ const newbookTestMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/newbook/test-connection', { const res = await fetch('/kitchen/api/newbook/test-connection', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1849,7 +1849,7 @@ export default function Settings() {
const updateResosSyncMutation = useMutation({ const updateResosSyncMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
console.log('[Resos] Sending PATCH with data:', data) console.log('[Resos] Sending PATCH with data:', data)
const res = await fetch('/api/resos/settings', { const res = await fetch('/kitchen/api/resos/settings', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1879,7 +1879,7 @@ export default function Settings() {
const fetchGLAccountsMutation = useMutation({ const fetchGLAccountsMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/newbook/gl-accounts/fetch', { const res = await fetch('/kitchen/api/newbook/gl-accounts/fetch', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1901,7 +1901,7 @@ export default function Settings() {
const syncForecastMutation = useMutation({ const syncForecastMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/newbook/sync/forecast', { const res = await fetch('/kitchen/api/newbook/sync/forecast', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -1923,7 +1923,7 @@ export default function Settings() {
const syncHistoricalMutation = useMutation({ const syncHistoricalMutation = useMutation({
mutationFn: async (dates: { date_from: string; date_to: string }) => { mutationFn: async (dates: { date_from: string; date_to: string }) => {
const res = await fetch('/api/newbook/sync/historical', { const res = await fetch('/kitchen/api/newbook/sync/historical', {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1950,7 +1950,7 @@ export default function Settings() {
const updateGLAccountMutation = useMutation({ const updateGLAccountMutation = useMutation({
mutationFn: async ({ id, is_tracked }: { id: number; is_tracked: boolean }) => { mutationFn: async ({ id, is_tracked }: { id: number; is_tracked: boolean }) => {
const res = await fetch(`/api/newbook/gl-accounts/${id}`, { const res = await fetch(`/kitchen/api/newbook/gl-accounts/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1968,7 +1968,7 @@ export default function Settings() {
const bulkUpdateGLAccountsMutation = useMutation({ const bulkUpdateGLAccountsMutation = useMutation({
mutationFn: async (updates: { id: number; is_tracked: boolean }[]) => { mutationFn: async (updates: { id: number; is_tracked: boolean }[]) => {
const res = await fetch('/api/newbook/gl-accounts/bulk-update', { const res = await fetch('/kitchen/api/newbook/gl-accounts/bulk-update', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -1987,7 +1987,7 @@ export default function Settings() {
// Room category mutations // Room category mutations
const fetchRoomCategoriesMutation = useMutation({ const fetchRoomCategoriesMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/newbook/room-categories/fetch', { const res = await fetch('/kitchen/api/newbook/room-categories/fetch', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -2009,7 +2009,7 @@ export default function Settings() {
const bulkUpdateRoomCategoriesMutation = useMutation({ const bulkUpdateRoomCategoriesMutation = useMutation({
mutationFn: async (updates: { id: number; is_included: boolean }[]) => { mutationFn: async (updates: { id: number; is_included: boolean }[]) => {
const res = await fetch('/api/newbook/room-categories/bulk-update', { const res = await fetch('/kitchen/api/newbook/room-categories/bulk-update', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2028,7 +2028,7 @@ export default function Settings() {
// SambaPOS mutations // SambaPOS mutations
const updateSambaMutation = useMutation({ const updateSambaMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/sambapos/settings', { const res = await fetch('/kitchen/api/sambapos/settings', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2052,7 +2052,7 @@ export default function Settings() {
const sambaTestMutation = useMutation({ const sambaTestMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/sambapos/test-connection', { const res = await fetch('/kitchen/api/sambapos/test-connection', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -2074,7 +2074,7 @@ export default function Settings() {
const saveSambaCoursesMutation = useMutation({ const saveSambaCoursesMutation = useMutation({
mutationFn: async (courses: string[]) => { mutationFn: async (courses: string[]) => {
const res = await fetch('/api/sambapos/tracked-categories', { const res = await fetch('/kitchen/api/sambapos/tracked-categories', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2097,7 +2097,7 @@ export default function Settings() {
const saveExcludedItemsMutation = useMutation({ const saveExcludedItemsMutation = useMutation({
mutationFn: async (items: string[]) => { mutationFn: async (items: string[]) => {
const res = await fetch('/api/sambapos/excluded-items', { const res = await fetch('/kitchen/api/sambapos/excluded-items', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2120,7 +2120,7 @@ export default function Settings() {
const saveGLCodesMutation = useMutation({ const saveGLCodesMutation = useMutation({
mutationFn: async (data: { food_codes: string[]; beverage_codes: string[] }) => { mutationFn: async (data: { food_codes: string[]; beverage_codes: string[] }) => {
const res = await fetch('/api/sambapos/gl-codes', { const res = await fetch('/kitchen/api/sambapos/gl-codes', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2144,7 +2144,7 @@ export default function Settings() {
// KDS mutations // KDS mutations
const updateKdsMutation = useMutation({ const updateKdsMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/kds/settings', { const res = await fetch('/kitchen/api/kds/settings', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2168,7 +2168,7 @@ export default function Settings() {
const kdsTestMutation = useMutation({ const kdsTestMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/kds/test-connection', { const res = await fetch('/kitchen/api/kds/test-connection', {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
const data = await res.json() const data = await res.json()
@ -2189,7 +2189,7 @@ export default function Settings() {
// Budget/Forecast API mutations // Budget/Forecast API mutations
const saveKitchenDetailsMutation = useMutation({ const saveKitchenDetailsMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/settings/kitchen-details', { const res = await fetch('/kitchen/api/settings/kitchen-details', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2215,7 +2215,7 @@ export default function Settings() {
const saveBudgetMutation = useMutation({ const saveBudgetMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/budget/settings', { const res = await fetch('/kitchen/api/budget/settings', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2242,7 +2242,7 @@ export default function Settings() {
const budgetTestMutation = useMutation({ const budgetTestMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/budget/test-forecast-connection', { const res = await fetch('/kitchen/api/budget/test-forecast-connection', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -2264,7 +2264,7 @@ export default function Settings() {
// Nextcloud mutations // Nextcloud mutations
const saveNextcloudMutation = useMutation({ const saveNextcloudMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/settings/nextcloud', { const res = await fetch('/kitchen/api/settings/nextcloud', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2291,7 +2291,7 @@ export default function Settings() {
const nextcloudTestMutation = useMutation({ const nextcloudTestMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/settings/nextcloud/test', { const res = await fetch('/kitchen/api/settings/nextcloud/test', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -2312,7 +2312,7 @@ export default function Settings() {
const archiveAllMutation = useMutation({ const archiveAllMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/settings/nextcloud/archive-all', { const res = await fetch('/kitchen/api/settings/nextcloud/archive-all', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -2335,7 +2335,7 @@ export default function Settings() {
// Backup mutations // Backup mutations
const saveBackupMutation = useMutation({ const saveBackupMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/backup/settings', { const res = await fetch('/kitchen/api/backup/settings', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -2361,7 +2361,7 @@ export default function Settings() {
const createBackupMutation = useMutation({ const createBackupMutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const res = await fetch('/api/backup/create', { const res = await fetch('/kitchen/api/backup/create', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -2384,7 +2384,7 @@ export default function Settings() {
const restoreBackupMutation = useMutation({ const restoreBackupMutation = useMutation({
mutationFn: async (backupId: number) => { mutationFn: async (backupId: number) => {
const res = await fetch(`/api/backup/${backupId}/restore`, { const res = await fetch(`/kitchen/api/backup/${backupId}/restore`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -2407,7 +2407,7 @@ export default function Settings() {
const deleteBackupMutation = useMutation({ const deleteBackupMutation = useMutation({
mutationFn: async (backupId: number) => { mutationFn: async (backupId: number) => {
const res = await fetch(`/api/backup/${backupId}`, { const res = await fetch(`/kitchen/api/backup/${backupId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -2431,7 +2431,7 @@ export default function Settings() {
mutationFn: async (file: File) => { mutationFn: async (file: File) => {
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
const res = await fetch('/api/backup/upload', { const res = await fetch('/kitchen/api/backup/upload', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
body: formData, body: formData,
@ -2455,7 +2455,7 @@ export default function Settings() {
// Search settings mutation // Search settings mutation
const saveSearchSettingsMutation = useMutation({ const saveSearchSettingsMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => { mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/search/settings', { const res = await fetch('/kitchen/api/search/settings', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -3426,7 +3426,7 @@ export default function Settings() {
support_email: supportEmail || null support_email: supportEmail || null
} }
const saveRes = await fetch('/api/settings/', { const saveRes = await fetch('/kitchen/api/settings/', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -3444,7 +3444,7 @@ export default function Settings() {
// Now test the connection // Now test the connection
setSmtpTestStatus('Testing connection...') setSmtpTestStatus('Testing connection...')
const res = await fetch('/api/settings/test-smtp', { const res = await fetch('/kitchen/api/settings/test-smtp', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -3469,7 +3469,7 @@ export default function Settings() {
<button <button
onClick={async () => { onClick={async () => {
try { try {
const res = await fetch('/api/settings/', { const res = await fetch('/kitchen/api/settings/', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -3646,7 +3646,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
setImapTestStatus('Testing connection...') setImapTestStatus('Testing connection...')
try { try {
const res = await fetch('/api/imap/test-connection', { const res = await fetch('/kitchen/api/imap/test-connection', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -3679,7 +3679,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
setImapSyncMessage('Syncing...') setImapSyncMessage('Syncing...')
try { try {
const res = await fetch('/api/imap/sync-now', { const res = await fetch('/kitchen/api/imap/sync-now', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -3709,7 +3709,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
setImapSaveMessage('Saving...') setImapSaveMessage('Saving...')
try { try {
const res = await fetch('/api/imap/settings', { const res = await fetch('/kitchen/api/imap/settings', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -3915,7 +3915,7 @@ export default function Settings() {
<button <button
onClick={async () => { onClick={async () => {
try { try {
const res = await fetch('/api/settings/', { const res = await fetch('/kitchen/api/settings/', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -3966,7 +3966,7 @@ export default function Settings() {
return return
} }
try { try {
const res = await fetch('/api/invoices/bulk/mark-all-dext-sent', { const res = await fetch('/kitchen/api/invoices/bulk/mark-all-dext-sent', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -4329,7 +4329,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
try { try {
setResosTestStatus('Testing...') setResosTestStatus('Testing...')
const res = await fetch('/api/resos/test-connection', { const res = await fetch('/kitchen/api/resos/test-connection', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -4399,7 +4399,7 @@ export default function Settings() {
<button <button
onClick={async () => { onClick={async () => {
try { try {
const res = await fetch('/api/resos/custom-fields', { const res = await fetch('/kitchen/api/resos/custom-fields', {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (res.ok) { if (res.ok) {
@ -4463,7 +4463,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
try { try {
// First, sync opening hours to database (POST endpoint) // First, sync opening hours to database (POST endpoint)
const syncRes = await fetch('/api/resos/sync/opening-hours', { const syncRes = await fetch('/kitchen/api/resos/sync/opening-hours', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -4477,7 +4477,7 @@ export default function Settings() {
const syncData = await syncRes.json() const syncData = await syncRes.json()
// Then, fetch opening hours for display (GET endpoint) // Then, fetch opening hours for display (GET endpoint)
const res = await fetch('/api/resos/opening-hours', { const res = await fetch('/kitchen/api/resos/opening-hours', {
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
if (res.ok) { if (res.ok) {
@ -4787,7 +4787,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
try { try {
setResosSaveMessage('Syncing upcoming bookings...') setResosSaveMessage('Syncing upcoming bookings...')
const res = await fetch('/api/resos/sync/upcoming', { const res = await fetch('/kitchen/api/resos/sync/upcoming', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -4815,7 +4815,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
try { try {
setResosSaveMessage('Syncing forecast...') setResosSaveMessage('Syncing forecast...')
const res = await fetch('/api/resos/sync/forecast', { const res = await fetch('/kitchen/api/resos/sync/forecast', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -4855,7 +4855,7 @@ export default function Settings() {
<button <button
onClick={async () => { onClick={async () => {
try { try {
const res = await fetch('/api/resos/settings', { const res = await fetch('/kitchen/api/resos/settings', {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
@ -4937,7 +4937,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
try { try {
setResosSaveMessage('Syncing historical data...') setResosSaveMessage('Syncing historical data...')
const res = await fetch(`/api/resos/sync/historical?from_date=${historicalResosDateFrom}&to_date=${historicalResosDateTo}`, { const res = await fetch(`/kitchen/api/resos/sync/historical?from_date=${historicalResosDateFrom}&to_date=${historicalResosDateTo}`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -6405,7 +6405,7 @@ export default function Settings() {
<div style={styles.actionButtons}> <div style={styles.actionButtons}>
<button <button
onClick={() => { onClick={() => {
window.open(`/api/backup/${backup.id}/download?token=${token}`, '_blank') window.open(`/kitchen/api/backup/${backup.id}/download?token=${token}`, '_blank')
}} }}
style={styles.actionBtn} style={styles.actionBtn}
disabled={backup.status !== 'success'} disabled={backup.status !== 'success'}
@ -6464,7 +6464,7 @@ export default function Settings() {
setSeedingDefaults(true) setSeedingDefaults(true)
setFoodFlagMessage(null) setFoodFlagMessage(null)
try { try {
const res = await fetch('/api/food-flags/seed-defaults', { const res = await fetch('/kitchen/api/food-flags/seed-defaults', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -6891,7 +6891,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
setIngCatMessage(null) setIngCatMessage(null)
try { try {
const res = await fetch('/api/ingredients/categories/seed-defaults', { const res = await fetch('/kitchen/api/ingredients/categories/seed-defaults', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -7061,7 +7061,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
setRecipeSectionsMsg(null) setRecipeSectionsMsg(null)
try { try {
const res = await fetch('/api/recipes/menu-sections/seed-defaults?section_type=recipe', { const res = await fetch('/kitchen/api/recipes/menu-sections/seed-defaults?section_type=recipe', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -7108,7 +7108,7 @@ export default function Settings() {
<button <button
onClick={async () => { onClick={async () => {
if (confirm(`Delete "${sec.name}"?${sec.recipe_count > 0 ? ` ${sec.recipe_count} recipe(s) will become unsectioned.` : ''}`)) { if (confirm(`Delete "${sec.name}"?${sec.recipe_count > 0 ? ` ${sec.recipe_count} recipe(s) will become unsectioned.` : ''}`)) {
const res = await fetch(`/api/recipes/menu-sections/${sec.id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` } }) const res = await fetch(`/kitchen/api/recipes/menu-sections/${sec.id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` } })
if (res.ok) refetchRecipeSections() if (res.ok) refetchRecipeSections()
} }
}} }}
@ -7136,7 +7136,7 @@ export default function Settings() {
const input = e.currentTarget const input = e.currentTarget
const name = input.value.trim() const name = input.value.trim()
if (!name) return if (!name) return
const res = await fetch('/api/recipes/menu-sections', { const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, section_type: 'recipe', sort_order: recipeSections?.length || 0 }), body: JSON.stringify({ name, section_type: 'recipe', sort_order: recipeSections?.length || 0 }),
@ -7150,7 +7150,7 @@ export default function Settings() {
const input = document.getElementById('newRecipeSectionName') as HTMLInputElement const input = document.getElementById('newRecipeSectionName') as HTMLInputElement
const name = input?.value.trim() const name = input?.value.trim()
if (!name) return if (!name) return
const res = await fetch('/api/recipes/menu-sections', { const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, section_type: 'recipe', sort_order: recipeSections?.length || 0 }), body: JSON.stringify({ name, section_type: 'recipe', sort_order: recipeSections?.length || 0 }),
@ -7172,7 +7172,7 @@ export default function Settings() {
onClick={async () => { onClick={async () => {
setDishCoursesMsg(null) setDishCoursesMsg(null)
try { try {
const res = await fetch('/api/recipes/menu-sections/seed-defaults?section_type=dish', { const res = await fetch('/kitchen/api/recipes/menu-sections/seed-defaults?section_type=dish', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -7219,7 +7219,7 @@ export default function Settings() {
<button <button
onClick={async () => { onClick={async () => {
if (confirm(`Delete "${course.name}"?${course.recipe_count > 0 ? ` ${course.recipe_count} dish(es) will become uncategorised.` : ''}`)) { if (confirm(`Delete "${course.name}"?${course.recipe_count > 0 ? ` ${course.recipe_count} dish(es) will become uncategorised.` : ''}`)) {
const res = await fetch(`/api/recipes/menu-sections/${course.id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` } }) const res = await fetch(`/kitchen/api/recipes/menu-sections/${course.id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` } })
if (res.ok) refetchDishCourses() if (res.ok) refetchDishCourses()
} }
}} }}
@ -7247,7 +7247,7 @@ export default function Settings() {
const input = e.currentTarget const input = e.currentTarget
const name = input.value.trim() const name = input.value.trim()
if (!name) return if (!name) return
const res = await fetch('/api/recipes/menu-sections', { const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, section_type: 'dish', sort_order: dishCourses?.length || 0 }), body: JSON.stringify({ name, section_type: 'dish', sort_order: dishCourses?.length || 0 }),
@ -7261,7 +7261,7 @@ export default function Settings() {
const input = document.getElementById('newDishCourseName') as HTMLInputElement const input = document.getElementById('newDishCourseName') as HTMLInputElement
const name = input?.value.trim() const name = input?.value.trim()
if (!name) return if (!name) return
const res = await fetch('/api/recipes/menu-sections', { const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, section_type: 'dish', sort_order: dishCourses?.length || 0 }), body: JSON.stringify({ name, section_type: 'dish', sort_order: dishCourses?.length || 0 }),

View file

@ -135,7 +135,7 @@ export default function UploadApp() {
q.id === queueId ? { ...q, status: 'processing' as const } : q q.id === queueId ? { ...q, status: 'processing' as const } : q
)) ))
const res = await fetch('/api/invoices/upload', { const res = await fetch('/kitchen/api/invoices/upload', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
body: formData, body: formData,
@ -220,7 +220,7 @@ export default function UploadApp() {
const formData = new FormData() const formData = new FormData()
formData.append('file', pdfFile) formData.append('file', pdfFile)
const res = await fetch('/api/invoices/upload', { const res = await fetch('/kitchen/api/invoices/upload', {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
body: formData, body: formData,

View file

@ -119,7 +119,7 @@ export default function WastageLogbook() {
const { data: entries, isLoading } = useQuery<LogbookEntry[]>({ const { data: entries, isLoading } = useQuery<LogbookEntry[]>({
queryKey: ['logbook', typeFilter, dateFrom, dateTo], queryKey: ['logbook', typeFilter, dateFrom, dateTo],
queryFn: async () => { queryFn: async () => {
const url = queryString ? `/api/logbook?${queryString}` : '/api/logbook' const url = queryString ? `/kitchen/api/logbook?${queryString}` : '/kitchen/api/logbook'
const res = await fetch(url, { const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -138,7 +138,7 @@ export default function WastageLogbook() {
const { data: summary } = useQuery<LogbookSummary>({ const { data: summary } = useQuery<LogbookSummary>({
queryKey: ['logbook-summary', dateFrom, dateTo], queryKey: ['logbook-summary', dateFrom, dateTo],
queryFn: async () => { queryFn: async () => {
const url = summaryString ? `/api/logbook/summary?${summaryString}` : '/api/logbook/summary' const url = summaryString ? `/kitchen/api/logbook/summary?${summaryString}` : '/kitchen/api/logbook/summary'
const res = await fetch(url, { const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -150,7 +150,7 @@ export default function WastageLogbook() {
const deleteMutation = useMutation({ const deleteMutation = useMutation({
mutationFn: async (entryId: number) => { mutationFn: async (entryId: number) => {
const res = await fetch(`/api/logbook/${entryId}`, { const res = await fetch(`/kitchen/api/logbook/${entryId}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
@ -570,7 +570,7 @@ function CreateEntryModal({
return return
} }
try { try {
const res = await fetch(`/api/logbook/products/search?query=${encodeURIComponent(query)}`, { const res = await fetch(`/kitchen/api/logbook/products/search?query=${encodeURIComponent(query)}`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}) })
if (res.ok) { if (res.ok) {
@ -630,7 +630,7 @@ function CreateEntryModal({
setError(null) setError(null)
try { try {
let endpoint = '/api/logbook/' let endpoint = '/kitchen/api/logbook/'
let body: Record<string, unknown> = { let body: Record<string, unknown> = {
entry_date: entryDate, entry_date: entryDate,
notes: notes || undefined, notes: notes || undefined,