feat: update card and title description
This commit is contained in:
5596
package-lock.json
generated
Normal file
5596
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -29,6 +29,7 @@
|
|||||||
"next-auth": "^4.24.4",
|
"next-auth": "^4.24.4",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
|
"react-contenteditable": "^3.3.7",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-icons": "^4.11.0",
|
"react-icons": "^4.11.0",
|
||||||
"react-lottie-player": "^1.5.5",
|
"react-lottie-player": "^1.5.5",
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ export default function BoardPage() {
|
|||||||
className="-mr-0.5 h-5 w-5"
|
className="-mr-0.5 h-5 w-5"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
New
|
New list
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export function Boards() {
|
|||||||
if (data?.length === 0) return <></>;
|
if (data?.length === 0) return <></>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
{data?.map((board) => {
|
{data?.map((board) => {
|
||||||
return (
|
return (
|
||||||
<Link key={board.publicId} href={`boards/${board.publicId}`}>
|
<Link key={board.publicId} href={`boards/${board.publicId}`}>
|
||||||
@@ -20,6 +20,6 @@ export function Boards() {
|
|||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,84 +1,75 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { HiOutlinePlusSmall } from "react-icons/hi2";
|
import { useFormik } from "formik";
|
||||||
import { Formik, Form, Field, type FieldProps } from "formik";
|
import ContentEditable from "react-contenteditable";
|
||||||
|
|
||||||
import { api } from "~/trpc/react";
|
import { api } from "~/trpc/react";
|
||||||
|
|
||||||
interface FormValues {
|
interface FormValues {
|
||||||
cardId: string;
|
cardId: string;
|
||||||
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CardPage() {
|
export default function CardPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
|
||||||
const cardId = params?.id?.length && params.id[0];
|
const cardId = params?.id?.length ? params.id[0] : null;
|
||||||
|
|
||||||
|
const { data } = api.card.byId.useQuery({ id: cardId ?? "" });
|
||||||
|
|
||||||
|
const updateCard = api.card.update.useMutation();
|
||||||
|
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: {
|
||||||
|
cardId: cardId ?? "",
|
||||||
|
title: data?.title ? data.title : "",
|
||||||
|
description: data?.description ? data.description : "",
|
||||||
|
},
|
||||||
|
onSubmit: (values: FormValues) => {
|
||||||
|
updateCard.mutate({
|
||||||
|
cardId: values.cardId,
|
||||||
|
title: values.title,
|
||||||
|
description: values.description,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
enableReinitialize: true,
|
||||||
|
});
|
||||||
|
|
||||||
if (!cardId) return <></>;
|
if (!cardId) return <></>;
|
||||||
|
|
||||||
const { data } = api.card.byId.useQuery({ id: cardId });
|
|
||||||
|
|
||||||
const updateCard = api.card.updateDescription.useMutation();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-8 flex w-full justify-between">
|
<div className="mb-8 flex w-full justify-between">
|
||||||
<h1 className="font-medium tracking-tight text-dark-1000 sm:text-[1.2rem]">
|
<form onSubmit={formik.handleSubmit} className="w-full space-y-6">
|
||||||
{data?.title}
|
<div className="mt-2">
|
||||||
</h1>
|
<input
|
||||||
<div>
|
type="text"
|
||||||
<button
|
id="title"
|
||||||
type="button"
|
name="title"
|
||||||
className="inline-flex items-center gap-x-1.5 rounded-md bg-dark-1000 px-3 py-2 text-sm font-semibold text-dark-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
|
value={formik.values.title}
|
||||||
>
|
onChange={formik.handleChange}
|
||||||
<HiOutlinePlusSmall
|
onBlur={formik.submitForm}
|
||||||
className="-mr-0.5 h-5 w-5"
|
className="block w-full border-0 bg-transparent p-0 py-1.5 font-medium tracking-tight text-dark-1000 focus:ring-0 sm:text-[1.2rem] sm:leading-6"
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
/>
|
||||||
New
|
</div>
|
||||||
</button>
|
</form>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-8 flex w-full max-w-2xl justify-between">
|
<div className="mb-8 flex w-full max-w-2xl justify-between">
|
||||||
<Formik
|
<form onSubmit={formik.handleSubmit} className="w-full space-y-6">
|
||||||
initialValues={{
|
<div className="mt-2">
|
||||||
cardId,
|
<ContentEditable
|
||||||
description: data?.description ? data.description : "",
|
html={formik.values.description || "Add description..."}
|
||||||
}}
|
disabled={false}
|
||||||
onSubmit={(values: FormValues) => {
|
onChange={(e) =>
|
||||||
updateCard.mutate({
|
formik.setFieldValue("description", e.target.value)
|
||||||
cardId: values.cardId,
|
}
|
||||||
description: values.description,
|
onBlur={formik.submitForm}
|
||||||
});
|
className="block w-full border-0 bg-transparent py-1.5 text-dark-1000 focus-visible:outline-none sm:text-sm sm:leading-6"
|
||||||
}}
|
/>
|
||||||
enableReinitialize
|
</div>
|
||||||
>
|
</form>
|
||||||
<Form className="w-full space-y-6">
|
|
||||||
<div>
|
|
||||||
<div className="mt-2">
|
|
||||||
<Field
|
|
||||||
id="description"
|
|
||||||
name="description"
|
|
||||||
render={({ field, form }: FieldProps) => (
|
|
||||||
<div
|
|
||||||
onBlur={() => form.submitForm()}
|
|
||||||
onInput={async (e) => {
|
|
||||||
const { innerText } = e.target as HTMLDivElement;
|
|
||||||
await form.setFieldValue("description", innerText);
|
|
||||||
}}
|
|
||||||
contentEditable
|
|
||||||
className="block w-full border-0 bg-transparent py-1.5 text-dark-1000 focus-visible:outline-none sm:text-sm sm:leading-6"
|
|
||||||
>
|
|
||||||
{field.value || "Add description..."}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
</Formik>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
const refetchBoard = () =>
|
const refetchBoard = () =>
|
||||||
utils.board.byId.refetch({ id: boardData.publicId });
|
utils.board.byId.refetch({ id: boardData.publicId });
|
||||||
|
|
||||||
const updateCardMutation = api.card.update.useMutation({
|
const updateCardMutation = api.card.reorder.useMutation({
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
try {
|
try {
|
||||||
await refetchBoard();
|
await refetchBoard();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export const boardRouter = createTRPCRouter({
|
|||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
return ctx.db.query.boards.findMany({
|
return ctx.db.query.boards.findMany({
|
||||||
|
where: eq(boards.createdBy, userId),
|
||||||
columns: {
|
columns: {
|
||||||
publicId: true,
|
publicId: true,
|
||||||
name: true,
|
name: true,
|
||||||
|
|||||||
@@ -58,10 +58,11 @@ export const cardRouter = createTRPCRouter({
|
|||||||
where: eq(cards.publicId, input.id),
|
where: eq(cards.publicId, input.id),
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
updateDescription: publicProcedure
|
update: publicProcedure
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
cardId: z.string(),
|
cardId: z.string().min(12),
|
||||||
|
title: z.string().min(1),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
}))
|
}))
|
||||||
.mutation(({ ctx, input }) => {
|
.mutation(({ ctx, input }) => {
|
||||||
@@ -69,9 +70,9 @@ export const cardRouter = createTRPCRouter({
|
|||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
return ctx.db.update(cards).set({ description: input.description}).where(eq(cards.publicId, input.cardId));
|
return ctx.db.update(cards).set({ title: input.title, description: input.description }).where(eq(cards.publicId, input.cardId));
|
||||||
}),
|
}),
|
||||||
update: publicProcedure
|
reorder: publicProcedure
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
cardId: z.string().min(12),
|
cardId: z.string().min(12),
|
||||||
|
|||||||
Reference in New Issue
Block a user