feat: swap out drizzle for supabase in label, list and workspace routers
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
|
|
||||||
import { HiXMark } from "react-icons/hi2";
|
import { HiXMark } from "react-icons/hi2";
|
||||||
@@ -28,15 +29,23 @@ export function NewWorkspaceForm() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const nameElement: HTMLElement | null =
|
||||||
|
document?.querySelector<HTMLElement>("#workspace-name");
|
||||||
|
if (nameElement) nameElement.focus();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex w-full justify-between pb-4">
|
<div className="flex w-full items-center justify-between pb-4">
|
||||||
<h2 className="text-sm font-bold text-dark-1000">New workspace</h2>
|
<h2 className="text-sm font-bold text-neutral-900 dark:text-dark-1000">
|
||||||
|
New workspace
|
||||||
|
</h2>
|
||||||
<button
|
<button
|
||||||
className="rounded p-1 hover:bg-dark-300 focus:outline-none"
|
className="rounded p-1 hover:bg-light-200 focus:outline-none dark:hover:bg-dark-300"
|
||||||
onClick={() => closeModal()}
|
onClick={() => closeModal()}
|
||||||
>
|
>
|
||||||
<HiXMark size={18} className="text-dark-900" />
|
<HiXMark size={18} className="text-light-900 dark:text-dark-900" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -52,20 +61,20 @@ export function NewWorkspaceForm() {
|
|||||||
>
|
>
|
||||||
<Form>
|
<Form>
|
||||||
<label
|
<label
|
||||||
htmlFor="name"
|
htmlFor="workspace-name"
|
||||||
className="block pb-2 text-sm font-normal leading-6 text-dark-1000"
|
className="block pb-2 text-sm font-normal leading-6 text-neutral-900 dark:text-dark-1000"
|
||||||
>
|
>
|
||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
<Field
|
<Field
|
||||||
id="name"
|
id="workspace-name"
|
||||||
name="name"
|
name="name"
|
||||||
className="block w-full rounded-md border-0 bg-dark-300 bg-white/5 py-1.5 text-dark-1000 shadow-sm ring-1 ring-inset ring-dark-700 focus:ring-2 focus:ring-inset focus:ring-dark-700 sm:text-sm sm:leading-6"
|
className="block w-full rounded-md border-0 bg-dark-300 bg-white/5 py-1.5 text-neutral-900 shadow-sm ring-1 ring-inset ring-light-600 focus:ring-2 focus:ring-inset focus:ring-light-600 dark:text-dark-1000 dark:ring-dark-700 dark:focus:ring-dark-700 sm:text-sm sm:leading-6"
|
||||||
/>
|
/>
|
||||||
<div className="mt-5 sm:mt-6">
|
<div className="mt-5 sm:mt-6">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="inline-flex w-full justify-center rounded-md bg-dark-1000 px-3 py-2 text-sm font-semibold text-dark-50 shadow-sm focus-visible:outline-none"
|
className="inline-flex w-full justify-center rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none dark:bg-dark-1000 dark:text-dark-50"
|
||||||
>
|
>
|
||||||
Create workspace
|
Create workspace
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export default function SideNavigation({ user }: SideNavigationProps) {
|
|||||||
<li key={item.name}>
|
<li key={item.name}>
|
||||||
<ReactiveButton
|
<ReactiveButton
|
||||||
href={item.href}
|
href={item.href}
|
||||||
current={pathname.includes(item.href)}
|
current={pathname?.includes(item.href)}
|
||||||
name={item.name}
|
name={item.name}
|
||||||
json={item.icon}
|
json={item.icon}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { generateUID } from "~/utils/generateUID";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createTRPCRouter,
|
createTRPCRouter,
|
||||||
@@ -10,7 +9,7 @@ export const authRouter = createTRPCRouter({
|
|||||||
login: publicProcedure
|
login: publicProcedure
|
||||||
.input(z.object({ email: z.string() }))
|
.input(z.object({ email: z.string() }))
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const { data, error } = await ctx.supabase.auth.signInWithOtp({
|
const { data } = await ctx.supabase.auth.signInWithOtp({
|
||||||
email: input.email,
|
email: input.email,
|
||||||
options: {
|
options: {
|
||||||
emailRedirectTo: '/boards',
|
emailRedirectTo: '/boards',
|
||||||
|
|||||||
@@ -107,11 +107,9 @@ export const boardRouter = createTRPCRouter({
|
|||||||
.limit(1)
|
.limit(1)
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
console.log({ workspace })
|
|
||||||
|
|
||||||
if (!workspace.data) return;
|
if (!workspace.data) return;
|
||||||
|
|
||||||
const { data, error } = await ctx.supabase
|
const { data } = await ctx.supabase
|
||||||
.from('board')
|
.from('board')
|
||||||
.insert({
|
.insert({
|
||||||
publicId: generateUID(),
|
publicId: generateUID(),
|
||||||
@@ -168,23 +166,26 @@ export const boardRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const listIds = board.data.lists.map((list) => list.id);
|
const listIds = board.data.lists.map((list) => list.id);
|
||||||
|
|
||||||
const deletedAt = new Date().toString();
|
const deletedAt = new Date().toISOString();
|
||||||
|
|
||||||
await ctx.supabase
|
await ctx.supabase
|
||||||
.from('board')
|
.from('board')
|
||||||
.update({ deletedAt, deletedBy: userId })
|
.update({ deletedAt, deletedBy: userId })
|
||||||
.eq('id', board.data.id);
|
.eq('id', board.data.id)
|
||||||
|
.is('deletedAt', null);
|
||||||
|
|
||||||
if (listIds.length) {
|
if (listIds.length) {
|
||||||
await ctx.supabase
|
await ctx.supabase
|
||||||
.from('list')
|
.from('list')
|
||||||
.update({ deletedAt, deletedBy: userId })
|
.update({ deletedAt, deletedBy: userId })
|
||||||
.eq('boardId', board.data.id);
|
.eq('boardId', board.data.id)
|
||||||
|
.is('deletedAt', null);
|
||||||
|
|
||||||
await ctx.supabase
|
await ctx.supabase
|
||||||
.from('card')
|
.from('card')
|
||||||
.update({ deletedAt, deletedBy: userId })
|
.update({ deletedAt, deletedBy: userId })
|
||||||
.in('listId', listIds);
|
.in('listId', listIds)
|
||||||
|
.is('deletedAt', null);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { and, eq, isNull } from "drizzle-orm";
|
|
||||||
|
|
||||||
import { cards, cardsToLabels, labels } from "~/server/db/schema";
|
|
||||||
import { generateUID } from "~/utils/generateUID";
|
import { generateUID } from "~/utils/generateUID";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -18,41 +15,43 @@ export const labelRouter = createTRPCRouter({
|
|||||||
colourCode: z.string().length(7),
|
colourCode: z.string().length(7),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.mutation(({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const userId = ctx.session?.user.id;
|
const userId = ctx.user?.id;
|
||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
return ctx.db.transaction(async (tx) => {
|
const card = await ctx.supabase
|
||||||
const card = await tx.query.cards.findFirst({
|
.from('card')
|
||||||
where: and(eq(cards.publicId, input.cardPublicId), isNull(cards.deletedAt)),
|
.select(`id, list (boardId)`)
|
||||||
with: {
|
.eq('publicId', input.cardPublicId)
|
||||||
list: {
|
.is('deletedAt', null)
|
||||||
with: {
|
.limit(1)
|
||||||
board: true
|
.single();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!card) return;
|
if (!card.data?.list) return;
|
||||||
|
|
||||||
const newLabel = await tx.insert(labels).values({
|
const newLabel = await ctx.supabase
|
||||||
|
.from('label')
|
||||||
|
.insert({
|
||||||
publicId: generateUID(),
|
publicId: generateUID(),
|
||||||
name: input.name,
|
name: input.name,
|
||||||
colourCode: input.colourCode,
|
colourCode: input.colourCode,
|
||||||
createdBy: userId,
|
createdBy: userId,
|
||||||
boardId: card.list.boardId,
|
boardId: card.data.list.boardId,
|
||||||
}).returning({ id: labels.id });
|
})
|
||||||
|
.select(`id`)
|
||||||
|
.limit(1)
|
||||||
|
.single();
|
||||||
|
|
||||||
const newLabelId = newLabel[0]?.id
|
if (!newLabel.data) return;
|
||||||
|
|
||||||
if (!newLabelId) return;
|
await ctx.supabase
|
||||||
|
.from('_card_labels')
|
||||||
|
.insert({
|
||||||
|
cardId: card.data.id,
|
||||||
|
labelId: newLabel.data.id,
|
||||||
|
})
|
||||||
|
|
||||||
return tx.insert(cardsToLabels).values({
|
return newLabel.data;
|
||||||
cardId: card.id,
|
|
||||||
labelId: newLabelId,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { and, desc, eq, sql, isNull } from "drizzle-orm";
|
|
||||||
|
|
||||||
import { boards, cards, lists } from "~/server/db/schema";
|
|
||||||
import { generateUID } from "~/utils/generateUID";
|
import { generateUID } from "~/utils/generateUID";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -17,37 +14,39 @@ export const listRouter = createTRPCRouter({
|
|||||||
boardPublicId: z.string().min(12)
|
boardPublicId: z.string().min(12)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.mutation(({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const userId = ctx.session?.user.id;
|
const userId = ctx.user?.id;
|
||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
return ctx.db.transaction(async (tx) => {
|
const board = await ctx.supabase
|
||||||
const board = await tx.query.boards.findFirst({
|
.from('board')
|
||||||
where: eq(boards.publicId, input.boardPublicId),
|
.select(`id, lists:list (index)`)
|
||||||
columns: {
|
.eq('publicId', input.boardPublicId)
|
||||||
id: true
|
.order('index', { foreignTable: 'list', ascending: false })
|
||||||
}
|
.is('list.deletedAt', null)
|
||||||
});
|
.limit(1)
|
||||||
|
.single();
|
||||||
|
|
||||||
if (!board) return;
|
if (!board.data) return;
|
||||||
|
|
||||||
const latestList = await tx.query.lists.findFirst({
|
const latestListIndex = board.data.lists[0]?.index
|
||||||
where: eq(lists.boardId, board.id),
|
|
||||||
columns: {
|
|
||||||
index: true
|
|
||||||
},
|
|
||||||
orderBy: desc(lists.index)
|
|
||||||
});
|
|
||||||
|
|
||||||
return tx.insert(lists).values({
|
const { data } = await ctx.supabase
|
||||||
|
.from('list')
|
||||||
|
.insert({
|
||||||
publicId: generateUID(),
|
publicId: generateUID(),
|
||||||
name: input.name,
|
name: input.name,
|
||||||
createdBy: userId,
|
createdBy: userId,
|
||||||
boardId: board.id,
|
boardId: board.data.id,
|
||||||
index: latestList ? latestList.index + 1 : 0
|
index: latestListIndex ? latestListIndex + 1 : 0
|
||||||
});
|
})
|
||||||
})
|
.select(`
|
||||||
|
publicId,
|
||||||
|
name
|
||||||
|
`);
|
||||||
|
|
||||||
|
return data;
|
||||||
}),
|
}),
|
||||||
reorder: publicProcedure
|
reorder: publicProcedure
|
||||||
.input(
|
.input(
|
||||||
@@ -57,52 +56,70 @@ export const listRouter = createTRPCRouter({
|
|||||||
currentIndex: z.number(),
|
currentIndex: z.number(),
|
||||||
newIndex: z.number(),
|
newIndex: z.number(),
|
||||||
}))
|
}))
|
||||||
.mutation(({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const userId = ctx.session?.user.id;
|
const userId = ctx.user?.id;
|
||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
return ctx.db.transaction(async (tx) => {
|
const list = await ctx.supabase
|
||||||
const [list] = await tx.select({ id: lists.id, boardId: lists.boardId }).from(lists).where(eq(lists.publicId, input.listId))
|
.from('list')
|
||||||
|
.select(`id, boardId`)
|
||||||
|
.eq('publicId', input.listId)
|
||||||
|
.limit(1)
|
||||||
|
.single();
|
||||||
|
|
||||||
if (!list) return;
|
if (!list?.data) return;
|
||||||
|
|
||||||
await tx.execute(sql`
|
const { data } = await ctx.supabase
|
||||||
UPDATE ${lists}
|
.rpc('reorder_list', {
|
||||||
SET index =
|
board_id: list.data.boardId,
|
||||||
CASE
|
list_id: list.data.id,
|
||||||
WHEN ${lists.index} = ${input.currentIndex} AND ${lists.id} = ${list.id} THEN ${input.newIndex}
|
current_index: input.currentIndex,
|
||||||
WHEN ${input.currentIndex} < ${input.newIndex} AND ${lists.index} > ${input.currentIndex} AND ${lists.index} <= ${input.newIndex} THEN ${lists.index} - 1
|
new_index: input.newIndex,
|
||||||
WHEN ${input.currentIndex} > ${input.newIndex} AND ${lists.index} >= ${input.newIndex} AND ${lists.index} < ${input.currentIndex} THEN ${lists.index} + 1
|
})
|
||||||
ELSE ${lists.index}
|
|
||||||
END
|
return data;
|
||||||
WHERE ${lists.boardId} = ${list.boardId};
|
|
||||||
`);
|
|
||||||
})
|
|
||||||
}),
|
}),
|
||||||
delete: publicProcedure
|
delete: publicProcedure
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
listPublicId: z.string().min(12),
|
listPublicId: z.string().min(12),
|
||||||
}))
|
}))
|
||||||
.mutation(({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const userId = ctx.session?.user.id;
|
const userId = ctx.user?.id;
|
||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
return ctx.db.transaction(async (tx) => {
|
const list = await ctx.supabase
|
||||||
const list = await tx.query.lists.findFirst({
|
.from('list')
|
||||||
where: eq(lists.publicId, input.listPublicId),
|
.select(`id, boardId, index`)
|
||||||
|
.eq('publicId', input.listPublicId)
|
||||||
|
.limit(1)
|
||||||
|
.single();
|
||||||
|
|
||||||
|
if (!list.data) return;
|
||||||
|
|
||||||
|
const deletedAt = new Date().toISOString();
|
||||||
|
|
||||||
|
await ctx.supabase
|
||||||
|
.from('list')
|
||||||
|
.update({ deletedAt, deletedBy: userId })
|
||||||
|
.eq('id', list.data.id)
|
||||||
|
.is('deletedAt', null);
|
||||||
|
|
||||||
|
await ctx.supabase
|
||||||
|
.from('card')
|
||||||
|
.update({ deletedAt, deletedBy: userId })
|
||||||
|
.eq('listId', list.data.id)
|
||||||
|
.is('deletedAt', null);
|
||||||
|
|
||||||
|
const { data } = await ctx.supabase
|
||||||
|
.rpc('shift_list_index', {
|
||||||
|
board_id: list.data.boardId,
|
||||||
|
list_index: list.data.index
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!list) return;
|
return data;
|
||||||
|
|
||||||
await tx.update(lists).set({ deletedAt: new Date(), deletedBy: userId}).where(eq(lists.id, list.id));
|
|
||||||
|
|
||||||
await tx.update(cards).set({ deletedAt: new Date(), deletedBy: userId}).where(eq(cards.listId, list.id));
|
|
||||||
|
|
||||||
await tx.execute(sql`UPDATE ${lists} SET ${lists.index} = ${lists.index} - 1 WHERE ${lists.boardId} = ${list.boardId} AND ${lists.index} > ${list.index} AND ${lists.deletedAt} IS NULL;`);
|
|
||||||
})
|
|
||||||
}),
|
}),
|
||||||
update: publicProcedure
|
update: publicProcedure
|
||||||
.input(
|
.input(
|
||||||
@@ -110,11 +127,18 @@ export const listRouter = createTRPCRouter({
|
|||||||
listPublicId: z.string().min(12),
|
listPublicId: z.string().min(12),
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
}))
|
}))
|
||||||
.mutation(({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const userId = ctx.session?.user.id;
|
const userId = ctx.user?.id;
|
||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
return ctx.db.update(lists).set({ name: input.name }).where(and(eq(lists.publicId, input.listPublicId), isNull(lists.deletedAt)));
|
const { data } = await ctx.supabase
|
||||||
|
.from('list')
|
||||||
|
.update({ name: input.name })
|
||||||
|
.eq('publicId', input.listPublicId)
|
||||||
|
.is('deletedAt', null)
|
||||||
|
.select(`publicId, name`);
|
||||||
|
|
||||||
|
return data;
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -12,56 +12,52 @@ import {
|
|||||||
|
|
||||||
export const workspaceRouter = createTRPCRouter({
|
export const workspaceRouter = createTRPCRouter({
|
||||||
all: publicProcedure
|
all: publicProcedure
|
||||||
.query(({ ctx }) => {
|
.query(async ({ ctx }) => {
|
||||||
const userId = ctx.session?.user.id;
|
const userId = ctx.user?.id;
|
||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
return ctx.db.query.workspaceMembers.findMany({
|
const { data } = await ctx.supabase
|
||||||
where: and(eq(workspaceMembers.userId, userId), isNull(workspaceMembers.deletedAt)),
|
.from('workspace_members')
|
||||||
columns: {
|
.select(`
|
||||||
role: true,
|
role,
|
||||||
},
|
workspace (
|
||||||
with: {
|
publicId,
|
||||||
workspace: {
|
name
|
||||||
columns: {
|
)
|
||||||
publicId: true,
|
`)
|
||||||
name: true
|
.eq('userId', userId)
|
||||||
}
|
.is('deletedAt', null);
|
||||||
}
|
|
||||||
}
|
return data;
|
||||||
});
|
|
||||||
}),
|
}),
|
||||||
byId: publicProcedure
|
byId: publicProcedure
|
||||||
.input(z.object({ publicId: z.string().min(12) }))
|
.input(z.object({ publicId: z.string().min(12) }))
|
||||||
.query(({ ctx, input }) => {
|
.query(async ({ ctx, input }) => {
|
||||||
const userId = ctx.session?.user.id;
|
const userId = ctx.user?.id;
|
||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
return ctx.db.query.workspaces.findFirst({
|
const { data, error } = await ctx.supabase
|
||||||
where: and(eq(workspaces.publicId, input.publicId), isNull(workspaces.deletedAt)),
|
.from('workspace')
|
||||||
columns: {
|
.select(`
|
||||||
publicId: true,
|
publicId,
|
||||||
},
|
members: workspace_members (
|
||||||
with: {
|
publicId,
|
||||||
members: {
|
role,
|
||||||
columns: {
|
user (
|
||||||
publicId: true,
|
id,
|
||||||
role: true,
|
name,
|
||||||
},
|
email
|
||||||
with: {
|
)
|
||||||
user: {
|
)
|
||||||
columns: {
|
`)
|
||||||
id: true,
|
.eq('publicId', input.publicId)
|
||||||
name: true,
|
.is('deletedAt', null)
|
||||||
email: true,
|
.limit(1)
|
||||||
}
|
.single();
|
||||||
}
|
|
||||||
}
|
return data;
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}),
|
}),
|
||||||
create: publicProcedure
|
create: publicProcedure
|
||||||
.input(
|
.input(
|
||||||
@@ -70,35 +66,47 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const userId = ctx.session?.user.id;
|
const userId = ctx.user?.id;
|
||||||
|
|
||||||
|
|
||||||
|
console.log('>>> here <<<')
|
||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
const workspace = await ctx.db.insert(workspaces).values({
|
const workspace = await ctx.supabase
|
||||||
publicId: generateUID(),
|
.from('workspace')
|
||||||
name: input.name,
|
.insert({
|
||||||
slug: input.name.toLowerCase(),
|
publicId: generateUID(),
|
||||||
createdBy: userId,
|
name: input.name,
|
||||||
}).returning({ id: workspaces.id });
|
slug: input.name.toLowerCase(),
|
||||||
|
createdBy: userId,
|
||||||
|
})
|
||||||
|
.select(`
|
||||||
|
id,
|
||||||
|
publicId,
|
||||||
|
name
|
||||||
|
`)
|
||||||
|
.limit(1)
|
||||||
|
.single()
|
||||||
|
|
||||||
const workspaceId = workspace[0]?.id;
|
const newWorkspaceId = workspace.data?.id
|
||||||
|
|
||||||
if (!workspaceId) return;
|
if (!newWorkspaceId) return;
|
||||||
|
|
||||||
await ctx.db.insert(workspaceMembers).values({
|
await ctx.supabase
|
||||||
publicId: generateUID(),
|
.from('workspace_members')
|
||||||
userId,
|
.insert({
|
||||||
workspaceId: workspaceId,
|
publicId: generateUID(),
|
||||||
createdBy: userId,
|
userId,
|
||||||
role: 'admin'
|
workspaceId: newWorkspaceId,
|
||||||
})
|
createdBy: userId,
|
||||||
|
role: 'admin'
|
||||||
|
})
|
||||||
|
|
||||||
return ctx.db.query.workspaces.findFirst({
|
const newWorkspace = { ...workspace.data };
|
||||||
where: eq(workspaces.id, workspaceId),
|
|
||||||
columns: {
|
delete newWorkspace.id;
|
||||||
publicId: true,
|
|
||||||
name: true,
|
return newWorkspace;
|
||||||
},
|
|
||||||
});
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -600,7 +600,22 @@ export type Database = {
|
|||||||
[_ in never]: never
|
[_ in never]: never
|
||||||
}
|
}
|
||||||
Functions: {
|
Functions: {
|
||||||
[_ in never]: never
|
reorder_list: {
|
||||||
|
Args: {
|
||||||
|
board_id: number
|
||||||
|
list_id: number
|
||||||
|
current_index: number
|
||||||
|
new_index: number
|
||||||
|
}
|
||||||
|
Returns: undefined
|
||||||
|
}
|
||||||
|
shift_list_index: {
|
||||||
|
Args: {
|
||||||
|
board_id: number
|
||||||
|
list_index: number
|
||||||
|
}
|
||||||
|
Returns: undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Enums: {
|
Enums: {
|
||||||
role: "admin" | "member" | "guest"
|
role: "admin" | "member" | "guest"
|
||||||
|
|||||||
@@ -86,17 +86,20 @@ export default function BoardPage() {
|
|||||||
enableReinitialize: true,
|
enableReinitialize: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!boardId) return <></>;
|
const { data, isSuccess } = api.board.byId.useQuery(
|
||||||
|
{ id: boardId ?? "" },
|
||||||
api.board.byId.useQuery(
|
|
||||||
{ id: boardId },
|
|
||||||
{
|
{
|
||||||
onSuccess: (data) => {
|
enabled: !!boardId,
|
||||||
if (data) setBoardData(data);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isSuccess && data) {
|
||||||
|
console.log({ data });
|
||||||
|
setBoardData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!boardId) return <></>;
|
||||||
|
|
||||||
const openNewListForm = (publicBoardId: string) => {
|
const openNewListForm = (publicBoardId: string) => {
|
||||||
openModal("NEW_LIST");
|
openModal("NEW_LIST");
|
||||||
setSelectedPublicListId(publicBoardId);
|
setSelectedPublicListId(publicBoardId);
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
CREATE OR REPLACE FUNCTION reorder_list(board_id BIGINT, list_id BIGINT, current_index INT, new_index INT)
|
||||||
|
RETURNS VOID
|
||||||
|
LANGUAGE SQL
|
||||||
|
AS $$
|
||||||
|
UPDATE list
|
||||||
|
SET index =
|
||||||
|
CASE
|
||||||
|
WHEN index = current_index AND id = list_id THEN new_index
|
||||||
|
WHEN current_index < new_index AND index > current_index AND index <= new_index THEN index - 1
|
||||||
|
WHEN current_index > new_index AND index >= new_index AND index < current_index THEN index + 1
|
||||||
|
ELSE index
|
||||||
|
END
|
||||||
|
WHERE "boardId" = board_id;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION shift_list_index(board_id BIGINT, list_index INT)
|
||||||
|
RETURNS VOID
|
||||||
|
LANGUAGE SQL
|
||||||
|
AS $$
|
||||||
|
UPDATE list
|
||||||
|
SET index = index - 1
|
||||||
|
WHERE "boardId" = board_id AND index > list_index AND "deletedAt" IS NULL;
|
||||||
|
$$;
|
||||||
Reference in New Issue
Block a user