Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,14 @@ ARCJET_KEY=
# OpenAPI
OPENAI_API_KEY=

# Embedding Model Configuration
EMBEDDING_MODEL=
EMBEDDING_DIMENSIONS=
EMBEDDING_DIMENSIONS=

# S3 Bucket
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_ENDPOINT_URL_S3=
AWS_ENDPOINT_URL_IAM=
AWS_REGION=
NEXT_PUBLIC_S3_BUCKET=
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a trailing newline at end of file.

Static analysis (dotenv-linter) flags the missing blank line at EOF. Most tools and POSIX conventions expect a trailing newline.

 NEXT_PUBLIC_S3_BUCKET=
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
NEXT_PUBLIC_S3_BUCKET=
NEXT_PUBLIC_S3_BUCKET=
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 38-38: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

🤖 Prompt for AI Agents
In @.env.example at line 38, The .env.example file is missing a trailing newline
after the last entry (NEXT_PUBLIC_S3_BUCKET=); add a single newline character at
EOF so the file ends with a blank line (no extra whitespace or characters) to
satisfy dotenv-linter and POSIX conventions.

13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ The project uses PostgreSQL with Neon for the database layer, Better-Auth for fl

Follow these steps to set up the project locally on your machine.

**Prerequisites**
### ❕Prerequisites

Make sure you have the following installed on your machine:

Expand Down Expand Up @@ -191,11 +191,20 @@ ARCJET_KEY=
# OpenAPI
OPENAI_API_KEY=

# Embedding model configuration
EMBEDDING_MODEL=
EMBEDDING_DIMENSIONS=

