Add menu item allergens, drop nav Help link, animate customizer price

- Menu items can now list allergens (shared catalog + join table),
  shown on the menu grid and item detail pages when applicable, and
  editable from the admin menu item form.
- Removed the top-nav "Help" link now that the footer links to it.
- The item customization page's price now uses the sliding
  AnimatedNumber, matching the basket line price.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 11:50:17 +02:00
co-authored by Claude Sonnet 5
parent 917fc275f9
commit 8481032e30
20 changed files with 1141 additions and 27 deletions
+15
View File
@@ -0,0 +1,15 @@
CREATE TABLE "allergens" (
"id" serial PRIMARY KEY NOT NULL,
"name" text NOT NULL
);
--> statement-breakpoint
CREATE TABLE "menu_item_allergens" (
"id" serial PRIMARY KEY NOT NULL,
"menu_item_id" integer NOT NULL,
"allergen_id" integer NOT NULL
);
--> statement-breakpoint
ALTER TABLE "menu_item_allergens" ADD CONSTRAINT "menu_item_allergens_menu_item_id_menu_items_id_fk" FOREIGN KEY ("menu_item_id") REFERENCES "public"."menu_items"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "menu_item_allergens" ADD CONSTRAINT "menu_item_allergens_allergen_id_allergens_id_fk" FOREIGN KEY ("allergen_id") REFERENCES "public"."allergens"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
CREATE UNIQUE INDEX "allergens_name_idx" ON "allergens" USING btree ("name");--> statement-breakpoint
CREATE UNIQUE INDEX "menu_item_allergens_item_allergen_idx" ON "menu_item_allergens" USING btree ("menu_item_id","allergen_id");
+870
View File
@@ -0,0 +1,870 @@
{
"id": "4086d6cd-5c93-4617-a15b-a90331b459a1",
"prevId": "83dc14cf-82fb-43fc-8b7d-fd377bf48689",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.allergens": {
"name": "allergens",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"allergens_name_idx": {
"name": "allergens_name_idx",
"columns": [
{
"expression": "name",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.brands": {
"name": "brands",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.contact_messages": {
"name": "contact_messages",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"message": {
"name": "message",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.machine_tags": {
"name": "machine_tags",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"machine_tags_name_idx": {
"name": "machine_tags_name_idx",
"columns": [
{
"expression": "name",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.machines": {
"name": "machines",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"machine_tag_id": {
"name": "machine_tag_id",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"machines_machine_tag_id_machine_tags_id_fk": {
"name": "machines_machine_tag_id_machine_tags_id_fk",
"tableFrom": "machines",
"tableTo": "machine_tags",
"columnsFrom": [
"machine_tag_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.menu_item_allergens": {
"name": "menu_item_allergens",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"menu_item_id": {
"name": "menu_item_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"allergen_id": {
"name": "allergen_id",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"menu_item_allergens_item_allergen_idx": {
"name": "menu_item_allergens_item_allergen_idx",
"columns": [
{
"expression": "menu_item_id",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "allergen_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"menu_item_allergens_menu_item_id_menu_items_id_fk": {
"name": "menu_item_allergens_menu_item_id_menu_items_id_fk",
"tableFrom": "menu_item_allergens",
"tableTo": "menu_items",
"columnsFrom": [
"menu_item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"menu_item_allergens_allergen_id_allergens_id_fk": {
"name": "menu_item_allergens_allergen_id_allergens_id_fk",
"tableFrom": "menu_item_allergens",
"tableTo": "allergens",
"columnsFrom": [
"allergen_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.menu_item_options": {
"name": "menu_item_options",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"menu_item_id": {
"name": "menu_item_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"price_delta_cents": {
"name": "price_delta_cents",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 0
}
},
"indexes": {},
"foreignKeys": {
"menu_item_options_menu_item_id_menu_items_id_fk": {
"name": "menu_item_options_menu_item_id_menu_items_id_fk",
"tableFrom": "menu_item_options",
"tableTo": "menu_items",
"columnsFrom": [
"menu_item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.menu_item_steps": {
"name": "menu_item_steps",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"menu_item_id": {
"name": "menu_item_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"sequence": {
"name": "sequence",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"machine_tag_id": {
"name": "machine_tag_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"estimated_duration_seconds": {
"name": "estimated_duration_seconds",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"menu_item_steps_menu_item_id_menu_items_id_fk": {
"name": "menu_item_steps_menu_item_id_menu_items_id_fk",
"tableFrom": "menu_item_steps",
"tableTo": "menu_items",
"columnsFrom": [
"menu_item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"menu_item_steps_machine_tag_id_machine_tags_id_fk": {
"name": "menu_item_steps_machine_tag_id_machine_tags_id_fk",
"tableFrom": "menu_item_steps",
"tableTo": "machine_tags",
"columnsFrom": [
"machine_tag_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.menu_items": {
"name": "menu_items",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"brand_id": {
"name": "brand_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"price_cents": {
"name": "price_cents",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"menu_items_brand_id_brands_id_fk": {
"name": "menu_items_brand_id_brands_id_fk",
"tableFrom": "menu_items",
"tableTo": "brands",
"columnsFrom": [
"brand_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.order_item_options": {
"name": "order_item_options",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"order_item_id": {
"name": "order_item_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"price_delta_cents": {
"name": "price_delta_cents",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"order_item_options_order_item_id_order_items_id_fk": {
"name": "order_item_options_order_item_id_order_items_id_fk",
"tableFrom": "order_item_options",
"tableTo": "order_items",
"columnsFrom": [
"order_item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.order_item_steps": {
"name": "order_item_steps",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"order_item_id": {
"name": "order_item_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"sequence": {
"name": "sequence",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"machine_tag_id": {
"name": "machine_tag_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"estimated_duration_seconds": {
"name": "estimated_duration_seconds",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"order_item_steps_order_item_id_order_items_id_fk": {
"name": "order_item_steps_order_item_id_order_items_id_fk",
"tableFrom": "order_item_steps",
"tableTo": "order_items",
"columnsFrom": [
"order_item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"order_item_steps_machine_tag_id_machine_tags_id_fk": {
"name": "order_item_steps_machine_tag_id_machine_tags_id_fk",
"tableFrom": "order_item_steps",
"tableTo": "machine_tags",
"columnsFrom": [
"machine_tag_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.order_items": {
"name": "order_items",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"order_id": {
"name": "order_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"menu_item_id": {
"name": "menu_item_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"price_cents": {
"name": "price_cents",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'placed'"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"order_items_order_id_orders_id_fk": {
"name": "order_items_order_id_orders_id_fk",
"tableFrom": "order_items",
"tableTo": "orders",
"columnsFrom": [
"order_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"order_items_menu_item_id_menu_items_id_fk": {
"name": "order_items_menu_item_id_menu_items_id_fk",
"tableFrom": "order_items",
"tableTo": "menu_items",
"columnsFrom": [
"menu_item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.orders": {
"name": "orders",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"customer_id": {
"name": "customer_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"guest_name": {
"name": "guest_name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"guest_contact": {
"name": "guest_contact",
"type": "text",
"primaryKey": false,
"notNull": false
},
"guest_access_token": {
"name": "guest_access_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'placed'"
},
"payment_charge_id": {
"name": "payment_charge_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.preparation_step_instances": {
"name": "preparation_step_instances",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"order_item_id": {
"name": "order_item_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"sequence": {
"name": "sequence",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"machine_tag_id": {
"name": "machine_tag_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"estimated_duration_seconds": {
"name": "estimated_duration_seconds",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'queued'"
},
"machine_id": {
"name": "machine_id",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"done_at": {
"name": "done_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"preparation_step_instances_order_item_id_order_items_id_fk": {
"name": "preparation_step_instances_order_item_id_order_items_id_fk",
"tableFrom": "preparation_step_instances",
"tableTo": "order_items",
"columnsFrom": [
"order_item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"preparation_step_instances_machine_tag_id_machine_tags_id_fk": {
"name": "preparation_step_instances_machine_tag_id_machine_tags_id_fk",
"tableFrom": "preparation_step_instances",
"tableTo": "machine_tags",
"columnsFrom": [
"machine_tag_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"preparation_step_instances_machine_id_machines_id_fk": {
"name": "preparation_step_instances_machine_id_machines_id_fk",
"tableFrom": "preparation_step_instances",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
+7
View File
@@ -43,6 +43,13 @@
"when": 1789636006749,
"tag": "0005_tan_power_man",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1789637974330,
"tag": "0006_worried_shooting_star",
"breakpoints": true
}
]
}