diff --git a/package-lock.json b/package-lock.json index efcbce4..39d0327 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1046,9 +1046,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", - "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1083,9 +1083,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.30.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz", - "integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==", + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", + "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", "dev": true, "license": "MIT", "engines": { @@ -1119,19 +1119,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", - "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1669,16 +1656,16 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz", - "integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==", + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", "dev": true, "license": "MIT", "optional": true, "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.9.0" + "@tybys/wasm-util": "^0.10.0" } }, "node_modules/@next/env": { @@ -2179,9 +2166,9 @@ } }, "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", "dev": true, "license": "MIT", "optional": true, @@ -2239,9 +2226,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.6.tgz", - "integrity": "sha512-uYssdp9z5zH5GQ0L4zEJ2ZuavYsJwkozjiUzCRfGtaaQcyjAMJ34aP8idv61QlqTozu6kudyr6JMq9Chf09dfA==", + "version": "20.19.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.7.tgz", + "integrity": "sha512-1GM9z6BJOv86qkPvzh2i6VW5+VVrXxCLknfmTkWEqz+6DqosiY28XUWCTmBcJ0ACzKqx/iwdIREfo1fwExIlkA==", "dev": true, "license": "MIT", "dependencies": { @@ -3943,9 +3930,9 @@ } }, "node_modules/eslint": { - "version": "9.30.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz", - "integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==", + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz", + "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3953,9 +3940,9 @@ "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.0", - "@eslint/core": "^0.14.0", + "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.30.1", + "@eslint/js": "9.31.0", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", diff --git a/src/app/actions/auth.ts b/src/app/actions/auth.ts index 316a001..18acd1f 100644 --- a/src/app/actions/auth.ts +++ b/src/app/actions/auth.ts @@ -1,10 +1,8 @@ -"use server"; - -import { cookies } from "next/headers"; import { redirect } from "next/navigation"; -import { eq } from "drizzle-orm"; -import { db } from "@/lib/db"; +import { cookies } from "next/headers"; import { usersTable } from "@/lib/db/schema"; +import { db } from "@/lib/db"; +import { eq } from "drizzle-orm"; import jwt from "jsonwebtoken"; import bcrypt from "bcrypt"; @@ -82,6 +80,29 @@ export async function register(_prevState: unknown, formData: FormData) { redirect("/notes"); } +export async function getAuth() { + const cookieStore = await cookies(); + const token = cookieStore.get("session")?.value; + if (!token) { + return null; + } + + const decodedToken = jwt.decode(token) as jwt.JwtPayload; + const username = decodedToken.sub; + if (!username) { + return null; + } + + const users = await db.select() + .from(usersTable) + .where(eq(usersTable.username, username)); + if (users.length === 0) { + return null; + } + + return users[0]; +} + export async function logOut() { const cookieStore = await cookies(); cookieStore.delete("session"); diff --git a/src/app/actions/blocks.ts b/src/app/actions/blocks.ts deleted file mode 100644 index 4f31bf6..0000000 --- a/src/app/actions/blocks.ts +++ /dev/null @@ -1,42 +0,0 @@ -"use server"; - -import { revalidatePath } from "next/cache"; -import { eq, and } from "drizzle-orm"; -import { blocksTable, IBlock, INote } from "@/lib/db/schema"; -import { db } from "@/lib/db"; - -export async function createBlock(note: INote) { - await db - .insert(blocksTable) - .values({ noteId: note.id }); - - revalidatePath("/blocks/[id]"); -} - -export async function getBlocks(note: INote) { - return db.select() - .from(blocksTable) - .where(and(eq(blocksTable.noteId, note.id))); -} - -export async function updateBlockTag(block: IBlock, newTag: string) { - await db - .update(blocksTable) - .set({ tag: newTag }) - .where(eq(blocksTable.id, block.id)); -} - -export async function deleteBlock(block: IBlock) { - await db.delete(blocksTable) - .where(and(eq(blocksTable.id, block.id))); - - revalidatePath("/blocks/[id]"); -} - -export async function switchLock(block: IBlock) { - await db.update(blocksTable) - .set({ isLocked: !block.isLocked }) - .where(and(eq(blocksTable.id, block.id))); - - revalidatePath("/blocks/[id]"); -} diff --git a/src/app/actions/notes.ts b/src/app/actions/notes.ts deleted file mode 100644 index c5320b5..0000000 --- a/src/app/actions/notes.ts +++ /dev/null @@ -1,72 +0,0 @@ -"use server"; - -import { redirect } from "next/navigation"; -import { revalidatePath } from "next/cache"; -import { validate as uuidValidate } from "uuid"; -import { notesTable } from "@/lib/db/schema"; -import { getAuth } from "@/lib/auth"; -import { eq, and, desc } from "drizzle-orm"; -import { db } from "@/lib/db"; - -export async function createNote() { - const auth = await getAuth(); - if (!auth) { - redirect("/auth"); - } - - const notes = await db - .insert(notesTable) - .values({ authorId: auth.id }) - .returning({ id: notesTable.id }); - - redirect(`/notes/${notes[0].id}`); -} - -export async function getNotes(authorId: string) { - return db.select() - .from(notesTable) - .where(eq(notesTable.authorId, authorId)) - .orderBy(desc(notesTable.lastEdited)); -} - -export async function getNote(noteId: string) { - if (!uuidValidate(noteId)) { - return null; - } - - const auth = await getAuth(); - if (!auth) { - return null; - } - - const notes = await db.select() - .from(notesTable) - .where(and(eq(notesTable.id, noteId), eq(notesTable.authorId, auth.id))); - - if (notes.length === 0) { - return null; - } else { - return notes[0]; - } -} - -export async function deleteNote(noteId: string) { - if (!uuidValidate(noteId)) { - return null; - } - - const auth = await getAuth(); - if (!auth) { - return null; - } - - await db.delete(notesTable).where(eq(notesTable.id, noteId)); - revalidatePath("/notes"); -} - -export async function updateTitle(noteId: string, title: string) { - await db - .update(notesTable) - .set({ title }) - .where(eq(notesTable.id, noteId)); -} diff --git a/src/app/notes/[id]/page.tsx b/src/app/notes/[id]/page.tsx index 438da79..2bc2011 100644 --- a/src/app/notes/[id]/page.tsx +++ b/src/app/notes/[id]/page.tsx @@ -1,34 +1,18 @@ import { Metadata } from "next"; -import { notFound } from "next/navigation"; -import { getBlocks } from "@/app/actions/blocks"; -import { getNote } from "@/app/actions/notes"; import Editor from "@/components/editor/Editor"; export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise { const { id } = await params; - const note = await getNote(id); - if (!note) { - notFound(); - } - - return { title: note.title }; + return { title: id }; } export default async function Note({ params }: { params: Promise<{ id: string }> }) { const { id } = await params; - const note = await getNote(id); - if (!note) { - notFound(); - } - - const blocks = await getBlocks(note); - if (!blocks) { - notFound(); - } return (
- + {id} +
); } diff --git a/src/app/notes/page.tsx b/src/app/notes/page.tsx index 08bc2c8..e8f75fb 100644 --- a/src/app/notes/page.tsx +++ b/src/app/notes/page.tsx @@ -1,8 +1,4 @@ import { Metadata } from "next"; -import { redirect } from "next/navigation"; -import { getNotes } from "@/app/actions/notes"; -import { getAuth } from "@/lib/auth"; -import NoteCard from "@/components/ui/NoteCard"; export const metadata: Metadata = { title: "Notes - Rhyme", @@ -10,25 +6,10 @@ export const metadata: Metadata = { }; export default async function Notes() { - const auth = await getAuth(); - if (!auth) { - redirect("/auth"); - } - - const notes = await getNotes(auth.id); - return ( <> -

Notes of {auth.username}:

- {notes ? ( - notes.length > 0 ? ( - notes.map((note) => ) - ) : ( - You don't have any saved notes! - ) - ) : ( - Failed to get notes! Please, try again. - )} +

Notes of (username):

+ {/* notes */} ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index d64c6ca..0be1497 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,11 +1,10 @@ import Link from "next/link"; import { redirect } from "next/navigation"; -import { getAuth } from "@/lib/auth"; +import { getAuth } from "@/app/actions/auth"; import Editor from "@/components/editor/Editor"; export default async function Home() { const auth = await getAuth(); - if (auth) { redirect("/notes"); } diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 6c4b810..56cfc3e 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,8 +1,6 @@ import Link from "next/link"; import { CircleQuestionMark, List, Plus, UserRound, UserRoundMinus } from "lucide-react"; -import { createNote } from "@/app/actions/notes"; -import { logOut } from "@/app/actions/auth"; -import { getAuth } from "@/lib/auth"; +import { getAuth } from "@/app/actions/auth"; import HeaderButton from "./ui/HeaderButton"; export default async function Header() { @@ -16,7 +14,7 @@ export default async function Header() { {auth && (
- } /> + } /> } /> @@ -28,7 +26,7 @@ export default async function Header() { } /> {auth ? ( - } /> + } /> ) : ( } /> diff --git a/src/components/editor/Block.tsx b/src/components/editor/Block.tsx index d511a0a..bf5bd8c 100644 --- a/src/components/editor/Block.tsx +++ b/src/components/editor/Block.tsx @@ -1,37 +1,10 @@ "use client"; -import { ChangeEvent } from "react"; -import { ArrowDown, ArrowUp, Lock, LockOpen, Minus, Plus, X } from "lucide-react"; -import { IBlock } from "@/lib/db/schema"; -import { switchLock, deleteBlock } from "@/app/actions/blocks"; +import { ArrowDown, ArrowUp, LockOpen, Minus, Plus, X } from "lucide-react"; import IconOnlyButton from "../ui/IconOnlyButton"; import LineInput from "./LineInput"; -export default function Block({ block }: { block: IBlock }) { - const handleAddLine = () => { - // TODO - } - - const handleDeleteLine = () => { - // TODO - } - - const handleTagUpdate = (e: ChangeEvent) => { - // TODO - } - - const handleLineUpdate = (e: ChangeEvent, line: string) => { - // TODO - } - - const handleBlockUp = () => { - // TODO - } - - const handleBlockDown = () => { - // TODO - } - +export default function Block() { return (
@@ -39,34 +12,20 @@ export default function Block({ block }: { block: IBlock }) { type="text" placeholder="enter tag..." className="w-full focus:outline-none" - defaultValue={block.tag} - disabled={block.isLocked} - onChange={handleTagUpdate} /> - {block.lines.map((line, i) => ( - handleLineUpdate(e, line)} - /> - ))} +
- } /> - } /> + } /> + } />
- } /> - } /> + } /> + } />
- deleteBlock(block)} icon={} /> - switchLock(block)} - icon={block.isLocked ? : } - alwaysOn={block.isLocked} - /> + } /> + } />
diff --git a/src/components/editor/Editor.tsx b/src/components/editor/Editor.tsx index bb461d9..1f90bc8 100644 --- a/src/components/editor/Editor.tsx +++ b/src/components/editor/Editor.tsx @@ -1,70 +1,17 @@ "use client"; -import { ChangeEvent, useState } from "react"; import { Copy, Plus } from "lucide-react"; -import { v4 as uuidv4 } from "uuid"; -import { createBlock } from "@/app/actions/blocks"; -import { IBlock, INote } from "@/lib/db/schema"; import IconOnlyButton from "../ui/IconOnlyButton"; import Block from "./Block"; -interface EditorProps { - note? : INote; - blocks? : IBlock[]; -} - -const defaultNoteId = uuidv4(); - -const defaultNote: INote = { - id: defaultNoteId, - title: "Untitled", - creationTime: new Date(), - lastEdited: new Date(), - authorId: uuidv4(), -}; - -const defaultBlocks: IBlock[] = [ - { - id: uuidv4(), - tag: "", - order: 1, - isLocked: false, - noteId: defaultNoteId, - lines: ["", "", "", ""], - }, -]; - -export default function Editor({ note = defaultNote, blocks = defaultBlocks }: EditorProps) { - const [title, setTitle] = useState(note.title); - - const handleUpdateTitle = (e: ChangeEvent) => { - setTitle(e.target.value); - } - - const handleCopy = () => { - let copyString = ""; - - blocks.forEach((block) => { - if (block.tag !== "") { - copyString += `[${block.tag}]`; - } - copyString += block.lines + "\n"; - }); - - navigator.clipboard.writeText(copyString); - } - +export default function Editor() { return (
- - {blocks.map((block) => )} + +
- createBlock(note)} icon={} /> - } title="Copy note to clipboard" /> + } /> + } title="Copy note to clipboard" />
); diff --git a/src/components/ui/NoteCard.tsx b/src/components/ui/NoteCard.tsx index 5964a03..17e0ae9 100644 --- a/src/components/ui/NoteCard.tsx +++ b/src/components/ui/NoteCard.tsx @@ -1,7 +1,6 @@ import Link from "next/link"; import { X } from "lucide-react"; import { INote } from "@/lib/db/schema"; -import { deleteNote } from "@/app/actions/notes"; import IconOnlyButton from "./IconOnlyButton"; function makeTimestamp(date: Date) { @@ -14,11 +13,6 @@ function makeTimestamp(date: Date) { } export default function NoteCard({ note }: { note: INote }) { - const handleDelete = async () => { - "use server"; - await deleteNote(note.id); - } - return (
@@ -26,7 +20,7 @@ export default function NoteCard({ note }: { note: INote }) { Last time edited: {makeTimestamp(note.lastEdited)} Creation date: {makeTimestamp(note.creationTime)} - } onClick={handleDelete} /> + } />
); } diff --git a/src/lib/auth.ts b/src/lib/auth.ts deleted file mode 100644 index 77487ec..0000000 --- a/src/lib/auth.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { cookies } from "next/headers"; -import { eq } from "drizzle-orm"; -import { usersTable } from "./db/schema"; -import { db } from "./db"; -import jwt from "jsonwebtoken"; - -export async function getAuth() { - const cookieStore = await cookies(); - const token = cookieStore.get("session")?.value; - if (!token) { - return null; - } - - const decodedToken = jwt.decode(token) as jwt.JwtPayload; - const username = decodedToken.sub; - if (!username) { - return null; - } - - const users = await db.select() - .from(usersTable) - .where(eq(usersTable.username, username)); - if (users.length === 0) { - return null; - } - - return users[0]; -} diff --git a/src/lib/hooks/useDebounce.ts b/src/lib/hooks/useDebounce.ts index db9fd2f..e22b902 100644 --- a/src/lib/hooks/useDebounce.ts +++ b/src/lib/hooks/useDebounce.ts @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { useEffect } from "react"; // eslint-disable-next-line @typescript-eslint/no-explicit-any