# S3 Bucket
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_ENDPOINT_URL_S3=
AWS_ENDPOINT_URL_IAM=
AWS_REGION=
NEXT_PUBLIC_S3_BUCKET=
```

Replace the placeholder values with your actual credentials. You can obtain these credentials by signing up on the respective websites
Replace the placeholder values with your actual credentials. You can obtain these credentials by signing up on the respective websites.

## 🗄️ <a name="database-setup">Database Setup</a>

Expand Down
283 changes: 8 additions & 275 deletions bun.lock

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ const nextConfig: NextConfig = {
},
async headers() {
return [
{
// Exclude auth API routes from caching to prevent stale auth state
source: "/api/auth/:path*",
headers: [
{
key: "Cache-Control",
value: "no-store, no-cache, must-revalidate",
},
],
},
{
source: "/:path*",
headers: [
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
"@lexical/selection": "^0.39.0",
"@lexical/table": "^0.39.0",
"@lexical/utils": "^0.39.0",
"@mdxeditor/editor": "^3.47.0",
"@neondatabase/serverless": "^1.0.1",
"@number-flow/react": "^0.5.10",
"@orpc/client": "^1.12.2",
Expand Down Expand Up @@ -90,7 +89,7 @@
"motion": "^12.23.22",
"nanoid": "^5.1.6",
"next": "^16.1.0",
"next-mdx-remote": "^5.0.0",
"next-mdx-remote": "^6.0.0",
"next-themes": "^0.4.6",
"nextjs-toploader": "^3.9.17",
"nuqs": "^2.8.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { DataRenderer } from "@/components/shared";
import { EMPTY_ANSWERS, EMPTY_QUESTION } from "@/common/constants/states";
import { QuestionCard } from "@/components/modules/questions";
import { AnswerCard } from "@/components/modules/answers";
import MarkdownPreview from "@/components/markdown/markdown-preview";
import MarkdownPreview from "@/components/editor/markdown/markdown-preview";

export async function getUserPosts(
userId: string,
Expand Down
2 changes: 1 addition & 1 deletion src/app/(root)/(dashboard)/questions/[id]/edit/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import EditorFallback from "@/components/markdown/editor-fallback";
import EditorFallback from "@/components/editor/markdown/editor-fallback";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
Expand Down
2 changes: 1 addition & 1 deletion src/app/(root)/(dashboard)/questions/[id]/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import EditorFallback from "@/components/markdown/editor-fallback";
import EditorFallback from "@/components/editor/markdown/editor-fallback";
import {
PostCardsSkeleton,
QuestionHeaderSkeleton,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Code } from "bright";
import { MDXRemote } from "next-mdx-remote/rsc";
import { dev4roomLight } from "./theme";
import { dev4roomLight } from "../themes/preview-theme";

Code.theme = {
light: dev4roomLight,
Expand Down
2 changes: 1 addition & 1 deletion src/components/form/form-markdown.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ReactNode, Suspense, RefObject, useCallback } from "react";
import dynamic from "next/dynamic";

import EditorFallback from "@/components/markdown/editor-fallback";
import EditorFallback from "@/components/editor/markdown/editor-fallback";
import type { FormEditorMethods } from "@/components/editor/markdown/form-editor";
import { FormBase, FormControlFn } from "./form-base";
import { useDebounce } from "@/hooks/use-debounce";
Expand Down
128 changes: 0 additions & 128 deletions src/components/markdown/index.tsx

This file was deleted.

49 changes: 0 additions & 49 deletions src/components/markdown/markdown-editor.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/modules/answers/answer-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ReactNode } from "react";
import { cn, getTimeStamp } from "@/lib/utils";
import { Card } from "@/components/ui/card";
import UserAvatar from "@/components/modules/profile/user-avatar";
import EditorFallback from "@/components/markdown/editor-fallback";
import EditorFallback from "@/components/editor/markdown/editor-fallback";
import EditDelete from "@/components/shared/edit-delete";
import Votes from "@/components/modules/vote/votes";
import AnswerForm from "./answer-form";
Expand Down
2 changes: 1 addition & 1 deletion src/components/modules/answers/answer-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { FilterProvider } from "@/context";
import { NextPagination } from "@/components/ui/dev";
import AnswerCard from "./answer-card";
import ScrollToAnswer from "./scroll-to-answer";
import MarkdownPreview from "@/components/markdown/markdown-preview";
import MarkdownPreview from "@/components/editor/markdown/markdown-preview";

interface AnswerListProps {
questionId: string;
Expand Down
6 changes: 1 addition & 5 deletions src/components/modules/dashboard/nav-user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
import UserAvatar from "../profile/user-avatar";
import { authClient } from "@/lib/auth-client";
import { Skeleton } from "@/components/ui";
import { useRouter } from "next/navigation";
import { toast } from "sonner";

export function NavUser() {
Expand Down Expand Up @@ -114,17 +113,14 @@ export function NavUser() {
}

function LogoutItem() {
const router = useRouter();

async function handleLogout() {
const { error } = await authClient.signOut();

if (error) {
toast.error(error.message || "Something went wrong");
} else {
toast.success("Logged out successfully");
router.push("/");
router.refresh();
window.location.href = "/";
}
}
Comment on lines 115 to 125
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Toast may not be visible before the hard redirect.

toast.success(...) on line 122 fires right before window.location.href = "/" on line 123. The full-page navigation will likely destroy the DOM before the toast renders or becomes readable. Consider either removing the toast or deferring the redirect briefly.

Option: small delay before redirect
     } else {
       toast.success("Logged out successfully");
-      window.location.href = "/";
+      setTimeout(() => {
+        window.location.href = "/";
+      }, 300);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function LogoutItem() {
const router = useRouter();
async function handleLogout() {
const { error } = await authClient.signOut();
if (error) {
toast.error(error.message || "Something went wrong");
} else {
toast.success("Logged out successfully");
router.push("/");
router.refresh();
window.location.href = "/";
}
}
function LogoutItem() {
async function handleLogout() {
const { error } = await authClient.signOut();
if (error) {
toast.error(error.message || "Something went wrong");
} else {
toast.success("Logged out successfully");
setTimeout(() => {
window.location.href = "/";
}, 300);
}
}
🤖 Prompt for AI Agents
In `@src/components/modules/dashboard/nav-user.tsx` around lines 115 - 125, The
toast.success call in LogoutItem.handleLogout runs immediately before the hard
redirect (window.location.href = "/"), which prevents the toast from being
visible; update handleLogout to either remove the toast or delay the redirect so
the toast can render (e.g., show toast.success(...) then perform the redirect
inside a short setTimeout or use the SPA router navigation instead of
window.location.href). Locate LogoutItem and its async handleLogout function
(which calls authClient.signOut, toast.success, and window.location.href) and
implement the chosen approach so the toast is visible before navigation.


Expand Down
7 changes: 2 additions & 5 deletions src/components/modules/profile/user-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import UserAvatar from "./user-avatar";
import Link from "next/link";
import { toast } from "sonner";
import { authClient } from "@/lib/auth-client";
import { useRouter } from "next/navigation";
import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils";

Expand Down Expand Up @@ -125,17 +124,15 @@ function PendingQuestionsItem() {
}

function LogoutItem() {
const router = useRouter();

async function handleLogout() {
const { error } = await authClient.signOut();

if (error) {
toast.error(error.message || "Something went wrong");
} else {
toast.success("Logged out successfully");
router.push("/");
router.refresh();
// Hard redirect to fully clear Router Cache + stale auth state
window.location.href = "/";
}
}
Comment on lines 126 to 137
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same toast-before-redirect issue as in nav-user.tsx; also consider extracting shared logout logic.

The same toast visibility concern applies here. Additionally, both LogoutItem components (here and in nav-user.tsx) share identical handleLogout logic. Consider extracting a shared useLogout hook or utility to avoid duplication.

🤖 Prompt for AI Agents
In `@src/components/modules/profile/user-nav.tsx` around lines 126 - 137, The
LogoutItem component’s handleLogout calls toast.success and immediately forces a
hard redirect, causing the toast to be cut off; change the flow in LogoutItem
(and the other nav LogoutItem in nav-user.tsx) to wait briefly or await a toast
display before setting window.location.href, and refactor the duplicated logic
into a shared useLogout hook or utility (export a useLogout or logoutUser
function that performs authClient.signOut, handles toast.error/toast.success and
the delayed redirect) then import and call that from both LogoutItem components
to remove duplication.


Expand Down
2 changes: 1 addition & 1 deletion src/components/modules/questions/question-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { SaveQuestion } from "@/components/modules/questions";
import TagCard from "@/components/modules/tags/tag-card";
import EditDelete from "@/components/shared/edit-delete";
import { Separator } from "@/components/ui/separator";
import MarkdownPreview from "@/components/markdown/markdown-preview";
import MarkdownPreview from "@/components/editor/markdown/markdown-preview";
import { Metric } from "@/components/shared";
import { QuestionUtilsFallback } from "@/components/modules/questions";

Expand Down
File renamed without changes.
Loading