Small changes to label form
This commit is contained in:
parent
b103b5418b
commit
0802e36796
@ -0,0 +1,3 @@
|
||||
2024-11-18T16:54:25.722Z error: Authentication error. User: "ryan@pandu.ski", Message: "no such table: user", IP-Address: "::ffff:127.0.0.1"
|
||||
2024-11-18T16:54:31.817Z error: Authentication error. User: "ryan@ryanpandya.com", Message: "no such table: user", IP-Address: "::ffff:127.0.0.1"
|
||||
2024-11-18T16:54:43.805Z error: Authentication error. User: "ryan@ryanpandya.com", Message: "no such table: user", IP-Address: "::ffff:127.0.0.1"
|
||||
@ -34,6 +34,7 @@ import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { zLabelSchema } from "@lifetracker/shared/types/labels";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
|
||||
type CreateLabelSchema = z.infer<typeof zLabelSchema>;
|
||||
|
||||
@ -46,13 +47,6 @@ export default function AddLabelDialog({
|
||||
const [isOpen, onOpenChange] = useState(false);
|
||||
const form = useForm<CreateLabelSchema>({
|
||||
resolver: zodResolver(zLabelSchema),
|
||||
defaultValues: {
|
||||
id: "69",
|
||||
name: "Fuckdicks",
|
||||
code: 420,
|
||||
description: "This shit sucks",
|
||||
color: "#004400",
|
||||
},
|
||||
});
|
||||
const { mutate, isPending } = api.labels.createLabel.useMutation({
|
||||
onSuccess: () => {
|
||||
@ -87,17 +81,36 @@ export default function AddLabelDialog({
|
||||
<DialogTrigger asChild>{children}</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Add User</DialogTitle>
|
||||
<DialogTitle>Create Label</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit((val) => mutate(val))}>
|
||||
<div className="flex w-full flex-col space-y-2">
|
||||
<div style={{ display: "grid", gridTemplateColumns: "5em 1fr 75px", gap: "10px" }}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="code"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
{/* <FormLabel>Code</FormLabel> */}
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Code"
|
||||
{...field}
|
||||
className="w-full rounded border p-2"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
{/* <FormLabel>Name</FormLabel> */}
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
@ -112,14 +125,14 @@ export default function AddLabelDialog({
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="code"
|
||||
name="color"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Code</FormLabel>
|
||||
{/* <FormLabel>Color</FormLabel> */}
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Code"
|
||||
type="text"
|
||||
placeholder="Color"
|
||||
{...field}
|
||||
className="w-full rounded border p-2"
|
||||
/>
|
||||
@ -128,15 +141,15 @@ export default function AddLabelDialog({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="description"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Description</FormLabel>
|
||||
{/* <FormLabel>Description</FormLabel> */}
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
<Textarea
|
||||
placeholder="Description"
|
||||
{...field}
|
||||
className="w-full rounded border p-2"
|
||||
@ -146,24 +159,6 @@ export default function AddLabelDialog({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="color"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Color, hope you like hex codes</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Color"
|
||||
{...field}
|
||||
className="w-full rounded border p-2"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<DialogFooter className="sm:justify-end">
|
||||
<DialogClose asChild>
|
||||
<Button type="button" variant="secondary">
|
||||
|
||||
@ -3,26 +3,26 @@ import { ActionButton } from "@/components/ui/action-button";
|
||||
import ActionConfirmingDialog from "@/components/ui/action-confirming-dialog";
|
||||
import { toast } from "@/components/ui/use-toast";
|
||||
|
||||
import { useDeleteTag } from "@hoarder/shared-react/hooks/tags";
|
||||
import { useDeleteLabel } from "@lifetracker/shared-react/hooks/labels";
|
||||
|
||||
export default function DeleteTagConfirmationDialog({
|
||||
tag,
|
||||
export default function DeleteLabelConfirmationDialog({
|
||||
label,
|
||||
open,
|
||||
setOpen,
|
||||
}: {
|
||||
tag: { id: string; name: string };
|
||||
label: { id: string; code: number; name: string };
|
||||
open?: boolean;
|
||||
setOpen?: (v: boolean) => void;
|
||||
}) {
|
||||
const currentPath = usePathname();
|
||||
const router = useRouter();
|
||||
const { mutate: deleteTag, isPending } = useDeleteTag({
|
||||
const { mutate: deleteTag, isPending } = useDeleteLabel({
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
description: `Tag "${tag.name}" has been deleted!`,
|
||||
description: `Label "${label.name}" has been deleted!`,
|
||||
});
|
||||
if (currentPath.includes(tag.id)) {
|
||||
router.push("/dashboard/tags");
|
||||
if (currentPath.includes(label.code)) {
|
||||
router.push("/dashboard/labels");
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
@ -36,8 +36,8 @@ export default function DeleteTagConfirmationDialog({
|
||||
<ActionConfirmingDialog
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
title={`Delete ${tag.name}?`}
|
||||
description={`Are you sure you want to delete the tag "${tag.name}"?`}
|
||||
title={`Delete ${label.name}?`}
|
||||
description={`Are you sure you want to delete the label "${label.name}"?`}
|
||||
actionButton={(setDialogOpen) => (
|
||||
<ActionButton
|
||||
type="button"
|
||||
@ -45,7 +45,7 @@ export default function DeleteTagConfirmationDialog({
|
||||
loading={isPending}
|
||||
onClick={() =>
|
||||
deleteTag(
|
||||
{ tagId: tag.id },
|
||||
{ labelId: label.id },
|
||||
{ onSuccess: () => setDialogOpen(false) },
|
||||
)
|
||||
}
|
||||
@ -17,12 +17,30 @@ import { Check, KeyRound, Pencil, Trash, FilePlus, X } from "lucide-react";
|
||||
import { useSession } from "next-auth/react";
|
||||
import AddLabelDialog from "./AddLabelDialog";
|
||||
import EditLabelDialog from "./EditLabelDialog";
|
||||
import DeleteLabelConfirmationDialog from "./DeleteLabelConfirmationDialog";
|
||||
|
||||
export default function LabelsView() {
|
||||
const { data: session } = useSession();
|
||||
const { data: labels } = api.labels.list.useQuery();
|
||||
const { data: labelStats } = api.labels.labelStats.useQuery();
|
||||
|
||||
const invalidateLabelList = api.useUtils().labels.list.invalidate;
|
||||
const { mutate: deleteLabel, isPending: isDeletionPending } =
|
||||
api.labels.delete.useMutation({
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
description: "Label deleted",
|
||||
});
|
||||
invalidateLabelList();
|
||||
},
|
||||
onError: (e) => {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
description: `Something went wrong: ${e.message}`,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const LabelsTable = ({ labels }) => (
|
||||
<Table>
|
||||
<TableHeader className="bg-gray-200">
|
||||
|
||||
@ -7,17 +7,19 @@ import path from "path";
|
||||
|
||||
import dbConfig from "./drizzle.config";
|
||||
|
||||
console.log("dbURL: ", dbConfig.dbCredentials.url);
|
||||
|
||||
const sqlite = new Database(dbConfig.dbCredentials.url);
|
||||
export const db = drizzle(sqlite, {
|
||||
schema,
|
||||
// logger: true
|
||||
logger: true
|
||||
});
|
||||
|
||||
export function getInMemoryDB(runMigrations: boolean) {
|
||||
const mem = new Database(":memory:");
|
||||
const db = drizzle(mem, { schema, logger: true });
|
||||
if (runMigrations) {
|
||||
migrate(db, { migrationsFolder: path.resolve(__dirname, "./drizzle") });
|
||||
migrate(db, { migrationsFolder: path.resolve(__dirname, "./migrations") });
|
||||
}
|
||||
return db;
|
||||
}
|
||||
50
packages/shared-react/hooks/labels.ts
Normal file
50
packages/shared-react/hooks/labels.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { api } from "../trpc";
|
||||
|
||||
export function useUpdateLabel(
|
||||
...opts: Parameters<typeof api.labels.update.useMutation>
|
||||
) {
|
||||
const apiUtils = api.useUtils();
|
||||
|
||||
return api.tags.update.useMutation({
|
||||
...opts[0],
|
||||
onSuccess: (res, req, meta) => {
|
||||
apiUtils.labels.list.invalidate();
|
||||
apiUtils.labels.get.invalidate({ labelId: res.id });
|
||||
// apiUtils.bookmarks.getBookmarks.invalidate({
|
||||
// labelId: res.id;
|
||||
|
||||
// TODO: Maybe we can only look at the cache and invalidate only affected bookmarks
|
||||
// apiUtils.bookmarks.getBookmark.invalidate();
|
||||
return opts[0]?.onSuccess?.(res, req, meta);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteLabel(
|
||||
...opts: Parameters<typeof api.labels.delete.useMutation>
|
||||
) {
|
||||
const apiUtils = api.useUtils();
|
||||
|
||||
return api.labels.delete.useMutation({
|
||||
...opts[0],
|
||||
onSuccess: (res, req, meta) => {
|
||||
apiUtils.labels.list.invalidate();
|
||||
// apiUtils.bookmarks.getBookmark.invalidate();
|
||||
return opts[0]?.onSuccess?.(res, req, meta);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteUnusedTags(
|
||||
...opts: Parameters<typeof api.tags.deleteUnused.useMutation>
|
||||
) {
|
||||
const apiUtils = api.useUtils();
|
||||
|
||||
return api.tags.deleteUnused.useMutation({
|
||||
...opts[0],
|
||||
onSuccess: (res, req, meta) => {
|
||||
apiUtils.tags.list.invalidate();
|
||||
return opts[0]?.onSuccess?.(res, req, meta);
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
import { api } from "../trpc";
|
||||
|
||||
export function useUpdateTag(
|
||||
...opts: Parameters<typeof api.tags.update.useMutation>
|
||||
) {
|
||||
const apiUtils = api.useUtils();
|
||||
|
||||
return api.tags.update.useMutation({
|
||||
...opts[0],
|
||||
onSuccess: (res, req, meta) => {
|
||||
apiUtils.tags.list.invalidate();
|
||||
apiUtils.tags.get.invalidate({ tagId: res.id });
|
||||
apiUtils.bookmarks.getBookmarks.invalidate({ tagId: res.id });
|
||||
|
||||
// TODO: Maybe we can only look at the cache and invalidate only affected bookmarks
|
||||
apiUtils.bookmarks.getBookmark.invalidate();
|
||||
return opts[0]?.onSuccess?.(res, req, meta);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useMergeTag(
|
||||
...opts: Parameters<typeof api.tags.merge.useMutation>
|
||||
) {
|
||||
const apiUtils = api.useUtils();
|
||||
|
||||
return api.tags.merge.useMutation({
|
||||
...opts[0],
|
||||
onSuccess: (res, req, meta) => {
|
||||
apiUtils.tags.list.invalidate();
|
||||
[res.mergedIntoTagId, ...res.deletedTags].forEach((tagId) => {
|
||||
apiUtils.tags.get.invalidate({ tagId });
|
||||
apiUtils.bookmarks.getBookmarks.invalidate({ tagId });
|
||||
});
|
||||
// TODO: Maybe we can only look at the cache and invalidate only affected bookmarks
|
||||
apiUtils.bookmarks.getBookmark.invalidate();
|
||||
return opts[0]?.onSuccess?.(res, req, meta);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteTag(
|
||||
...opts: Parameters<typeof api.tags.delete.useMutation>
|
||||
) {
|
||||
const apiUtils = api.useUtils();
|
||||
|
||||
return api.tags.delete.useMutation({
|
||||
...opts[0],
|
||||
onSuccess: (res, req, meta) => {
|
||||
apiUtils.tags.list.invalidate();
|
||||
apiUtils.bookmarks.getBookmark.invalidate();
|
||||
return opts[0]?.onSuccess?.(res, req, meta);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteUnusedTags(
|
||||
...opts: Parameters<typeof api.tags.deleteUnused.useMutation>
|
||||
) {
|
||||
const apiUtils = api.useUtils();
|
||||
|
||||
return api.tags.deleteUnused.useMutation({
|
||||
...opts[0],
|
||||
onSuccess: (res, req, meta) => {
|
||||
apiUtils.tags.list.invalidate();
|
||||
return opts[0]?.onSuccess?.(res, req, meta);
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -185,9 +185,6 @@ export const labelsAppRouter = router({
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
console.log(input);
|
||||
console.log(ctx);
|
||||
console.log("TEEEEEEEEEEEEEEEEEEEEEST\n\n\n\n\n");
|
||||
try {
|
||||
const res = await ctx.db
|
||||
.update(bookmarkTags)
|
||||
@ -238,4 +235,31 @@ export const labelsAppRouter = router({
|
||||
throw e;
|
||||
}
|
||||
}),
|
||||
delete: authedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
labelId: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
// const affectedBookmarks = await ctx.db
|
||||
// .select({
|
||||
// bookmarkId: tagsOnBookmarks.bookmarkId,
|
||||
// })
|
||||
// .from(tagsOnBookmarks)
|
||||
// .where(
|
||||
// and(
|
||||
// eq(tagsOnBookmarks.tagId, input.tagId),
|
||||
// // Tag ownership is checked in the ensureTagOwnership middleware
|
||||
// // eq(bookmarkTags.userId, ctx.user.id),
|
||||
// ),
|
||||
// );
|
||||
|
||||
const res = await ctx.db
|
||||
.delete(labels)
|
||||
.where(conditionFromInput(input, ctx.user.id));
|
||||
if (res.changes == 0) {
|
||||
throw new TRPCError({ code: "NOT_FOUND" });
|
||||
}
|
||||
}),
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user