diff --git a/app/models/design.server.ts b/app/models/design.server.ts index 64812f91..56138eeb 100644 --- a/app/models/design.server.ts +++ b/app/models/design.server.ts @@ -12,6 +12,8 @@ export interface IDesignWithType { type: string visible: boolean createdAt: Date | string + nextId: string | null + prevId: string | null ownerId: string artboardId: string | null palette: IPalette | null diff --git a/app/routes/sketch+/artboards+/$slug_+/actions/artboard-design.ts b/app/routes/sketch+/artboards+/$slug_+/actions/artboard-design.ts index 5d86d8fd..a777f724 100644 --- a/app/routes/sketch+/artboards+/$slug_+/actions/artboard-design.ts +++ b/app/routes/sketch+/artboards+/$slug_+/actions/artboard-design.ts @@ -30,15 +30,169 @@ export async function artboardDesignReorderAction({ } // changes - const { id } = submission.value + const { id, direction } = submission.value try { await prisma.$transaction(async prisma => { const design = await prisma.design.findFirst({ where: { id, ownerId: userId }, }) if (!design) return submissionErrorResponse(submission) + const { nextId, prevId } = design + + // remove unique constraints on current design + const currentDesignRemoveNodes = prisma.design.update({ + where: { id }, + data: { prevId: null, nextId: null }, + }) + + if (direction === 'up') { + // if design is head, do nothing + if (!prevId) return submissionErrorResponse(submission) + + // CURRENT DESIGN PREV DESIGN (required unless was head) + const prev = await prisma.design.findFirst({ + where: { id: prevId }, + }) + if (!prev) return submissionErrorResponse(submission) + + const prevDesignRemoveNodes = prisma.design.update({ + where: { id: prevId }, + data: { prevId: null, nextId: null }, + }) + + const prevDesignUpdateNodes = prisma.design.update({ + where: { id: prevId }, + data: { nextId, prevId: id }, + }) + + // CURRENT DESIGN PREV PREV DESIGN (required unless prev was head) + // check if prev design had its own prev design + // and set nextId of prev prev design to current id of design + let prevPrevDesignUpdateNext + if (prev.prevId) { + const prevPrevDesign = await prisma.design.findFirst({ + where: { id: prev.prevId }, + }) + if (prevPrevDesign) { + prevPrevDesignUpdateNext = prisma.design.update({ + where: { id: prev.prevId }, + data: { nextId: id }, + }) + } + } + + // CURRENT DESIGN NEXT DESIGN (optional if was tail) + let nextDesignRemovePrev, nextDesignUpdatePrev + if (nextId) { + const next = await prisma.design.findFirst({ + where: { id: nextId }, + }) + if (next) { + nextDesignRemovePrev = prisma.design.update({ + where: { id: nextId }, + data: { prevId: null }, + }) + + nextDesignUpdatePrev = prisma.design.update({ + where: { id: nextId }, + data: { prevId }, + }) + } + } + + // update prevId of current design to prevId of prev design + // and nextId of current design to id of prev design + const currentDesignUpdateNodes = prisma.design.update({ + where: { id }, + data: { prevId: prev.prevId, nextId: prevId }, + }) + + // order of promises is important + // since unique constraints will fail the transaction + const promises = [] + promises.push(currentDesignRemoveNodes) + promises.push(prevDesignRemoveNodes) + if (nextDesignRemovePrev) promises.push(nextDesignRemovePrev) + if (nextDesignUpdatePrev) promises.push(nextDesignUpdatePrev) + promises.push(prevPrevDesignUpdateNext) + promises.push(prevDesignUpdateNodes) + promises.push(currentDesignUpdateNodes) + await Promise.all(promises) + } else if (direction === 'down') { + console.log('down') + // if design is tail, do nothing + if (!nextId) return submissionErrorResponse(submission) + + // CURRENT DESIGN NEXT DESIGN (required unless was tail) + const next = await prisma.design.findFirst({ + where: { id: nextId }, + }) + if (!next) return submissionErrorResponse(submission) + + const nextDesignRemoveNodes = prisma.design.update({ + where: { id: nextId }, + data: { prevId: null, nextId: null }, + }) + + const nextDesignUpdateNodes = prisma.design.update({ + where: { id: nextId }, + data: { nextId: id, prevId }, + }) - // TODO: reorder here + // CURRENT DESIGN NEXT NEXT DESIGN (required unless next was tail) + // check if next design had its own next design + // and set nextId of next next design to current id of design + let nextNextDesignUpdatePrev + if (next.nextId) { + const nextNextDesign = await prisma.design.findFirst({ + where: { id: next.nextId }, + }) + if (nextNextDesign) { + nextNextDesignUpdatePrev = prisma.design.update({ + where: { id: next.nextId }, + data: { prevId: id }, + }) + } + } + + // CURRENT DESIGN PREV DESIGN (optional if was head) + let prevDesignRemoveNext, prevDesignUpdateNext + if (prevId) { + const prev = await prisma.design.findFirst({ + where: { id: prevId }, + }) + if (prev) { + prevDesignRemoveNext = prisma.design.update({ + where: { id: prevId }, + data: { nextId: null }, + }) + + prevDesignUpdateNext = prisma.design.update({ + where: { id: prevId }, + data: { nextId }, + }) + } + } + + // update nextId of current design to nextId of prev design + // and nextId of current design to id of prev design + const currentDesignUpdateNodes = prisma.design.update({ + where: { id }, + data: { nextId: next.nextId, prevId: nextId }, + }) + + // order of promises is important + // since unique constraints will fail the transaction + const promises = [] + promises.push(currentDesignRemoveNodes) + promises.push(nextDesignRemoveNodes) + if (prevDesignRemoveNext) promises.push(prevDesignRemoveNext) + if (prevDesignUpdateNext) promises.push(prevDesignUpdateNext) + promises.push(nextNextDesignUpdatePrev) + promises.push(nextDesignUpdateNodes) + promises.push(currentDesignUpdateNodes) + await Promise.all(promises) + } }) } catch (error) { console.log(error) @@ -114,6 +268,8 @@ export async function artboardDesignDeleteAction({ where: { id }, }) if (!design) return submissionErrorResponse(submission) + // get nextId and prevId from design + const { nextId, prevId } = design // delete design will cascade delete type relation await prisma.design.delete({ @@ -121,34 +277,55 @@ export async function artboardDesignDeleteAction({ }) // if design is the only design in the artboard - if (!design.prevId && !design.nextId) return + if (!prevId && !nextId) return - if (!design.prevId && design.nextId) { + if (!prevId && nextId) { // if head // remove prevId from next design, becomes head - await prisma.design.update({ - where: { id: design.nextId }, - data: { prevId: null }, + const nextDesign = await prisma.design.findFirst({ + where: { id: nextId }, }) - } else if (design.prevId && !design.nextId) { + if (nextDesign) { + await prisma.design.update({ + where: { id: nextId }, + data: { prevId: null }, + }) + } + } else if (prevId && !nextId) { // if tail // remove nextId from prev design, becomes tail - await prisma.design.update({ - where: { id: design.prevId }, - data: { nextId: null }, + const prevDesign = await prisma.design.findFirst({ + where: { id: prevId }, }) - } else if (design.prevId && design.nextId) { + if (prevDesign) { + await prisma.design.update({ + where: { id: prevId }, + data: { nextId: null }, + }) + } + } else if (prevId && nextId) { // if in middle // replace nextId for prev design with nextId of deleted design - await prisma.design.update({ - where: { id: design.prevId }, - data: { nextId: design.nextId }, + const prevDesign = await prisma.design.findFirst({ + where: { id: prevId }, }) + if (prevDesign) { + await prisma.design.update({ + where: { id: prevId }, + data: { nextId: nextId }, + }) + } + // replace prevId for next design with prevId of deleted design - await prisma.design.update({ - where: { id: design.nextId }, - data: { prevId: design.prevId }, + const nextDesign = await prisma.design.findFirst({ + where: { id: nextId }, }) + if (nextDesign) { + await prisma.design.update({ + where: { id: nextId }, + data: { prevId: prevId }, + }) + } } }) } catch (error) { diff --git a/app/routes/sketch+/artboards+/$slug_+/components/panel-content-artboard-design-palette.tsx b/app/routes/sketch+/artboards+/$slug_+/components/panel-content-artboard-design-palette.tsx index 8ab4cf03..cae4d545 100644 --- a/app/routes/sketch+/artboards+/$slug_+/components/panel-content-artboard-design-palette.tsx +++ b/app/routes/sketch+/artboards+/$slug_+/components/panel-content-artboard-design-palette.tsx @@ -6,8 +6,6 @@ import { PanelRowIconContainer, PanelRowOrderContainer, PanelRowValueContainer, - // PanelRow, - // PanelRowContainer, PanelTitle, } from '#app/components/shared' import { type IDesignWithPalette } from '#app/models/design.server' @@ -25,6 +23,27 @@ export const PanelContentArtboardDesignPalette = ({ artboard: PickedArtboardType designPalettes: IDesignWithPalette[] }) => { + const orderedDesignPalettes = designPalettes.reduce( + (acc: IDesignWithPalette[], designPalette) => { + if (!designPalette.prevId) { + acc.unshift(designPalette) // Add the head of the list to the start + } else { + let currentDesignIndex = acc.findIndex( + d => d.id === designPalette.prevId, + ) + if (currentDesignIndex !== -1) { + // Insert the designPalette right after its predecessor + acc.splice(currentDesignIndex + 1, 0, designPalette) + } else { + // If predecessor is not found, add it to the end as a fallback + acc.push(designPalette) + } + } + return acc + }, + [], + ) + const designCount = designPalettes.length return ( @@ -34,7 +53,7 @@ export const PanelContentArtboardDesignPalette = ({ - {designPalettes.map((designPalette, index) => { + {orderedDesignPalettes.map((designPalette, index) => { const { id, visible, palette } = designPalette return (