Add authentication check and require user ID for story creation

This commit is contained in:
Riccardo Giorato
2025-12-25 14:21:41 +01:00
parent 8bc68eb102
commit d5b163e586
3 changed files with 29 additions and 18 deletions
+27 -16
View File
@@ -6,6 +6,7 @@ import { ArrowRight, Loader2 } from "lucide-react"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { useToast } from "@/hooks/use-toast" import { useToast } from "@/hooks/use-toast"
import { useS3Upload } from "next-s3-upload" import { useS3Upload } from "next-s3-upload"
import { useAuth, SignInButton } from "@clerk/nextjs"
interface CreateButtonProps { interface CreateButtonProps {
prompt: string prompt: string
@@ -19,6 +20,7 @@ export function CreateButton({ prompt, style, characterFiles }: CreateButtonProp
const [loadingStep, setLoadingStep] = useState(0) const [loadingStep, setLoadingStep] = useState(0)
const { toast } = useToast() const { toast } = useToast()
const { uploadToS3 } = useS3Upload() const { uploadToS3 } = useS3Upload()
const { isSignedIn } = useAuth()
useEffect(() => { useEffect(() => {
if (!isLoading) return if (!isLoading) return
@@ -98,23 +100,32 @@ export function CreateButton({ prompt, style, characterFiles }: CreateButtonProp
return ( return (
<div className="pt-2"> <div className="pt-2">
<Button {isSignedIn ? (
onClick={handleCreate} <Button
disabled={isLoading || !prompt.trim()} onClick={handleCreate}
className="w-full sm:w-auto sm:min-w-40 bg-white hover:bg-neutral-200 text-black px-8 py-2 rounded-md text-sm font-medium transition-colors flex items-center justify-center gap-3 tracking-tight" disabled={isLoading || !prompt.trim()}
> className="w-full sm:w-auto sm:min-w-40 bg-white hover:bg-neutral-200 text-black px-8 py-2 rounded-md text-sm font-medium transition-colors flex items-center justify-center gap-3 tracking-tight"
{isLoading ? ( >
<> {isLoading ? (
<Loader2 className="w-4 h-4 animate-spin" /> <>
<span className="text-sm font-medium tracking-tight">{loadingSteps[loadingStep]}</span> <Loader2 className="w-4 h-4 animate-spin" />
</> <span className="text-sm font-medium tracking-tight">{loadingSteps[loadingStep]}</span>
) : ( </>
<> ) : (
Generate <>
Generate
<ArrowRight className="w-4 h-4" />
</>
)}
</Button>
) : (
<SignInButton mode="modal">
<Button className="w-full sm:w-auto sm:min-w-40 bg-white hover:bg-neutral-200 text-black px-8 py-2 rounded-md text-sm font-medium transition-colors flex items-center justify-center gap-3 tracking-tight">
Login to create your comic
<ArrowRight className="w-4 h-4" /> <ArrowRight className="w-4 h-4" />
</> </Button>
)} </SignInButton>
</Button> )}
</div> </div>
) )
} }
+1 -1
View File
@@ -3,7 +3,7 @@ import { stories, pages, type Story, type Page } from './schema';
import { eq } from 'drizzle-orm'; import { eq } from 'drizzle-orm';
import { generateComicSlug } from './slug-generator'; import { generateComicSlug } from './slug-generator';
export async function createStory(data: { title: string; description?: string; userId?: string }): Promise<Story> { export async function createStory(data: { title: string; description?: string; userId: string }): Promise<Story> {
// Generate a unique slug // Generate a unique slug
let slug = generateComicSlug(); let slug = generateComicSlug();
let attempts = 0; let attempts = 0;
+1 -1
View File
@@ -7,7 +7,7 @@ export const stories = pgTable('stories', {
title: text('title').notNull(), title: text('title').notNull(),
slug: text('slug').notNull().unique(), slug: text('slug').notNull().unique(),
description: text('description'), description: text('description'),
userId: uuid('user_id'), // Optional - for future Clerk auth userId: uuid('user_id').notNull(), // Required Clerk user ID
createdAt: timestamp('created_at').defaultNow().notNull(), createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(), updatedAt: timestamp('updated_at').defaultNow().notNull(),
}); });