Skip to content

Commit

Permalink
Merge pull request #15 from ETLOnline/feature/create-db-user-on-webhook
Browse files Browse the repository at this point in the history
feat(db): config correction and create user in db on register
  • Loading branch information
usama-tariq1 authored Dec 7, 2024
2 parents 284148a + 23151e5 commit 1473939
Show file tree
Hide file tree
Showing 12 changed files with 402 additions and 4 deletions.
113 changes: 113 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"react": "^18",
"react-day-picker": "^8.10.1",
"react-dom": "^18",
"svix": "^1.43.0",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7"
},
Expand Down
23 changes: 23 additions & 0 deletions src/app/(dashboard)/posts/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { PlatformSuggestionCard } from '@/src/components/dashboard/PlatformSuggestionCard/PlatformSuggestionCard'
import { TrendingTagsCard } from '@/src/components/dashboard/TrendingTagsCard/TrendingTagsCard'
import { Separator } from '@/src/components/ui/separator'
import React, { ReactNode } from 'react'

const PostFeedLayout = ({children}:{children:ReactNode}) => {
return (
<div className="flex border-t">
<div className="flex-1 overflow-auto">
{children}
</div>
<div className="hidden w-80 flex-shrink-0 border-l lg:block">
<div className="p-4">
<TrendingTagsCard />
<Separator className="my-4" />
<PlatformSuggestionCard />
</div>
</div>
</div>
)
}

export default PostFeedLayout
72 changes: 72 additions & 0 deletions src/app/api/webhook/user-created/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Webhook } from 'svix'
import { headers } from 'next/headers'
import { WebhookEvent } from '@clerk/nextjs/server'
import { InsertUser } from '@/src/db/schema'
import { CreateUser } from '@/src/db/data-access/user/query'

export async function POST(req: Request) {

// You can find this in the Clerk Dashboard -> Webhooks -> choose the endpoint
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET

if (!WEBHOOK_SECRET) {
throw new Error('Please add WEBHOOK_SECRET from Clerk Dashboard to .env or .env.local')
}

// Get the headers
const headerPayload = headers();
const svix_id = headerPayload.get("svix-id");
const svix_timestamp = headerPayload.get("svix-timestamp");
const svix_signature = headerPayload.get("svix-signature");

// If there are no headers, error out
if (!svix_id || !svix_timestamp || !svix_signature) {
return new Response('Error occured -- no svix headers', {
status: 400
})
}

// Get the body
const payload = await req.json()
const body = JSON.stringify(payload);

// Create a new Svix instance with your secret.
const wh = new Webhook(WEBHOOK_SECRET);

let evt: WebhookEvent

// Verify the payload with the headers
try {
evt = wh.verify(body, {
"svix-id": svix_id,
"svix-timestamp": svix_timestamp,
"svix-signature": svix_signature,
}) as WebhookEvent
} catch (err) {
console.error('Error verifying webhook:', err);
return new Response('Error occured', {
status: 400
})
}

// Do something with the payload
// For this guide, you simply log the payload to the console
// const { id } = evt.data;
// const eventType = evt.type;

// console.log(`Webhook with and ID of ${id} and type of ${eventType}`)
// console.log('Webhook body:', body)

if (evt.type === 'user.created') {
const userObj = evt.data
const newUser:InsertUser ={
first_name: userObj.first_name || '',
last_name: userObj.last_name || '',
email: userObj.email_addresses[0].email_address || '',
external_auth_id: userObj.id
}
await CreateUser(newUser)
}

return new Response('', { status: 200 })
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Avatar, AvatarFallback, AvatarImage } from "@/src/components/ui/avatar"
import { Button } from "@/src/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/src/components/ui/card"
import { Users } from 'lucide-react'

const suggestions = [
{ name: "Alice Johnson", avatar: "/avatars/01.png", role: "AI Researcher" },
{ name: "Bob Smith", avatar: "/avatars/02.png", role: "Data Scientist" },
{ name: "Carol Williams", avatar: "/avatars/03.png", role: "Web Developer" },
]

export function PlatformSuggestionCard() {
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center">
<Users className="mr-2 h-4 w-4" />
Suggested Connections
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
{suggestions.map((suggestion) => (
<div key={suggestion.name} className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<Avatar>
<AvatarImage src={suggestion.avatar} alt={suggestion.name} />
<AvatarFallback>{suggestion.name.charAt(0)}</AvatarFallback>
</Avatar>
<div>
<p className="text-sm font-medium">{suggestion.name}</p>
<p className="text-xs text-muted-foreground">{suggestion.role}</p>
</div>
</div>
<Button variant="outline" size="sm">
Connect
</Button>
</div>
))}
</div>
</CardContent>
</Card>
)
}

35 changes: 35 additions & 0 deletions src/components/dashboard/TrendingTagsCard/TrendingTagsCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Badge } from "@/src/components/ui/badge"
import { Card, CardContent, CardHeader, CardTitle } from "@/src/components/ui/card"
import { TrendingUp } from 'lucide-react'

const trendingTags = [
{ name: "AI", count: 1234 },
{ name: "MachineLearning", count: 987 },
{ name: "DataScience", count: 856 },
{ name: "WebDev", count: 743 },
{ name: "JavaScript", count: 621 },
]

export function TrendingTagsCard() {
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center">
<TrendingUp className="mr-2 h-4 w-4" />
Trending Tags
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex flex-wrap gap-2">
{trendingTags.map((tag) => (
<Badge key={tag.name} variant="secondary" className="text-xs">
#{tag.name}
<span className="ml-1 text-muted-foreground">({tag.count})</span>
</Badge>
))}
</div>
</CardContent>
</Card>
)
}

13 changes: 13 additions & 0 deletions src/db/data-access/user/query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { eq } from "drizzle-orm";
import { db } from "../..";
import { InsertUser, usersTable } from "../../schema";

export async function CreateUser(data: InsertUser) {
await db.insert(usersTable).values(data);
}

export async function SelectUserById(id: string) {
return await db.query.usersTable.findFirst({
where: eq(usersTable.external_auth_id, id)
});
}
4 changes: 3 additions & 1 deletion src/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { drizzle } from 'drizzle-orm/libsql';
import { createClient } from '@libsql/client';

config({ path: '.env.local' });

const client = createClient({
url: process.env.TURSO_CONNECTION_URL!,
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
});

export const db = drizzle(client , { schema });
Loading

0 comments on commit 1473939

Please sign in to comment.