From 84772852e3550bc88b33fb8fa05d173ba40cfb0d Mon Sep 17 00:00:00 2001 From: Corban-Lee Date: Thu, 1 May 2025 12:32:32 +0100 Subject: [PATCH] feat: patch existing feeds --- src/client/src/ts/guild/feeds.ts | 65 ++++++++++++++++--- .../controllers/guild/api/feed.controller.ts | 38 ++++++++++- 2 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src/client/src/ts/guild/feeds.ts b/src/client/src/ts/guild/feeds.ts index 9053a33..c08034f 100644 --- a/src/client/src/ts/guild/feeds.ts +++ b/src/client/src/ts/guild/feeds.ts @@ -33,7 +33,7 @@ const emptyTableHtml: string = `

- @@ -66,8 +66,8 @@ const columnDefs: ConfigColumnDefs[] = [ orderable: true, searchable: true, className: "size-px whitespace-nowrap", - render: (data: string) => { return ` - + render: (data: string, _type: string, row: prisma.Feed) => { return ` + ${data} `} @@ -294,12 +294,49 @@ const editModal: HSOverlay = new HSOverlay( editModalOptions ); -$(document).on("click", ".open-edit-modal-js", async () => { - await openEditModal(-1); +$(document).on("click", ".open-edit-modal-js", async event => { + await openEditModal($(event.target).data("id")); }); -const openEditModal = async (id: number) => { +interface FeedWithChannels extends prisma.Feed { + channels: prisma.Channel[] +} + +const clearEditModalData = () => { + $(editModal.el).data("id", undefined); + + $("#formName").val(""); + $("#formUrl").val(""); + $("#formActive").prop("checked", true); + channelSelect.setValue([]); +}; + +const loadEditModalData = async (id: number) => { + const feed: FeedWithChannels = await ajax({ + url: `/guild/${guildId}/feeds/api?id=${id}`, + method: "get" + }); + + $(editModal.el).data("id", feed.id); + + $("#formName").val(feed.name); + $("#formUrl").val(feed.url); + $("#formActive").prop("checked", feed.active); + + channelSelect.setValue(feed.channels.map(channel => channel.channel_id)); +} + +const openEditModal = async (id: number | undefined) => { + // ISSUE: + // The calculation with `channelSelect.setValue([])` assumes components are visible + // when determining the width of the input placeholder 'Select option...'. This + // requires the modal to be opened before running the calculation, which could be + // bad. editModal.open(); + + id === undefined + ? clearEditModalData() + : loadEditModalData(id); }; const closeEditModal = () => { @@ -356,11 +393,23 @@ $("#editForm").on("submit", async event => { if (!form.checkValidity()) return; + let method = "post"; + const data = $(event.target).serializeArray(); + const id: number | undefined = $(editModal.el).data("id"); + + if (id !== undefined) { + data.push({ + name: "id", + value: `${id}` + }) + method = "patch"; + } + await $.ajax({ url: `/guild/${guildId}/feeds/api`, - method: "post", dataType: "json", - data: $(event.target).serializeArray(), + method: method, + data: data, success: () => { (table as any).dataTable.draw() // is this okay? dataTable is private, but there is no other method I know of to redraw... closeEditModal(); diff --git a/src/server/controllers/guild/api/feed.controller.ts b/src/server/controllers/guild/api/feed.controller.ts index bec9078..29091ad 100644 --- a/src/server/controllers/guild/api/feed.controller.ts +++ b/src/server/controllers/guild/api/feed.controller.ts @@ -34,7 +34,7 @@ export const post = async (request: Request, response: Response) => { try { feed = await prisma.feed.create({ - data: { + data: { name: name, url: url, guild_id: guildId, @@ -54,7 +54,39 @@ export const post = async (request: Request, response: Response) => { response.status(201).json(feed); }; -export const patch = async () => {} // TODO ... +export const patch = async (request: Request, response: Response) => { + const guildId = request.params.guildId; + const { id, name, url, active, channels } = request.body; + + // channels comes through as either String[] or String + const formattedChannels = Array.isArray(channels) + ? channels.map((channelId) => ({ channel_id: channelId })) + : [{ channel_id: channels }] + + let feed; + + try { + feed = await prisma.feed.update({ + where: { id: Number(id) }, + data: { + name: name, + url: url, + guild_id: guildId, + active: active === "on", + channels: channels !== undefined ? { create: formattedChannels } : channels + } + }); + } + catch (error) { + console.error(error); + if (error instanceof Prisma.PrismaClientKnownRequestError) { + response.status(500).json({ error: error.message }); + return; + } + } + + response.status(201).json(feed); +} export const del = async (request: Request, response: Response) => { const { ids } = request.body; @@ -87,7 +119,7 @@ export const datatable = async (request: Request, response: Response) => { request, response, prisma.feed, - { id: "asc" }, + [{ updated_at: "desc" }, { id: "asc" }], { channels: true, filters: true }, { guild_id: request.params.guildId } // TODO: verify authenticated user can access this guild );