Skip to content

Commit 81d2f05

Browse files
ask question + Webhooks
1 parent e8952fa commit 81d2f05

18 files changed

+1489
-51
lines changed

app/(root)/(home)/page.tsx

+43-42
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,60 @@
1-
"use client";
2-
31
import QuestionCard from "@/components/cards/QuestionCard";
42
import HomeFilters from "@/components/home/HomeFilters";
53
import { Filter } from "@/components/shared/Filter";
64
import NoResult from "@/components/shared/NoResult";
75
import { LocalSearchbar } from "@/components/shared/search/LocalSearchbar";
86
import { Button } from "@/components/ui/button";
97
import { HomePageFilters } from "@/constants/filters";
8+
import { getQuestions } from "@/lib/actions/question.action";
109
import Link from "next/link";
1110

12-
const questions = [
13-
{
14-
_id: "1",
15-
title: "Cascading Deletes in SQLAlchemy?",
16-
tags: [
17-
{ _id: "1", name: "python" },
18-
{ _id: "2", name: "sql" },
19-
],
20-
author: {
21-
_id: "1",
22-
name: "John Doe",
23-
picture: "https://example.com/johndoe.jpg",
24-
},
25-
upvotes: 12311213421,
26-
views: 500552,
27-
answers: [{}],
28-
createdAt: new Date("2024-09-01T12:00:00.000Z"),
29-
},
30-
{
31-
_id: "2",
32-
title: "How to center a div?",
33-
tags: [
34-
{ _id: "1", name: "css" },
35-
{ _id: "2", name: "html" },
36-
],
37-
author: {
38-
_id: "2",
39-
name: "Jane Doe",
40-
picture: "https://example.com/janedoe.jpg",
41-
},
42-
upvotes: 20,
43-
views: 200,
44-
answers: [{}],
45-
createdAt: new Date("2021-09-01T12:00:00.000Z"),
46-
},
47-
];
11+
// const questions = [
12+
// {
13+
// _id: "1",
14+
// title: "Cascading Deletes in SQLAlchemy?",
15+
// tags: [
16+
// { _id: "1", name: "python" },
17+
// { _id: "2", name: "sql" },
18+
// ],
19+
// author: {
20+
// _id: "1",
21+
// name: "John Doe",
22+
// picture: "https://example.com/johndoe.jpg",
23+
// },
24+
// upvotes: 12311213421,
25+
// views: 500552,
26+
// answers: [{}],
27+
// createdAt: new Date("2024-09-01T12:00:00.000Z"),
28+
// },
29+
// {
30+
// _id: "2",
31+
// title: "How to center a div?",
32+
// tags: [
33+
// { _id: "1", name: "css" },
34+
// { _id: "2", name: "html" },
35+
// ],
36+
// author: {
37+
// _id: "2",
38+
// name: "Jane Doe",
39+
// picture: "https://example.com/janedoe.jpg",
40+
// },
41+
// upvotes: 20,
42+
// views: 200,
43+
// answers: [{}],
44+
// createdAt: new Date("2021-09-01T12:00:00.000Z"),
45+
// },
46+
// ];
47+
48+
export default async function Home() {
49+
const result = await getQuestions({});
4850

49-
export default function Home() {
5051
return (
5152
<>
5253
<div className="flex w-full flex-col-reverse justify-between gap-4 sm:flex-row sm:items-center">
5354
<h1 className="h1-bold text-dark100_light900">All Questions</h1>
5455
<Link href={`/ask-question`} className="flex justify-end max-sm:w-full">
5556
<Button className="primary-gradient min-h-[46px] px-4 py-3 !text-light-900">
56-
Ask a Questions
57+
Ask a Question
5758
</Button>
5859
</Link>
5960
</div>
@@ -75,8 +76,8 @@ export default function Home() {
7576
<HomeFilters />
7677

7778
<div className="mt-10 flex w-full flex-col gap-6">
78-
{questions.length > 0 ? (
79-
questions.map((question) => (
79+
{result.questions.length > 0 ? (
80+
result.questions.map((question) => (
8081
<QuestionCard
8182
key={question._id}
8283
_id={question._id}

app/(root)/ask-question/page.tsx

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
1+
import Question from "@/components/forms/Question";
2+
import { getUserById } from "@/lib/actions/user.action";
3+
import { auth } from "@clerk/nextjs/server";
4+
import { redirect } from "next/navigation";
15
import React from "react";
26

3-
const page = () => {
4-
return <div>Ask Question</div>;
7+
const Page = async () => {
8+
//const { userId } = auth();
9+
const userId = "clerk_12345";
10+
if (!userId) redirect("/sign-in");
11+
const mongoUser = await getUserById({ userId });
12+
console.log("MONGOUSER", mongoUser);
13+
return (
14+
<div>
15+
<h1 className="h1-bold text-dark100_light900">Ask a question</h1>
16+
<div className="mt-9">
17+
<Question mongoUserId={JSON.stringify(mongoUser._id)} />
18+
</div>
19+
</div>
20+
);
521
};
622

7-
export default page;
23+
export default Page;

app/api/webhook/route.ts

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { Webhook } from "svix";
2+
import { headers } from "next/headers";
3+
import { WebhookEvent } from "@clerk/nextjs/server";
4+
import { createUser, deleteUser, updateUser } from "@/lib/actions/user.action";
5+
import { json } from "stream/consumers";
6+
import { NextResponse } from "next/server";
7+
8+
export async function POST(req: Request) {
9+
// You can find this in the Clerk Dashboard -> Webhooks -> choose the endpoint
10+
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
11+
12+
if (!WEBHOOK_SECRET) {
13+
throw new Error(
14+
"Please add WEBHOOK_SECRET from Clerk Dashboard to .env or .env.local"
15+
);
16+
}
17+
18+
// Get the headers
19+
const headerPayload = headers();
20+
const svix_id = headerPayload.get("svix-id");
21+
const svix_timestamp = headerPayload.get("svix-timestamp");
22+
const svix_signature = headerPayload.get("svix-signature");
23+
24+
// If there are no headers, error out
25+
if (!svix_id || !svix_timestamp || !svix_signature) {
26+
return new Response("Error occured -- no svix headers", {
27+
status: 400,
28+
});
29+
}
30+
31+
// Get the body
32+
const payload = await req.json();
33+
const body = JSON.stringify(payload);
34+
35+
// Create a new Svix instance with your secret.
36+
const wh = new Webhook(WEBHOOK_SECRET);
37+
38+
let evt: WebhookEvent;
39+
40+
// Verify the payload with the headers
41+
try {
42+
evt = wh.verify(body, {
43+
"svix-id": svix_id,
44+
"svix-timestamp": svix_timestamp,
45+
"svix-signature": svix_signature,
46+
}) as WebhookEvent;
47+
} catch (err) {
48+
console.error("Error verifying webhook:", err);
49+
return new Response("Error occured", {
50+
status: 400,
51+
});
52+
}
53+
54+
// Do something with the payload
55+
// For this guide, you simply log the payload to the console
56+
const { id } = evt.data;
57+
const eventType = evt.type;
58+
59+
if (eventType === "user.created") {
60+
const { id, email_addresses, image_url, username, first_name, last_name } =
61+
evt.data;
62+
63+
const mongoUser = await createUser({
64+
clerkId: id,
65+
name: `${first_name}${last_name ? ` ${last_name}` : ""}`,
66+
username: username!,
67+
email: email_addresses[0].email_address,
68+
picture: image_url,
69+
});
70+
71+
return NextResponse.json({ message: "Ok", user: mongoUser });
72+
}
73+
if (eventType === "user.updated") {
74+
const { id, email_addresses, image_url, username, first_name, last_name } =
75+
evt.data;
76+
77+
const mongoUser = await updateUser({
78+
clerkId: id,
79+
updateData: {
80+
name: `${first_name}${last_name ? ` ${last_name}` : ""}`,
81+
username: username!,
82+
email: email_addresses[0].email_address,
83+
picture: image_url,
84+
},
85+
path: `/profile/${id}`,
86+
});
87+
88+
return NextResponse.json({ message: "Ok", user: mongoUser });
89+
}
90+
91+
if (eventType === "user.deleted") {
92+
const { id } = evt.data;
93+
94+
const deletedUser = await deleteUser({
95+
clerkId: id!,
96+
});
97+
return NextResponse.json({ message: "Ok", user: deletedUser });
98+
}
99+
100+
return new Response("", { status: 200 });
101+
}

0 commit comments

Comments
 (0)