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'
// 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.
const api = axios.create({
baseURL: '/kitchen/api',

View file

@ -254,7 +254,7 @@ export default function AllowancesReport() {
const { data: summary, isLoading, error } = useQuery<AllowancesSummaryResponse>({
queryKey: ['allowances-summary', submittedFromDate, submittedToDate],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch allowances summary')
@ -268,7 +268,7 @@ export default function AllowancesReport() {
const { data: chartData } = useQuery<DailyAllowanceChartResponse>({
queryKey: ['allowances-daily', submittedFromDate, submittedToDate],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch chart data')
@ -282,7 +282,7 @@ export default function AllowancesReport() {
const { data: disputes } = useQuery<DisputesSummaryResponse>({
queryKey: ['disputes-period-summary', submittedFromDate, submittedToDate],
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}` },
})
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>({
queryKey: ['budget', 'weekly', weekOffset],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch budget data')
@ -267,7 +267,7 @@ export default function Budget() {
const { data: prevWeek1 } = useQuery<WeeklyBudgetResponse>({
queryKey: ['budget', 'weekly', weekOffset - 1],
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}` },
})
if (!res.ok) return null
@ -278,7 +278,7 @@ export default function Budget() {
const { data: prevWeek2 } = useQuery<WeeklyBudgetResponse>({
queryKey: ['budget', 'weekly', weekOffset - 2],
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}` },
})
if (!res.ok) return null
@ -298,7 +298,7 @@ export default function Budget() {
const { data: overrideData, refetch: refetchOverrides, isLoading: isOverrideLoading } = useQuery<WeeklyOverrideResponse>({
queryKey: ['cover-overrides', 'weekly', weekOffset],
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}` },
})
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],
queryFn: async () => {
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}` } }
)
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],
queryFn: async () => {
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}` } }
)
if (!res.ok) return {}
@ -347,7 +347,7 @@ export default function Budget() {
const snapshotMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/cover-overrides/snapshot', {
const res = await fetch('/kitchen/api/cover-overrides/snapshot', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ week_offset: weekOffset }),
@ -383,7 +383,7 @@ export default function Budget() {
try {
await Promise.all(Object.entries(pendingOverrides).map(([key, value]) => {
const [overrideDate, period] = key.split('|')
return fetch('/api/cover-overrides', {
return fetch('/kitchen/api/cover-overrides', {
method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ override_date: overrideDate, period, override_covers: value }),
@ -398,7 +398,7 @@ export default function Budget() {
}
const deleteOverride = async (id: number) => {
await fetch(`/api/cover-overrides/${id}`, {
await fetch(`/kitchen/api/cover-overrides/${id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` },
})
@ -407,7 +407,7 @@ export default function Budget() {
}
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
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[]>({
queryKey: ['ingredients-bulk'],
queryFn: async () => {
const res = await fetch('/api/ingredients?limit=9999', {
const res = await fetch('/kitchen/api/ingredients?limit=9999', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch ingredients')
@ -78,7 +78,7 @@ export default function BulkAllergens() {
const { data: categories } = useQuery<IngredientCategory[]>({
queryKey: ['ingredient-categories'],
queryFn: async () => {
const res = await fetch('/api/ingredients/categories', {
const res = await fetch('/kitchen/api/ingredients/categories', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) return []
@ -91,7 +91,7 @@ export default function BulkAllergens() {
const { data: flagCategories } = useQuery<FoodFlagCategoryItem[]>({
queryKey: ['food-flag-categories-full'],
queryFn: async () => {
const res = await fetch('/api/food-flags/categories', {
const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` },
})
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[]>>({
queryKey: ['bulk-nones'],
queryFn: async () => {
const res = await fetch('/api/ingredients/bulk-nones', {
const res = await fetch('/kitchen/api/ingredients/bulk-nones', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) return {}
@ -117,7 +117,7 @@ export default function BulkAllergens() {
const { data: allSuggestions } = useQuery<Record<number, AllergenSuggestion[]>>({
queryKey: ['bulk-suggestions'],
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}` },
})
if (!res.ok) return {}
@ -140,7 +140,7 @@ export default function BulkAllergens() {
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ food_flag_ids: newFlagIds }),
@ -156,7 +156,7 @@ export default function BulkAllergens() {
// Toggle None for a category on an ingredient
const toggleNoneMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
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[]>({
queryKey: ['dishes-for-bulk'],
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}` },
})
if (!res.ok) throw new Error('Failed')
@ -46,7 +46,7 @@ export default function BulkPublishModal({ menuId, divisionId, divisionName, onC
queryFn: async () => {
const results: Record<number, { ok: boolean; unassessed?: Array<{ name: string }> }> = {}
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}` },
})
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),
}
})
const res = await fetch(`/api/menus/${menuId}/items/bulk`, {
const res = await fetch(`/kitchen/api/menus/${menuId}/items/bulk`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({

View file

@ -123,7 +123,7 @@ export default function CostDistributionModal({ isOpen, onClose, onSaved, invoic
if (distributionId) {
// Load existing distribution
setLoading(true)
fetch(`/api/cost-distributions/${distributionId}`, {
fetch(`/kitchen/api/cost-distributions/${distributionId}`, {
headers: { Authorization: `Bearer ${token}` },
})
.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) {
// Load invoice availability
setLoading(true)
fetch(`/api/cost-distributions/invoice/${invoiceId}/availability`, {
fetch(`/kitchen/api/cost-distributions/invoice/${invoiceId}/availability`, {
headers: { Authorization: `Bearer ${token}` },
})
.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
}
const res = await fetch('/api/cost-distributions/', {
const res = await fetch('/kitchen/api/cost-distributions/', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body),
@ -300,7 +300,7 @@ export default function CostDistributionModal({ isOpen, onClose, onSaved, invoic
if (!token || !distributionId) return
setSaving(true)
try {
const res = await fetch(`/api/cost-distributions/${distributionId}`, {
const res = await fetch(`/kitchen/api/cost-distributions/${distributionId}`, {
method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
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
setDeleting(true)
try {
const res = await fetch(`/api/cost-distributions/${distributionId}`, {
const res = await fetch(`/kitchen/api/cost-distributions/${distributionId}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` },
})
@ -343,7 +343,7 @@ export default function CostDistributionModal({ isOpen, onClose, onSaved, invoic
try {
const body: any = { entry_date: settleDate }
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body),

View file

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

View file

@ -136,7 +136,7 @@ export default function Dashboard() {
const { data: resosSettings } = useQuery<ResosSettings>({
queryKey: ['resos-settings'],
queryFn: async () => {
const res = await fetch('/api/resos/settings', {
const res = await fetch('/kitchen/api/resos/settings', {
headers: { Authorization: `Bearer ${token}` },
})
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>({
queryKey: ['dashboard'],
queryFn: async () => {
const res = await fetch('/api/reports/dashboard', {
const res = await fetch('/kitchen/api/reports/dashboard', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch dashboard')
@ -159,7 +159,7 @@ export default function Dashboard() {
const { data: resosCovers } = useQuery<ResosCoversData>({
queryKey: ['resos-dashboard-covers'],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch Resos covers')
@ -172,7 +172,7 @@ export default function Dashboard() {
const { data: arrivalStats } = useQuery<ArrivalDashboardData>({
queryKey: ['newbook-arrival-stats'],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch arrival stats')
@ -193,7 +193,7 @@ export default function Dashboard() {
}>({
queryKey: ['upcoming-events'],
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}` }
})
if (!res.ok) throw new Error('Failed to fetch upcoming events')
@ -217,7 +217,7 @@ export default function Dashboard() {
}>({
queryKey: ['recipe-dashboard-stats'],
queryFn: async () => {
const res = await fetch('/api/recipes/dashboard-stats', {
const res = await fetch('/kitchen/api/recipes/dashboard-stats', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch recipe stats')
@ -230,7 +230,7 @@ export default function Dashboard() {
const { data: disputeStats } = useQuery<DisputeStats>({
queryKey: ['dispute-stats'],
queryFn: async () => {
const res = await fetch('/api/disputes/stats/summary', {
const res = await fetch('/kitchen/api/disputes/stats/summary', {
headers: { Authorization: `Bearer ${token}` }
})
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>({
queryKey: ['recipe', recipeId],
queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}`, {
const res = await fetch(`/kitchen/api/recipes/${recipeId}`, {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Not found')
@ -301,7 +301,7 @@ export default function DishEditor() {
const { data: sections } = useQuery<MenuSection[]>({
queryKey: ['dish-courses'],
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}` },
})
return res.json()
@ -313,7 +313,7 @@ export default function DishEditor() {
const { data: costData } = useQuery<CostData>({
queryKey: ['recipe-cost', recipeId],
queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/costing`, {
const res = await fetch(`/kitchen/api/recipes/${recipeId}/costing`, {
headers: { Authorization: `Bearer ${token}` },
})
return res.json()
@ -325,7 +325,7 @@ export default function DishEditor() {
const { data: scaledCostData } = useQuery<CostData>({
queryKey: ['recipe-cost-scaled', recipeId, scalePortions],
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}` },
})
return res.json()
@ -337,7 +337,7 @@ export default function DishEditor() {
const { data: flagData } = useQuery<FlagState>({
queryKey: ['recipe-flags', recipeId],
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}` },
})
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 }>>({
queryKey: ['food-flag-categories'],
queryFn: async () => {
const res = await fetch('/api/food-flags/categories', {
const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` },
})
return res.json()
@ -361,7 +361,7 @@ export default function DishEditor() {
const { data: changeLog } = useQuery<ChangeLogEntry[]>({
queryKey: ['recipe-changelog', recipeId],
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}` },
})
return res.json()
@ -373,7 +373,7 @@ export default function DishEditor() {
const { data: costTrendRaw } = useQuery<CostTrendResponse>({
queryKey: ['recipe-cost-trend', recipeId],
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}` },
})
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 }>>({
queryKey: ['dish-menus', recipeId],
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}` },
})
if (!res.ok) return []
@ -399,7 +399,7 @@ export default function DishEditor() {
const { data: editIngData } = useQuery<EditingIngredient>({
queryKey: ['ingredient-edit', editIngId],
queryFn: async () => {
const res = await fetch(`/api/ingredients/${editIngId}`, {
const res = await fetch(`/kitchen/api/ingredients/${editIngId}`, {
headers: { Authorization: `Bearer ${token}` },
})
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 }>>({
queryKey: ['recipes-list-for-sub'],
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}` },
})
return res.json()
@ -438,7 +438,7 @@ export default function DishEditor() {
const { data: sambaposItems } = useQuery<SambaposMenuItem[]>({
queryKey: ['sambapos-menu-items-portions'],
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}` },
})
if (!res.ok) return []
@ -467,7 +467,7 @@ export default function DishEditor() {
if (!ingSearch || ingSearch.length < 2 || !token) return
const timer = setTimeout(async () => {
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}` },
})
if (res.ok) {
@ -484,7 +484,7 @@ export default function DishEditor() {
// Mutations
const updateMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch(`/api/recipes/${recipeId}`, {
const res = await fetch(`/kitchen/api/recipes/${recipeId}`, {
method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -502,7 +502,7 @@ export default function DishEditor() {
const addIngMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -527,7 +527,7 @@ export default function DishEditor() {
const updateIngMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ quantity, unit, yield_percent, notes }),
@ -545,7 +545,7 @@ export default function DishEditor() {
const removeIngMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -562,7 +562,7 @@ export default function DishEditor() {
const addSubMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -583,7 +583,7 @@ export default function DishEditor() {
const removeSubMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -599,7 +599,7 @@ export default function DishEditor() {
const addStepMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -617,7 +617,7 @@ export default function DishEditor() {
const updateStepMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -636,7 +636,7 @@ export default function DishEditor() {
const removeStepMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -652,7 +652,7 @@ export default function DishEditor() {
formData.append('file', file)
formData.append('caption', caption)
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',
headers: { Authorization: `Bearer ${token}` },
body: formData,
@ -670,7 +670,7 @@ export default function DishEditor() {
// Delete image mutation
const deleteImageMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -684,7 +684,7 @@ export default function DishEditor() {
// Batch reorder ingredients
const reorderIngMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ingredient_ids: ingredientIds }),
@ -699,7 +699,7 @@ export default function DishEditor() {
// Batch reorder sub-recipes
const reorderSubMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ sub_recipe_ids: subRecipeIds }),
@ -714,7 +714,7 @@ export default function DishEditor() {
// Reorder steps mutation
const reorderStepsMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ step_ids: stepIds }),
@ -799,7 +799,7 @@ export default function DishEditor() {
}
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>
@ -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' }}
onClick={async () => {
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
@ -1345,10 +1345,10 @@ export default function DishEditor() {
{recipe.images.map(img => (
<div key={img.id} style={styles.imageCard}>
<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'}
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' }}>
{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[]>({
queryKey: ['dish-courses'],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch sections')
@ -137,7 +137,7 @@ export default function DishList() {
params.set('recipe_type', 'dish')
if (sectionFilter) params.set('menu_section_id', sectionFilter)
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}` },
})
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[] }>({
queryKey: ['price-impact-dishes', costChangeDays],
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}` },
})
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[] }>({
queryKey: ['cost-trend', expandedCostId],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch cost trend')
@ -178,7 +178,7 @@ export default function DishList() {
const createMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/recipes', {
const res = await fetch('/kitchen/api/recipes', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -195,7 +195,7 @@ export default function DishList() {
const duplicateMutation = useMutation({
mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/${id}/duplicate`, {
const res = await fetch(`/kitchen/api/recipes/${id}/duplicate`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -210,7 +210,7 @@ export default function DishList() {
const archiveMutation = useMutation({
mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/${id}`, {
const res = await fetch(`/kitchen/api/recipes/${id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` },
})
@ -221,7 +221,7 @@ export default function DishList() {
const unarchiveMutation = useMutation({
mutationFn: async (id: number) => {
const res = await fetch(`/api/recipes/${id}`, {
const res = await fetch(`/kitchen/api/recipes/${id}`, {
method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ is_archived: false }),
@ -233,7 +233,7 @@ export default function DishList() {
const createSectionMutation = useMutation({
mutationFn: async (name: string) => {
const res = await fetch('/api/recipes/menu-sections', {
const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, section_type: 'dish' }),
@ -250,7 +250,7 @@ export default function DishList() {
const updateSectionMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name }),
@ -268,7 +268,7 @@ export default function DishList() {
const deleteSectionMutation = useMutation({
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',
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 }> }>>({
queryKey: ['food-flag-categories'],
queryFn: async () => {
const res = await fetch('/api/food-flags/categories', {
const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` },
})
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 }>({
queryKey: ['settings'],
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 {}
return res.json()
},
@ -136,7 +136,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
const { data: dispute, isLoading, error } = useQuery<DisputeDetail>({
queryKey: ['dispute', disputeId],
queryFn: async () => {
const res = await fetch(`/api/disputes/${disputeId}`, {
const res = await fetch(`/kitchen/api/disputes/${disputeId}`, {
headers: { Authorization: `Bearer ${token}` },
})
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({
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',
headers: {
'Content-Type': 'application/json',
@ -172,7 +172,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
const deleteMutation = useMutation({
mutationFn: async () => {
const res = await fetch(`/api/disputes/${disputeId}`, {
const res = await fetch(`/kitchen/api/disputes/${disputeId}`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${token}`,
@ -251,7 +251,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
setAiEmailSubject('')
setAiEmailBody('')
try {
const res = await fetch(`/api/disputes/${disputeId}/draft-email`, {
const res = await fetch(`/kitchen/api/disputes/${disputeId}/draft-email`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -290,7 +290,7 @@ export default function DisputeDetailModal({ disputeId, onClose, onUpdate }: Dis
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',
headers: {
Authorization: `Bearer ${token}`,

View file

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

View file

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

View file

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

View file

@ -317,7 +317,7 @@ export default function GPReport() {
const { data, isLoading, error } = useQuery<DateRangeGPResponse>({
queryKey: ['gp-range', submittedFromDate, submittedToDate],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch GP data')
@ -331,7 +331,7 @@ export default function GPReport() {
const { data: chartData } = useQuery<DailyChartData>({
queryKey: ['gp-daily', submittedFromDate, submittedToDate],
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}` },
})
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>({
queryKey: ['gp-top-sellers', submittedFromDate, submittedToDate],
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}` },
})
if (!res.ok) {

View file

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

View file

@ -30,11 +30,11 @@ const SUPPLIER_LOOKUPS: SupplierLookup[] = [
namePattern: /brakes/i,
label: 'Fetch Brakes',
color: '#f59e0b',
endpoint: '/api/food-flags/brakes-lookup',
endpoint: '/kitchen/api/food-flags/brakes-lookup',
paramName: 'product_code',
},
// 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 {
@ -165,7 +165,7 @@ export default function IngredientModal({
const { data: categories } = useQuery<IngredientCategory[]>({
queryKey: ['ingredient-categories'],
queryFn: async () => {
const res = await fetch('/api/ingredients/categories', {
const res = await fetch('/kitchen/api/ingredients/categories', {
headers: { Authorization: `Bearer ${token}` },
})
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 }>>({
queryKey: ['suppliers'],
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 []
const data = await res.json()
return data.suppliers || data || []
@ -199,7 +199,7 @@ export default function IngredientModal({
}>>({
queryKey: ['ingredient-sources', editingIngredient?.id],
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}` },
})
if (!res.ok) return []
@ -216,7 +216,7 @@ export default function IngredientModal({
if (debouncedLiSearch) params.set('q', debouncedLiSearch)
if (liSupplierId) params.set('supplier_id', liSupplierId)
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}` },
})
if (!res.ok) return { items: [], total_count: 0 }
@ -230,7 +230,7 @@ export default function IngredientModal({
const { data: settingsData } = useQuery<{ llm_enabled: boolean }>({
queryKey: ['settings-llm-check'],
queryFn: async () => {
const res = await fetch('/api/settings/', {
const res = await fetch('/kitchen/api/settings/', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) return { llm_enabled: false }
@ -252,7 +252,7 @@ export default function IngredientModal({
const runAnalysis = async () => {
setLlmAnalysing(true)
try {
const res = await fetch('/api/food-flags/analyse-label', {
const res = await fetch('/kitchen/api/food-flags/analyse-label', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
@ -294,7 +294,7 @@ export default function IngredientModal({
const fetchYield = async () => {
setYieldHintLoading(true)
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}` },
})
if (res.ok && !cancelled) {
@ -434,8 +434,8 @@ export default function IngredientModal({
reader.onload = (e) => setLabelPreview(e.target?.result as string)
reader.readAsDataURL(file)
const url = editingIngredient
? `/api/food-flags/scan-label/${editingIngredient.id}`
: '/api/food-flags/scan-label'
? `/kitchen/api/food-flags/scan-label/${editingIngredient.id}`
: '/kitchen/api/food-flags/scan-label'
const res = await fetch(url, {
method: 'POST',
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_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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(sourceData),
@ -484,7 +484,7 @@ export default function IngredientModal({
const applyPendingFlags = async (ingredientId: number) => {
if (pendingFlagIds.length > 0) {
try {
await fetch(`/api/ingredients/${ingredientId}/flags`, {
await fetch(`/kitchen/api/ingredients/${ingredientId}/flags`, {
method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ food_flag_ids: pendingFlagIds }),
@ -493,7 +493,7 @@ export default function IngredientModal({
}
for (const catId of pendingNoneCatIds) {
try {
await fetch(`/api/ingredients/${ingredientId}/flags/none`, {
await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/none`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ category_id: catId }),
@ -503,7 +503,7 @@ export default function IngredientModal({
// Batch persist dismissals from create mode
if (pendingDismissals.length > 0) {
try {
await fetch(`/api/ingredients/${ingredientId}/flags/dismissals/batch`, {
await fetch(`/kitchen/api/ingredients/${ingredientId}/flags/dismissals/batch`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ dismissals: pendingDismissals }),
@ -529,7 +529,7 @@ export default function IngredientModal({
setFormFree(editingIngredient.is_free || false)
setFormPrepackaged(editingIngredient.is_prepackaged || false)
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)
} else {
const name = prePopulateName || ''
@ -550,7 +550,7 @@ export default function IngredientModal({
} else if (preSelectLineItem.description) {
// LLM FEATURE — AI pack size deduction when regex can't parse
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}` },
}).then(res => res.ok ? res.json() : null).then(data => {
if (data?.pack_quantity && data?.unit_size) {
@ -589,7 +589,7 @@ export default function IngredientModal({
}
const timer = setTimeout(async () => {
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}` },
})
if (res.ok) {
@ -605,7 +605,7 @@ export default function IngredientModal({
const createMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/ingredients', {
const res = await fetch('/kitchen/api/ingredients', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -628,7 +628,7 @@ export default function IngredientModal({
const updateMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -988,7 +988,7 @@ export default function IngredientModal({
title="Click to enlarge"
>
<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"
style={{ width: '100%', height: 'auto', display: 'block' }}
onError={(e) => { (e.target as HTMLImageElement).parentElement!.style.display = 'none' }}
@ -1058,7 +1058,7 @@ export default function IngredientModal({
{selectedLi.most_recent_line_number != null && (
<div style={{ flex: '0 0 auto', maxWidth: '120px', borderRadius: '4px', overflow: 'hidden', border: '1px solid #e0e0e0' }}>
<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"
style={{ width: '100%', height: 'auto', display: 'block' }}
onError={(e) => { (e.target as HTMLImageElement).parentElement!.style.display = 'none' }}
@ -1246,7 +1246,7 @@ export default function IngredientModal({
{'\u2715'}
</button>
<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"
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[]>({
queryKey: ['ingredient-categories'],
queryFn: async () => {
const res = await fetch('/api/ingredients/categories', {
const res = await fetch('/kitchen/api/ingredients/categories', {
headers: { Authorization: `Bearer ${token}` },
})
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 (showUnmapped) params.set('unmapped', '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}` },
})
if (!res.ok) throw new Error('Failed to fetch ingredients')
@ -97,7 +97,7 @@ export default function Ingredients() {
const { data: sources } = useQuery<SourceItem[]>({
queryKey: ['ingredient-sources', expandedId],
queryFn: async () => {
const res = await fetch(`/api/ingredients/${expandedId}/sources`, {
const res = await fetch(`/kitchen/api/ingredients/${expandedId}/sources`, {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch sources')
@ -108,7 +108,7 @@ export default function Ingredients() {
const archiveMutation = useMutation({
mutationFn: async (id: number) => {
const res = await fetch(`/api/ingredients/${id}`, {
const res = await fetch(`/kitchen/api/ingredients/${id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` },
})
@ -119,7 +119,7 @@ export default function Ingredients() {
const unarchiveMutation = useMutation({
mutationFn: async (id: number) => {
const res = await fetch(`/api/ingredients/${id}`, {
const res = await fetch(`/kitchen/api/ingredients/${id}`, {
method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ is_archived: false }),

View file

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

View file

@ -64,7 +64,7 @@ export default function LinkDisputeModal({
const { data: disputes, isLoading } = useQuery<OpenDispute[]>({
queryKey: ['open-disputes', supplierId],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch disputes')
@ -78,7 +78,7 @@ export default function LinkDisputeModal({
mutationFn: async () => {
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',
headers: {
'Content-Type': 'application/json',

View file

@ -95,7 +95,7 @@ export default function MapLineItemsModal({ ingredient, onClose, onSaved }: MapL
const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'],
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 []
const data = await res.json()
return data.suppliers || data || []
@ -112,7 +112,7 @@ export default function MapLineItemsModal({ ingredient, onClose, onSaved }: MapL
params.set('date_from', dateFrom)
params.set('date_to', dateTo)
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}` },
})
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
}
const res = await fetch(`/api/ingredients/${ingredient.id}/sources`, {
const res = await fetch(`/kitchen/api/ingredients/${ingredient.id}/sources`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(sourceData),
@ -233,7 +233,7 @@ export default function MapLineItemsModal({ ingredient, onClose, onSaved }: MapL
// Preview URL for the selected line item
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
return (

View file

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

View file

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

View file

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

View file

@ -48,7 +48,7 @@ export default function PriceImpact() {
const { data, isLoading } = useQuery<ImpactData>({
queryKey: ['price-impact', days],
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}` },
})
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 }>({
queryKey: ['settings'],
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 }
return res.json()
},
@ -70,7 +70,7 @@ export default function PublishToMenuModal({
if (!recipeIdToUse) return
setAiDescLoading(true)
try {
const res = await fetch('/api/menus/generate-description', {
const res = await fetch('/kitchen/api/menus/generate-description', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
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 }>>({
queryKey: ['dishes-for-menu'],
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}` },
})
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 }>>({
queryKey: ['menus-for-publish'],
queryFn: async () => {
const res = await fetch('/api/menus', {
const res = await fetch('/kitchen/api/menus', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch menus')
@ -113,7 +113,7 @@ export default function PublishToMenuModal({
const { data: menuDetail } = useQuery<{ divisions: Division[] }>({
queryKey: ['menu-divisions', selectedMenuId],
queryFn: async () => {
const res = await fetch(`/api/menus/${selectedMenuId}`, {
const res = await fetch(`/kitchen/api/menus/${selectedMenuId}`, {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed')
@ -129,7 +129,7 @@ export default function PublishToMenuModal({
}>({
queryKey: ['recipe-flags-for-publish', selectedRecipeId],
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}` },
})
if (!res.ok) throw new Error('Failed')
@ -158,7 +158,7 @@ export default function PublishToMenuModal({
const publishMutation = useMutation({
mutationFn: async () => {
const res = await fetch(`/api/menus/${selectedMenuId}/items`, {
const res = await fetch(`/kitchen/api/menus/${selectedMenuId}/items`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({

View file

@ -35,7 +35,7 @@ export default function PurchaseOrderList() {
const { data: suppliersData } = useQuery<{ suppliers: Array<{ id: number; name: string }> }>({
queryKey: ['suppliers'],
queryFn: async () => {
const res = await fetch('/api/suppliers/', {
const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch suppliers')
@ -52,7 +52,7 @@ export default function PurchaseOrderList() {
const { data: poList, refetch } = useQuery<PurchaseOrderSummary[]>({
queryKey: ['purchase-orders', statusFilter, supplierFilter],
queryFn: async () => {
const res = await fetch(`/api/purchase-orders/?${params}`, {
const res = await fetch(`/kitchen/api/purchase-orders/?${params}`, {
headers: { Authorization: `Bearer ${token}` },
})
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)
useEffect(() => {
if (!token) return
fetch('/api/suppliers/', { headers: { Authorization: `Bearer ${token}` } })
fetch('/kitchen/api/suppliers/', { headers: { Authorization: `Bearer ${token}` } })
.then(r => r.json())
.then(data => setSuppliers(data.suppliers || data || []))
.catch(() => {})
@ -73,7 +73,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
// Check if SMTP is configured (for email button visibility)
useEffect(() => {
if (!token) return
fetch('/api/settings/', { headers: { Authorization: `Bearer ${token}` } })
fetch('/kitchen/api/settings/', { headers: { Authorization: `Bearer ${token}` } })
.then(r => r.json())
.then(data => setSmtpConfigured(!!(data.smtp_host && data.smtp_from_email)))
.catch(() => setSmtpConfigured(false))
@ -83,7 +83,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
useEffect(() => {
if (!poId || !token) return
setLoading(true)
fetch(`/api/purchase-orders/${poId}`, { headers: { Authorization: `Bearer ${token}` } })
fetch(`/kitchen/api/purchase-orders/${poId}`, { headers: { Authorization: `Bearer ${token}` } })
.then(r => {
if (!r.ok) throw new Error('Failed to load')
return r.json()
@ -144,7 +144,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
searchTimeout.current = setTimeout(() => {
const params = new URLSearchParams({ query: searchQuery })
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}` },
})
.then(r => r.json())
@ -243,7 +243,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
}
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 res = await fetch(url, {
method,
@ -269,7 +269,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
const form = new FormData()
form.append('file', file)
try {
const res = await fetch(`/api/purchase-orders/${poId}/attachment`, {
const res = await fetch(`/kitchen/api/purchase-orders/${poId}/attachment`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: form,
@ -285,7 +285,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
const handleRemoveAttachment = async () => {
if (!poId || !token) return
try {
await fetch(`/api/purchase-orders/${poId}/attachment`, {
await fetch(`/kitchen/api/purchase-orders/${poId}/attachment`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` },
})
@ -299,7 +299,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
if (!poId || !token) return
if (!confirm('Delete this purchase order?')) return
try {
const res = await fetch(`/api/purchase-orders/${poId}`, {
const res = await fetch(`/kitchen/api/purchase-orders/${poId}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` },
})
@ -346,14 +346,14 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
...(orderType === 'single_value' ? { total_amount: totalAmount } : {}),
}
try {
const res = await fetch('/api/purchase-orders/', {
const res = await fetch('/kitchen/api/purchase-orders/', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body),
})
if (!res.ok) throw new Error('Failed to save')
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()
onClose()
} catch (e: any) {
@ -364,7 +364,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
} else {
// Existing PO — save current state then preview
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 {
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 saveRes = await fetch(url, {
method,
@ -411,7 +411,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
const savedPo = await saveRes.json()
// 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',
headers: { Authorization: `Bearer ${token}` },
})
@ -712,7 +712,7 @@ export default function PurchaseOrderModal({ isOpen, onClose, onSaved, poId, def
</>
)}
{!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
</button>
)}

View file

@ -281,7 +281,7 @@ export default function Purchases() {
const { data, isLoading, error } = useQuery<DateRangePurchasesResponse>({
queryKey: ['purchases-range', submittedFromDate, submittedToDate],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch purchases')
@ -293,7 +293,7 @@ export default function Purchases() {
const { data: disputeStats } = useQuery<DailyDisputeStats>({
queryKey: ['daily-dispute-stats', submittedFromDate, submittedToDate],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch dispute stats')
@ -305,7 +305,7 @@ export default function Purchases() {
const { data: allowanceStats } = useQuery<DailyLogbookStats>({
queryKey: ['daily-allowance-stats', submittedFromDate, submittedToDate],
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}` },
})
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>({
queryKey: ['weekly-chart-data', weeklyChartDateRange.from, weeklyChartDateRange.to],
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}` },
})
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>({
queryKey: ['purchases-summary', submittedFromDate, submittedToDate],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch purchases summary')
@ -284,7 +284,7 @@ export default function PurchasesReport() {
const { data: chartData } = useQuery<DailySupplierChartResponse>({
queryKey: ['purchases-daily-supplier', submittedFromDate, submittedToDate],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch chart data')
@ -298,7 +298,7 @@ export default function PurchasesReport() {
const { data: topItems } = useQuery<TopItemsResponse>({
queryKey: ['purchases-top-items', submittedFromDate, submittedToDate, topItemsSupplierFilter],
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) {
url += `&supplier_id=${topItemsSupplierFilter}`
}

View file

@ -284,7 +284,7 @@ export default function RecipeEditor() {
const { data: recipe } = useQuery<RecipeDetail>({
queryKey: ['recipe', recipeId],
queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}`, {
const res = await fetch(`/kitchen/api/recipes/${recipeId}`, {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Not found')
@ -297,7 +297,7 @@ export default function RecipeEditor() {
const { data: sections } = useQuery<MenuSection[]>({
queryKey: ['recipe-sections'],
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}` },
})
return res.json()
@ -309,7 +309,7 @@ export default function RecipeEditor() {
const { data: costData } = useQuery<CostData>({
queryKey: ['recipe-cost', recipeId],
queryFn: async () => {
const res = await fetch(`/api/recipes/${recipeId}/costing`, {
const res = await fetch(`/kitchen/api/recipes/${recipeId}/costing`, {
headers: { Authorization: `Bearer ${token}` },
})
return res.json()
@ -321,7 +321,7 @@ export default function RecipeEditor() {
const { data: scaledCostData } = useQuery<CostData>({
queryKey: ['recipe-cost-scaled', recipeId, scalePortions],
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}` },
})
return res.json()
@ -333,7 +333,7 @@ export default function RecipeEditor() {
const { data: flagData } = useQuery<FlagState>({
queryKey: ['recipe-flags', recipeId],
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}` },
})
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 }>>({
queryKey: ['food-flag-categories'],
queryFn: async () => {
const res = await fetch('/api/food-flags/categories', {
const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` },
})
return res.json()
@ -357,7 +357,7 @@ export default function RecipeEditor() {
const { data: changeLog } = useQuery<ChangeLogEntry[]>({
queryKey: ['recipe-changelog', recipeId],
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}` },
})
return res.json()
@ -369,7 +369,7 @@ export default function RecipeEditor() {
const { data: costTrendRaw } = useQuery<CostTrendResponse>({
queryKey: ['recipe-cost-trend', recipeId],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch cost trend')
@ -382,7 +382,7 @@ export default function RecipeEditor() {
const { data: editIngData } = useQuery<EditingIngredient>({
queryKey: ['ingredient-edit', editIngId],
queryFn: async () => {
const res = await fetch(`/api/ingredients/${editIngId}`, {
const res = await fetch(`/kitchen/api/ingredients/${editIngId}`, {
headers: { Authorization: `Bearer ${token}` },
})
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 }>>({
queryKey: ['recipes-list-for-sub'],
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}` },
})
return res.json()
@ -438,7 +438,7 @@ export default function RecipeEditor() {
if (!ingSearch || ingSearch.length < 2 || !token) return
const timer = setTimeout(async () => {
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}` },
})
if (res.ok) {
@ -455,7 +455,7 @@ export default function RecipeEditor() {
// Mutations
const updateMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch(`/api/recipes/${recipeId}`, {
const res = await fetch(`/kitchen/api/recipes/${recipeId}`, {
method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -473,7 +473,7 @@ export default function RecipeEditor() {
const addIngMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -498,7 +498,7 @@ export default function RecipeEditor() {
const updateIngMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ quantity, unit, yield_percent, notes }),
@ -516,7 +516,7 @@ export default function RecipeEditor() {
const removeIngMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -533,7 +533,7 @@ export default function RecipeEditor() {
const addSubMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -554,7 +554,7 @@ export default function RecipeEditor() {
const removeSubMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -570,7 +570,7 @@ export default function RecipeEditor() {
const addStepMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -588,7 +588,7 @@ export default function RecipeEditor() {
const updateStepMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -607,7 +607,7 @@ export default function RecipeEditor() {
const removeStepMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -623,7 +623,7 @@ export default function RecipeEditor() {
formData.append('file', file)
formData.append('caption', caption)
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',
headers: { Authorization: `Bearer ${token}` },
body: formData,
@ -641,7 +641,7 @@ export default function RecipeEditor() {
// Delete image mutation
const deleteImageMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -655,7 +655,7 @@ export default function RecipeEditor() {
// Batch reorder ingredients
const reorderIngMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ingredient_ids: ingredientIds }),
@ -670,7 +670,7 @@ export default function RecipeEditor() {
// Batch reorder sub-recipes
const reorderSubMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ sub_recipe_ids: subRecipeIds }),
@ -685,7 +685,7 @@ export default function RecipeEditor() {
// Reorder steps mutation
const reorderStepsMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ step_ids: stepIds }),
@ -769,7 +769,7 @@ export default function RecipeEditor() {
}
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>
@ -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' }}
onClick={async () => {
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
@ -1309,10 +1309,10 @@ export default function RecipeEditor() {
{recipe.images.map(img => (
<div key={img.id} style={styles.imageCard}>
<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'}
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' }}>
{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>({
queryKey: ['recipe-flag-matrix', recipeId],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch matrix')
@ -62,7 +62,7 @@ export default function RecipeFlagMatrix({ recipeId, categoryId }: Props) {
const toggleMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
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({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ ingredient_id: ingredientId, category_id: catId }),

View file

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

View file

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

View file

@ -75,7 +75,7 @@ export default function SalesGPReport() {
const { data: report, isLoading, error } = useQuery<SalesGPResponse>({
queryKey: ['sales-gp', submittedFrom, submittedTo],
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}` },
})
if (!res.ok) {
@ -91,7 +91,7 @@ export default function SalesGPReport() {
const { data: dishRecipes } = useQuery<DishRecipe[]>({
queryKey: ['recipes-for-mapping', recipeSearch],
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}` } })
return res.json()
},
@ -101,7 +101,7 @@ export default function SalesGPReport() {
// Map unmapped item to recipe
const mapMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({

View file

@ -104,7 +104,7 @@ export default function SearchDefinitions() {
const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'],
queryFn: async () => {
const res = await fetch('/api/suppliers/', {
const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` },
})
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')
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}` },
})
if (!res.ok) throw new Error('Search failed')
@ -136,7 +136,7 @@ export default function SearchDefinitions() {
const { data: lineItems } = useQuery<LineItem[]>({
queryKey: ['invoice-line-items', editingDef?.source_invoice_id],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch line items')
@ -149,7 +149,7 @@ export default function SearchDefinitions() {
const { data: ocrData } = useQuery<OcrData>({
queryKey: ['invoice-ocr-data', editingDef?.source_invoice_id],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch OCR data')
@ -161,7 +161,7 @@ export default function SearchDefinitions() {
// Update definition mutation
const updateMutation = useMutation({
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',
headers: {
Authorization: `Bearer ${token}`,
@ -191,7 +191,7 @@ export default function SearchDefinitions() {
return
}
const url = `/api/invoices/${editingDef.source_invoice_id}/image`
const url = `/kitchen/api/invoices/${editingDef.source_invoice_id}/image`
setInvoiceImageUrl(url)
// Check if PDF by fetching headers

View file

@ -72,7 +72,7 @@ export default function SearchInvoices() {
const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'],
queryFn: async () => {
const res = await fetch('/api/suppliers/', {
const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` },
})
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)
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}` },
})
if (!res.ok) throw new Error('Search failed')

View file

@ -144,7 +144,7 @@ export default function SearchLineItems() {
const { data: suppliers } = useQuery<Supplier[]>({
queryKey: ['suppliers'],
queryFn: async () => {
const res = await fetch('/api/suppliers/', {
const res = await fetch('/kitchen/api/suppliers/', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch suppliers')
@ -156,7 +156,7 @@ export default function SearchLineItems() {
const { data: _searchSettings } = useQuery<SearchSettings>({
queryKey: ['search-settings'],
queryFn: async () => {
const res = await fetch('/api/search/settings', {
const res = await fetch('/kitchen/api/search/settings', {
headers: { Authorization: `Bearer ${token}` },
})
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)
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}` },
})
if (!res.ok) throw new Error('Search failed')
@ -205,7 +205,7 @@ export default function SearchLineItems() {
const allSuggestions: typeof aliasSuggestions = {}
const promises = Array.from(bySupplier.entries()).map(([sid, items]) =>
fetch('/api/ingredients/sources/alias-suggestions', {
fetch('/kitchen/api/ingredients/sources/alias-suggestions', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ supplier_id: sid, items }),
@ -223,7 +223,7 @@ export default function SearchLineItems() {
const addDescriptionAliasMutation = useMutation({
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',
headers: {
Authorization: `Bearer ${token}`,
@ -300,7 +300,7 @@ export default function SearchLineItems() {
}
setIngredientSearchLoading(true)
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}` },
})
if (res.ok) setIngredientSuggestions(await res.json())
@ -371,7 +371,7 @@ export default function SearchLineItems() {
try {
// 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) {
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
@ -399,7 +399,7 @@ export default function SearchLineItems() {
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
await fetch(`/api/ingredients/${selectedIngredientId}/sources`, {
await fetch(`/kitchen/api/ingredients/${selectedIngredientId}/sources`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(sourceData),

View file

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

View file

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

View file

@ -159,7 +159,7 @@ export default function Upload() {
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',
headers: { Authorization: `Bearer ${token}` },
body: formData,

View file

@ -107,7 +107,7 @@ export default function UsageVarianceReport() {
setError(null)
try {
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}` } }
)
if (!res.ok) {

View file

@ -151,7 +151,7 @@ export default function BookingsStats() {
const { data: stats, isLoading } = useQuery<StatsData>({
queryKey: ['resos-stats', submittedFromDate, submittedToDate],
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}` }
})
if (!res.ok) throw new Error('Failed to fetch stats')
@ -182,7 +182,7 @@ export default function BookingsStats() {
queryKey: ['resos-stats-previous', submittedFromDate, submittedToDate],
queryFn: async () => {
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}` }
})
if (!res.ok) throw new Error('Failed to fetch previous stats')
@ -195,7 +195,7 @@ export default function BookingsStats() {
const { data: selectedDayBookings } = useQuery<Booking[]>({
queryKey: ['resos-bookings', selectedDate],
queryFn: async () => {
const res = await fetch(`/api/resos/bookings/${selectedDate}`, {
const res = await fetch(`/kitchen/api/resos/bookings/${selectedDate}`, {
headers: { Authorization: `Bearer ${token}` }
})
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>({
queryKey: ['settings'],
queryFn: async () => {
const res = await fetch('/api/settings/', {
const res = await fetch('/kitchen/api/settings/', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch settings')
@ -65,7 +65,7 @@ export default function NewbookData() {
const { data: calendarData, isLoading } = useQuery<CalendarData>({
queryKey: ['newbook-calendar', year, month],
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}` },
})
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>({
queryKey: ['residents-table-chart', 'v2', startDate], // v2 to invalidate old cache
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}` }
})
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>({
queryKey: ['resos-settings'],
queryFn: async () => {
const res = await fetch('/api/resos/settings', {
const res = await fetch('/kitchen/api/resos/settings', {
headers: { Authorization: `Bearer ${token}` },
})
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 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}` },
})
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 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}` },
})
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 lastDay = new Date(year, month, 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}` }
})
if (!res.ok) throw new Error('Failed to fetch calendar events')
@ -181,7 +181,7 @@ export default function ResosData() {
queryKey: ['resos-bookings', selectedDate],
queryFn: async () => {
if (!selectedDate) return []
const res = await fetch(`/api/resos/bookings/${selectedDate}`, {
const res = await fetch(`/kitchen/api/resos/bookings/${selectedDate}`, {
headers: { Authorization: `Bearer ${token}` },
})
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[] }>({
queryKey: ['resos-all-opening-hours'],
queryFn: async () => {
const res = await fetch(`/api/resos/opening-hours`, {
const res = await fetch(`/kitchen/api/resos/opening-hours`, {
headers: { Authorization: `Bearer ${token}` }
})
if (!res.ok) throw new Error('Failed to fetch opening hours')
@ -230,7 +230,7 @@ export default function ResosData() {
queryKey: ['resos-opening-hours', selectedDate],
queryFn: async () => {
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}` }
})
if (!res.ok) throw new Error('Failed to fetch opening hours')
@ -1322,7 +1322,7 @@ export default function ResosData() {
<button
onClick={async () => {
if (confirm('Delete this event?')) {
await fetch(`/api/calendar-events/${editingEvent.id}`, {
await fetch(`/kitchen/api/calendar-events/${editingEvent.id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` }
})
@ -1359,8 +1359,8 @@ export default function ResosData() {
<button
onClick={async () => {
const url = editingEvent
? `/api/calendar-events/${editingEvent.id}`
: '/api/calendar-events/'
? `/kitchen/api/calendar-events/${editingEvent.id}`
: '/kitchen/api/calendar-events/'
const method = editingEvent ? 'PUT' : 'POST'
await fetch(url, {

View file

@ -530,7 +530,7 @@ export default function Settings() {
const { data: settings, isLoading } = useQuery<SettingsData>({
queryKey: ['settings'],
queryFn: async () => {
const res = await fetch('/api/settings/', {
const res = await fetch('/kitchen/api/settings/', {
headers: { Authorization: `Bearer ${token}` },
})
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>({
queryKey: ['newbook-settings'],
queryFn: async () => {
const res = await fetch('/api/newbook/settings', {
const res = await fetch('/kitchen/api/newbook/settings', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) {
@ -561,7 +561,7 @@ export default function Settings() {
const { data: resosSettings, error: resosError, isLoading: resosLoading } = useQuery<ResosSettingsData>({
queryKey: ['resos-settings'],
queryFn: async () => {
const res = await fetch('/api/resos/settings', {
const res = await fetch('/kitchen/api/resos/settings', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) {
@ -579,7 +579,7 @@ export default function Settings() {
const { data: glAccounts, refetch: refetchGLAccounts } = useQuery<GLAccount[]>({
queryKey: ['gl-accounts'],
queryFn: async () => {
const res = await fetch('/api/newbook/gl-accounts', {
const res = await fetch('/kitchen/api/newbook/gl-accounts', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) return []
@ -591,7 +591,7 @@ export default function Settings() {
const { data: roomCategories, refetch: refetchRoomCategories } = useQuery<RoomCategory[]>({
queryKey: ['room-categories'],
queryFn: async () => {
const res = await fetch('/api/newbook/room-categories', {
const res = await fetch('/kitchen/api/newbook/room-categories', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) return []
@ -619,7 +619,7 @@ export default function Settings() {
const { data: sambaSettings } = useQuery<SambaPOSSettingsData>({
queryKey: ['sambapos-settings'],
queryFn: async () => {
const res = await fetch('/api/sambapos/settings', {
const res = await fetch('/kitchen/api/sambapos/settings', {
headers: { Authorization: `Bearer ${token}` },
})
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[]>({
queryKey: ['sambapos-categories'],
queryFn: async () => {
const res = await fetch('/api/sambapos/categories', {
const res = await fetch('/kitchen/api/sambapos/categories', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) {
@ -649,7 +649,7 @@ export default function Settings() {
const { data: sambaGroupCodes, refetch: refetchSambaGroupCodes, isLoading: sambaGroupCodesLoading } = useQuery<SambaPOSGroupCode[]>({
queryKey: ['sambapos-group-codes'],
queryFn: async () => {
const res = await fetch('/api/sambapos/group-codes', {
const res = await fetch('/kitchen/api/sambapos/group-codes', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) {
@ -666,7 +666,7 @@ export default function Settings() {
const { data: sambaGLCodes, refetch: refetchSambaGLCodes, isLoading: sambaGLCodesLoading } = useQuery<SambaPOSGLCode[]>({
queryKey: ['sambapos-gl-codes'],
queryFn: async () => {
const res = await fetch('/api/sambapos/gl-codes', {
const res = await fetch('/kitchen/api/sambapos/gl-codes', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) {
@ -683,7 +683,7 @@ export default function Settings() {
const { data: selectedGLCodes } = useQuery<{ food_codes: string[]; beverage_codes: string[] }>({
queryKey: ['sambapos-selected-gl-codes'],
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}` },
})
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>({
queryKey: ['kds-settings'],
queryFn: async () => {
const res = await fetch('/api/kds/settings', {
const res = await fetch('/kitchen/api/kds/settings', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch KDS settings')
@ -719,7 +719,7 @@ export default function Settings() {
const { data: kitchenDetails } = useQuery<KitchenDetailsData>({
queryKey: ['kitchen-details'],
queryFn: async () => {
const res = await fetch('/api/settings/kitchen-details', {
const res = await fetch('/kitchen/api/settings/kitchen-details', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch kitchen details')
@ -739,7 +739,7 @@ export default function Settings() {
const { data: budgetSettings } = useQuery<BudgetSettingsData>({
queryKey: ['budget-settings'],
queryFn: async () => {
const res = await fetch('/api/budget/settings', {
const res = await fetch('/kitchen/api/budget/settings', {
headers: { Authorization: `Bearer ${token}` },
})
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[] }>({
queryKey: ['page-restrictions'],
queryFn: async () => {
const res = await fetch('/api/settings/page-restrictions', {
const res = await fetch('/kitchen/api/settings/page-restrictions', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch page restrictions')
@ -765,7 +765,7 @@ export default function Settings() {
const { data: nextcloudSettings } = useQuery<NextcloudSettingsData>({
queryKey: ['nextcloud-settings'],
queryFn: async () => {
const res = await fetch('/api/settings/nextcloud', {
const res = await fetch('/kitchen/api/settings/nextcloud', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch Nextcloud settings')
@ -778,7 +778,7 @@ export default function Settings() {
const { data: nextcloudStats } = useQuery<NextcloudStatsData>({
queryKey: ['nextcloud-stats'],
queryFn: async () => {
const res = await fetch('/api/settings/nextcloud/stats', {
const res = await fetch('/kitchen/api/settings/nextcloud/stats', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch Nextcloud stats')
@ -791,7 +791,7 @@ export default function Settings() {
const { data: backupSettings } = useQuery<BackupSettingsData>({
queryKey: ['backup-settings'],
queryFn: async () => {
const res = await fetch('/api/backup/settings', {
const res = await fetch('/kitchen/api/backup/settings', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch backup settings')
@ -804,7 +804,7 @@ export default function Settings() {
const { data: backupHistory } = useQuery<BackupHistoryEntry[]>({
queryKey: ['backup-history'],
queryFn: async () => {
const res = await fetch('/api/backup/history', {
const res = await fetch('/kitchen/api/backup/history', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch backup history')
@ -817,7 +817,7 @@ export default function Settings() {
const { data: searchSettings } = useQuery<SearchSettingsData>({
queryKey: ['search-settings'],
queryFn: async () => {
const res = await fetch('/api/search/settings', {
const res = await fetch('/kitchen/api/search/settings', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch search settings')
@ -830,7 +830,7 @@ export default function Settings() {
const { data: imapSettings } = useQuery<ImapSettingsData>({
queryKey: ['imap-settings'],
queryFn: async () => {
const res = await fetch('/api/imap/settings', {
const res = await fetch('/kitchen/api/imap/settings', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch IMAP settings')
@ -843,7 +843,7 @@ export default function Settings() {
const { data: imapLogs } = useQuery<ImapLogEntry[]>({
queryKey: ['imap-logs'],
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}` },
})
if (!res.ok) throw new Error('Failed to fetch IMAP logs')
@ -856,7 +856,7 @@ export default function Settings() {
const { data: imapStats } = useQuery<ImapSyncStats>({
queryKey: ['imap-stats'],
queryFn: async () => {
const res = await fetch('/api/imap/logs/stats', {
const res = await fetch('/kitchen/api/imap/logs/stats', {
headers: { Authorization: `Bearer ${token}` },
})
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
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}` }
})
.then(res => res.json())
@ -1075,7 +1075,7 @@ export default function Settings() {
// 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) {
fetch('/api/resos/opening-hours', {
fetch('/kitchen/api/resos/opening-hours', {
headers: { Authorization: `Bearer ${token}` }
})
.then(res => res.json())
@ -1089,7 +1089,7 @@ export default function Settings() {
const { data: foodFlagCategories, refetch: refetchFoodFlags } = useQuery<FoodFlagCategoryData[]>({
queryKey: ['food-flag-categories'],
queryFn: async () => {
const res = await fetch('/api/food-flags/categories', {
const res = await fetch('/kitchen/api/food-flags/categories', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) return []
@ -1101,7 +1101,7 @@ export default function Settings() {
const { data: apiAccessSettings } = useQuery<ApiAccessData>({
queryKey: ['api-access-settings'],
queryFn: async () => {
const res = await fetch('/api/settings/api-access', {
const res = await fetch('/kitchen/api/settings/api-access', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) return { api_key: null, api_key_enabled: false }
@ -1120,7 +1120,7 @@ export default function Settings() {
// Food Flag mutations
const createCategoryMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -1141,7 +1141,7 @@ export default function Settings() {
const updateCategoryMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -1160,7 +1160,7 @@ export default function Settings() {
const deleteCategoryMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -1177,7 +1177,7 @@ export default function Settings() {
const createFlagMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -1199,7 +1199,7 @@ export default function Settings() {
const updateFlagMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -1218,7 +1218,7 @@ export default function Settings() {
const deleteFlagMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -1250,7 +1250,7 @@ export default function Settings() {
const { data: allergenKeywords, refetch: refetchAllergenKeywords } = useQuery<AllergenKeywordGroup[]>({
queryKey: ['allergen-keywords'],
queryFn: async () => {
const res = await fetch('/api/food-flags/keywords', {
const res = await fetch('/kitchen/api/food-flags/keywords', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) return []
@ -1261,7 +1261,7 @@ export default function Settings() {
const addKeywordMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ food_flag_id, keyword }),
@ -1286,7 +1286,7 @@ export default function Settings() {
const deleteKeywordMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -1299,7 +1299,7 @@ export default function Settings() {
const resetKeywordsMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -1323,7 +1323,7 @@ export default function Settings() {
const { data: ingCategories, refetch: refetchIngCategories } = useQuery<IngredientCategoryItem[]>({
queryKey: ['ingredient-categories-settings'],
queryFn: async () => {
const res = await fetch('/api/ingredients/categories', {
const res = await fetch('/kitchen/api/ingredients/categories', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) return []
@ -1334,7 +1334,7 @@ export default function Settings() {
const createIngCatMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -1355,7 +1355,7 @@ export default function Settings() {
const updateIngCatMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -1374,7 +1374,7 @@ export default function Settings() {
const deleteIngCatMutation = useMutation({
mutationFn: async (id: number) => {
const res = await fetch(`/api/ingredients/categories/${id}`, {
const res = await fetch(`/kitchen/api/ingredients/categories/${id}`, {
method: 'DELETE',
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 }[]>({
queryKey: ['recipe-sections-settings'],
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}` },
})
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 }[]>({
queryKey: ['dish-courses-settings'],
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}` },
})
if (!res.ok) return []
@ -1430,7 +1430,7 @@ export default function Settings() {
// API Access mutations
const saveApiAccessMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -1449,7 +1449,7 @@ export default function Settings() {
const regenerateApiKeyMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/settings/api-access/regenerate', {
const res = await fetch('/kitchen/api/settings/api-access/regenerate', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -1474,7 +1474,7 @@ export default function Settings() {
}>({
queryKey: ['llm-usage'],
queryFn: async () => {
const res = await fetch('/api/settings/llm-usage', {
const res = await fetch('/kitchen/api/settings/llm-usage', {
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 }
@ -1492,7 +1492,7 @@ export default function Settings() {
}>({
queryKey: ['llm-models'],
queryFn: async () => {
const res = await fetch('/api/settings/llm-models', {
const res = await fetch('/kitchen/api/settings/llm-models', {
headers: { Authorization: `Bearer ${token}` },
})
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({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/settings/', {
const res = await fetch('/kitchen/api/settings/', {
method: 'PATCH',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@ -1523,7 +1523,7 @@ export default function Settings() {
const llmTestMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/settings/test-llm', {
const res = await fetch('/kitchen/api/settings/test-llm', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -1559,7 +1559,7 @@ export default function Settings() {
// Mutations
const updateMutation = useMutation({
mutationFn: async (data: Partial<SettingsData & { azure_key?: string }>) => {
const res = await fetch('/api/settings/', {
const res = await fetch('/kitchen/api/settings/', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -1583,7 +1583,7 @@ export default function Settings() {
const azureTestMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/settings/test-azure', {
const res = await fetch('/kitchen/api/settings/test-azure', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -1683,7 +1683,7 @@ export default function Settings() {
const savePageRestrictionsMutation = useMutation({
mutationFn: async (pages: string[]) => {
const res = await fetch('/api/settings/page-restrictions', {
const res = await fetch('/kitchen/api/settings/page-restrictions', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -1706,7 +1706,7 @@ export default function Settings() {
const reprocessMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/invoices/reprocess-all', {
const res = await fetch('/kitchen/api/invoices/reprocess-all', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -1728,7 +1728,7 @@ export default function Settings() {
const cleanupPriceChangesMutation = useMutation({
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -1749,7 +1749,7 @@ export default function Settings() {
const backfillInvoiceRefsMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/recipes/backfill-invoice-references', {
const res = await fetch('/kitchen/api/recipes/backfill-invoice-references', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -1770,7 +1770,7 @@ export default function Settings() {
const rematchFuzzyMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/suppliers/rematch-fuzzy', {
const res = await fetch('/kitchen/api/suppliers/rematch-fuzzy', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -1794,7 +1794,7 @@ export default function Settings() {
const updateNewbookMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
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',
headers: {
Authorization: `Bearer ${token}`,
@ -1826,7 +1826,7 @@ export default function Settings() {
const newbookTestMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/newbook/test-connection', {
const res = await fetch('/kitchen/api/newbook/test-connection', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -1849,7 +1849,7 @@ export default function Settings() {
const updateResosSyncMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
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',
headers: {
Authorization: `Bearer ${token}`,
@ -1879,7 +1879,7 @@ export default function Settings() {
const fetchGLAccountsMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/newbook/gl-accounts/fetch', {
const res = await fetch('/kitchen/api/newbook/gl-accounts/fetch', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -1901,7 +1901,7 @@ export default function Settings() {
const syncForecastMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/newbook/sync/forecast', {
const res = await fetch('/kitchen/api/newbook/sync/forecast', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -1923,7 +1923,7 @@ export default function Settings() {
const syncHistoricalMutation = useMutation({
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',
headers: {
Authorization: `Bearer ${token}`,
@ -1950,7 +1950,7 @@ export default function Settings() {
const updateGLAccountMutation = useMutation({
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',
headers: {
Authorization: `Bearer ${token}`,
@ -1968,7 +1968,7 @@ export default function Settings() {
const bulkUpdateGLAccountsMutation = useMutation({
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',
headers: {
Authorization: `Bearer ${token}`,
@ -1987,7 +1987,7 @@ export default function Settings() {
// Room category mutations
const fetchRoomCategoriesMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/newbook/room-categories/fetch', {
const res = await fetch('/kitchen/api/newbook/room-categories/fetch', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -2009,7 +2009,7 @@ export default function Settings() {
const bulkUpdateRoomCategoriesMutation = useMutation({
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',
headers: {
Authorization: `Bearer ${token}`,
@ -2028,7 +2028,7 @@ export default function Settings() {
// SambaPOS mutations
const updateSambaMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/sambapos/settings', {
const res = await fetch('/kitchen/api/sambapos/settings', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -2052,7 +2052,7 @@ export default function Settings() {
const sambaTestMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/sambapos/test-connection', {
const res = await fetch('/kitchen/api/sambapos/test-connection', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -2074,7 +2074,7 @@ export default function Settings() {
const saveSambaCoursesMutation = useMutation({
mutationFn: async (courses: string[]) => {
const res = await fetch('/api/sambapos/tracked-categories', {
const res = await fetch('/kitchen/api/sambapos/tracked-categories', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -2097,7 +2097,7 @@ export default function Settings() {
const saveExcludedItemsMutation = useMutation({
mutationFn: async (items: string[]) => {
const res = await fetch('/api/sambapos/excluded-items', {
const res = await fetch('/kitchen/api/sambapos/excluded-items', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -2120,7 +2120,7 @@ export default function Settings() {
const saveGLCodesMutation = useMutation({
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',
headers: {
Authorization: `Bearer ${token}`,
@ -2144,7 +2144,7 @@ export default function Settings() {
// KDS mutations
const updateKdsMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/kds/settings', {
const res = await fetch('/kitchen/api/kds/settings', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -2168,7 +2168,7 @@ export default function Settings() {
const kdsTestMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/kds/test-connection', {
const res = await fetch('/kitchen/api/kds/test-connection', {
headers: { Authorization: `Bearer ${token}` },
})
const data = await res.json()
@ -2189,7 +2189,7 @@ export default function Settings() {
// Budget/Forecast API mutations
const saveKitchenDetailsMutation = useMutation({
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',
headers: {
Authorization: `Bearer ${token}`,
@ -2215,7 +2215,7 @@ export default function Settings() {
const saveBudgetMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/budget/settings', {
const res = await fetch('/kitchen/api/budget/settings', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -2242,7 +2242,7 @@ export default function Settings() {
const budgetTestMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/budget/test-forecast-connection', {
const res = await fetch('/kitchen/api/budget/test-forecast-connection', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -2264,7 +2264,7 @@ export default function Settings() {
// Nextcloud mutations
const saveNextcloudMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/settings/nextcloud', {
const res = await fetch('/kitchen/api/settings/nextcloud', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -2291,7 +2291,7 @@ export default function Settings() {
const nextcloudTestMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/settings/nextcloud/test', {
const res = await fetch('/kitchen/api/settings/nextcloud/test', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -2312,7 +2312,7 @@ export default function Settings() {
const archiveAllMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/settings/nextcloud/archive-all', {
const res = await fetch('/kitchen/api/settings/nextcloud/archive-all', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -2335,7 +2335,7 @@ export default function Settings() {
// Backup mutations
const saveBackupMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/backup/settings', {
const res = await fetch('/kitchen/api/backup/settings', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -2361,7 +2361,7 @@ export default function Settings() {
const createBackupMutation = useMutation({
mutationFn: async () => {
const res = await fetch('/api/backup/create', {
const res = await fetch('/kitchen/api/backup/create', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -2384,7 +2384,7 @@ export default function Settings() {
const restoreBackupMutation = useMutation({
mutationFn: async (backupId: number) => {
const res = await fetch(`/api/backup/${backupId}/restore`, {
const res = await fetch(`/kitchen/api/backup/${backupId}/restore`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -2407,7 +2407,7 @@ export default function Settings() {
const deleteBackupMutation = useMutation({
mutationFn: async (backupId: number) => {
const res = await fetch(`/api/backup/${backupId}`, {
const res = await fetch(`/kitchen/api/backup/${backupId}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` },
})
@ -2431,7 +2431,7 @@ export default function Settings() {
mutationFn: async (file: File) => {
const formData = new FormData()
formData.append('file', file)
const res = await fetch('/api/backup/upload', {
const res = await fetch('/kitchen/api/backup/upload', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: formData,
@ -2455,7 +2455,7 @@ export default function Settings() {
// Search settings mutation
const saveSearchSettingsMutation = useMutation({
mutationFn: async (data: Record<string, unknown>) => {
const res = await fetch('/api/search/settings', {
const res = await fetch('/kitchen/api/search/settings', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -3426,7 +3426,7 @@ export default function Settings() {
support_email: supportEmail || null
}
const saveRes = await fetch('/api/settings/', {
const saveRes = await fetch('/kitchen/api/settings/', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
@ -3444,7 +3444,7 @@ export default function Settings() {
// Now test the connection
setSmtpTestStatus('Testing connection...')
const res = await fetch('/api/settings/test-smtp', {
const res = await fetch('/kitchen/api/settings/test-smtp', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` }
})
@ -3469,7 +3469,7 @@ export default function Settings() {
<button
onClick={async () => {
try {
const res = await fetch('/api/settings/', {
const res = await fetch('/kitchen/api/settings/', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
@ -3646,7 +3646,7 @@ export default function Settings() {
onClick={async () => {
setImapTestStatus('Testing connection...')
try {
const res = await fetch('/api/imap/test-connection', {
const res = await fetch('/kitchen/api/imap/test-connection', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@ -3679,7 +3679,7 @@ export default function Settings() {
onClick={async () => {
setImapSyncMessage('Syncing...')
try {
const res = await fetch('/api/imap/sync-now', {
const res = await fetch('/kitchen/api/imap/sync-now', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` }
})
@ -3709,7 +3709,7 @@ export default function Settings() {
onClick={async () => {
setImapSaveMessage('Saving...')
try {
const res = await fetch('/api/imap/settings', {
const res = await fetch('/kitchen/api/imap/settings', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
@ -3915,7 +3915,7 @@ export default function Settings() {
<button
onClick={async () => {
try {
const res = await fetch('/api/settings/', {
const res = await fetch('/kitchen/api/settings/', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
@ -3966,7 +3966,7 @@ export default function Settings() {
return
}
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',
headers: { Authorization: `Bearer ${token}` }
})
@ -4329,7 +4329,7 @@ export default function Settings() {
onClick={async () => {
try {
setResosTestStatus('Testing...')
const res = await fetch('/api/resos/test-connection', {
const res = await fetch('/kitchen/api/resos/test-connection', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` }
})
@ -4399,7 +4399,7 @@ export default function Settings() {
<button
onClick={async () => {
try {
const res = await fetch('/api/resos/custom-fields', {
const res = await fetch('/kitchen/api/resos/custom-fields', {
headers: { Authorization: `Bearer ${token}` }
})
if (res.ok) {
@ -4463,7 +4463,7 @@ export default function Settings() {
onClick={async () => {
try {
// 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',
headers: { Authorization: `Bearer ${token}` }
})
@ -4477,7 +4477,7 @@ export default function Settings() {
const syncData = await syncRes.json()
// 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}` }
})
if (res.ok) {
@ -4787,7 +4787,7 @@ export default function Settings() {
onClick={async () => {
try {
setResosSaveMessage('Syncing upcoming bookings...')
const res = await fetch('/api/resos/sync/upcoming', {
const res = await fetch('/kitchen/api/resos/sync/upcoming', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` }
})
@ -4815,7 +4815,7 @@ export default function Settings() {
onClick={async () => {
try {
setResosSaveMessage('Syncing forecast...')
const res = await fetch('/api/resos/sync/forecast', {
const res = await fetch('/kitchen/api/resos/sync/forecast', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` }
})
@ -4855,7 +4855,7 @@ export default function Settings() {
<button
onClick={async () => {
try {
const res = await fetch('/api/resos/settings', {
const res = await fetch('/kitchen/api/resos/settings', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
@ -4937,7 +4937,7 @@ export default function Settings() {
onClick={async () => {
try {
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',
headers: { Authorization: `Bearer ${token}` }
})
@ -6405,7 +6405,7 @@ export default function Settings() {
<div style={styles.actionButtons}>
<button
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}
disabled={backup.status !== 'success'}
@ -6464,7 +6464,7 @@ export default function Settings() {
setSeedingDefaults(true)
setFoodFlagMessage(null)
try {
const res = await fetch('/api/food-flags/seed-defaults', {
const res = await fetch('/kitchen/api/food-flags/seed-defaults', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -6891,7 +6891,7 @@ export default function Settings() {
onClick={async () => {
setIngCatMessage(null)
try {
const res = await fetch('/api/ingredients/categories/seed-defaults', {
const res = await fetch('/kitchen/api/ingredients/categories/seed-defaults', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
})
@ -7061,7 +7061,7 @@ export default function Settings() {
onClick={async () => {
setRecipeSectionsMsg(null)
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -7108,7 +7108,7 @@ export default function Settings() {
<button
onClick={async () => {
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()
}
}}
@ -7136,7 +7136,7 @@ export default function Settings() {
const input = e.currentTarget
const name = input.value.trim()
if (!name) return
const res = await fetch('/api/recipes/menu-sections', {
const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
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 name = input?.value.trim()
if (!name) return
const res = await fetch('/api/recipes/menu-sections', {
const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, section_type: 'recipe', sort_order: recipeSections?.length || 0 }),
@ -7172,7 +7172,7 @@ export default function Settings() {
onClick={async () => {
setDishCoursesMsg(null)
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',
headers: { Authorization: `Bearer ${token}` },
})
@ -7219,7 +7219,7 @@ export default function Settings() {
<button
onClick={async () => {
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()
}
}}
@ -7247,7 +7247,7 @@ export default function Settings() {
const input = e.currentTarget
const name = input.value.trim()
if (!name) return
const res = await fetch('/api/recipes/menu-sections', {
const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
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 name = input?.value.trim()
if (!name) return
const res = await fetch('/api/recipes/menu-sections', {
const res = await fetch('/kitchen/api/recipes/menu-sections', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
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
))
const res = await fetch('/api/invoices/upload', {
const res = await fetch('/kitchen/api/invoices/upload', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: formData,
@ -220,7 +220,7 @@ export default function UploadApp() {
const formData = new FormData()
formData.append('file', pdfFile)
const res = await fetch('/api/invoices/upload', {
const res = await fetch('/kitchen/api/invoices/upload', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: formData,

View file

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