From dfebcc11ef3c98217dfb0671ac9c6a88194634bf Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Mon, 16 Mar 2026 00:44:35 +0100 Subject: [PATCH] feat(webhooks): add webhook fields to frontend types, api, and edit sheet --- .../components/edit-channel-sheet.tsx | 32 ++++++ k-tv-frontend/lib/types.ts | 7 ++ k-tv-frontend/package-lock.json | 100 ++++++++++++++---- k-tv-frontend/package.json | 2 +- 4 files changed, 122 insertions(+), 19 deletions(-) diff --git a/k-tv-frontend/app/(main)/dashboard/components/edit-channel-sheet.tsx b/k-tv-frontend/app/(main)/dashboard/components/edit-channel-sheet.tsx index b7f4a0b..a1a276b 100644 --- a/k-tv-frontend/app/(main)/dashboard/components/edit-channel-sheet.tsx +++ b/k-tv-frontend/app/(main)/dashboard/components/edit-channel-sheet.tsx @@ -756,6 +756,8 @@ interface EditChannelSheetProps { logo?: string | null; logo_position?: LogoPosition; logo_opacity?: number; + webhook_url?: string | null; + webhook_poll_interval_secs?: number; }, ) => void; isPending: boolean; @@ -787,6 +789,8 @@ export function EditChannelSheet({ const [logo, setLogo] = useState(null); const [logoPosition, setLogoPosition] = useState("top_right"); const [logoOpacity, setLogoOpacity] = useState(100); + const [webhookUrl, setWebhookUrl] = useState(""); + const [webhookPollInterval, setWebhookPollInterval] = useState(5); const [selectedBlockId, setSelectedBlockId] = useState(null); const [fieldErrors, setFieldErrors] = useState({}); const fileInputRef = useRef(null); @@ -804,6 +808,8 @@ export function EditChannelSheet({ setLogo(channel.logo ?? null); setLogoPosition(channel.logo_position ?? "top_right"); setLogoOpacity(Math.round((channel.logo_opacity ?? 1) * 100)); + setWebhookUrl(channel.webhook_url ?? ""); + setWebhookPollInterval(channel.webhook_poll_interval_secs ?? 5); setSelectedBlockId(null); setFieldErrors({}); } @@ -836,6 +842,10 @@ export function EditChannelSheet({ logo: logo, logo_position: logoPosition, logo_opacity: logoOpacity / 100, + webhook_url: webhookUrl || null, + ...(webhookUrl + ? { webhook_poll_interval_secs: webhookPollInterval === "" ? 5 : webhookPollInterval } + : {}), }); }; @@ -1085,6 +1095,28 @@ export function EditChannelSheet({ onChange={setRecyclePolicy} /> + + {/* Webhook */} +
+

Webhook

+ + + + {webhookUrl && ( + + + + )} +
{/* Footer */} diff --git a/k-tv-frontend/lib/types.ts b/k-tv-frontend/lib/types.ts index 3c0eb13..6d84764 100644 --- a/k-tv-frontend/lib/types.ts +++ b/k-tv-frontend/lib/types.ts @@ -147,6 +147,8 @@ export interface ChannelResponse { logo?: string | null; logo_position: LogoPosition; logo_opacity: number; + webhook_url?: string | null; + webhook_poll_interval_secs?: number; created_at: string; updated_at: string; } @@ -157,6 +159,8 @@ export interface CreateChannelRequest { description?: string; access_mode?: AccessMode; access_password?: string; + webhook_url?: string; + webhook_poll_interval_secs?: number; } export interface UpdateChannelRequest { @@ -173,6 +177,9 @@ export interface UpdateChannelRequest { logo?: string | null; logo_position?: LogoPosition; logo_opacity?: number; + /** null = clear webhook */ + webhook_url?: string | null; + webhook_poll_interval_secs?: number; } // Media & Schedule diff --git a/k-tv-frontend/package-lock.json b/k-tv-frontend/package-lock.json index b7808a1..4021b95 100644 --- a/k-tv-frontend/package-lock.json +++ b/k-tv-frontend/package-lock.json @@ -16,6 +16,7 @@ "cmdk": "^1.1.1", "date-fns": "^4.1.0", "embla-carousel-react": "^8.6.0", + "hls.js": "^1.6.15", "input-otp": "^1.4.2", "lucide-react": "^0.577.0", "next": "16.1.6", @@ -30,17 +31,20 @@ "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tw-animate-css": "^1.4.0", - "vaul": "^1.1.2" + "vaul": "^1.1.2", + "zod": "^4.3.6" }, "devDependencies": { "@tailwindcss/postcss": "^4", + "@types/chromecast-caf-sender": "^1.0.11", + "@types/hls.js": "^1.0.0", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "16.1.6", "tailwindcss": "^4", - "typescript": "^5" + "typescript": "5.9.3" } }, "node_modules/@alloc/quick-lru": { @@ -1493,13 +1497,6 @@ "version": "1.0.0", "license": "MIT" }, - "node_modules/@modelcontextprotocol/sdk/node_modules/zod": { - "version": "4.3.6", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/@mswjs/interceptors": { "version": "0.41.3", "license": "MIT", @@ -3551,6 +3548,27 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/chrome": { + "version": "0.1.37", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.1.37.tgz", + "integrity": "sha512-IJE4ceuDO7lrEuua7Pow47zwNcI8E6qqkowRP7aFPaZ0lrjxh6y836OPqqkIZeTX64FTogbw+4RNH0+QrweCTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, + "node_modules/@types/chromecast-caf-sender": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/chromecast-caf-sender/-/chromecast-caf-sender-1.0.11.tgz", + "integrity": "sha512-Pv3xvNYtxD/cTM/tKfuZRlLasvpxAm+CFni0GJd6Cp8XgiZS9g9tMZkR1uymsi5fIFv057SZKKAWVFFgy7fJtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chrome": "*" + } + }, "node_modules/@types/d3-array": { "version": "3.2.2", "license": "MIT" @@ -3601,6 +3619,41 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/filesystem": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.36.tgz", + "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz", + "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/har-format": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz", + "integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hls.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/hls.js/-/hls.js-1.0.0.tgz", + "integrity": "sha512-EGY2QJefX+Z9XH4PAxI7RFoNqBlQEk16UpYR3kbr82CIgMX5SlMe0PjFdFV0JytRhyVPQCiwSyONuI6S1KdSag==", + "deprecated": "This is a stub types definition. hls.js provides its own type definitions, so you do not need this installed.", + "dev": true, + "license": "MIT", + "dependencies": { + "hls.js": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "dev": true, @@ -5862,14 +5915,6 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, - "node_modules/eslint-plugin-react-hooks/node_modules/zod": { - "version": "4.3.6", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.6", "dev": true, @@ -6654,6 +6699,12 @@ "hermes-estree": "0.25.1" } }, + "node_modules/hls.js": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.15.tgz", + "integrity": "sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==", + "license": "Apache-2.0" + }, "node_modules/hono": { "version": "4.12.7", "license": "MIT", @@ -9321,6 +9372,15 @@ "shadcn": "dist/index.js" } }, + "node_modules/shadcn/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/sharp": { "version": "0.34.5", "hasInstallScript": true, @@ -10005,6 +10065,8 @@ }, "node_modules/typescript": { "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -10525,7 +10587,9 @@ } }, "node_modules/zod": { - "version": "3.25.76", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/k-tv-frontend/package.json b/k-tv-frontend/package.json index 4b6309a..b965ea5 100644 --- a/k-tv-frontend/package.json +++ b/k-tv-frontend/package.json @@ -45,7 +45,7 @@ "eslint": "^9", "eslint-config-next": "16.1.6", "tailwindcss": "^4", - "typescript": "^5" + "typescript": "5.9.3" }, "ignoreScripts": [ "sharp",