Skip to content

Commit c5fed6f

Browse files
Refactor publisher creation flow with modular step components and real-time validation
Breaks down monolithic publisher page into reusable step components, extracts validation logic into shared utilities, and adds real-time publisher ID validation API endpoint. Improves code maintainability and user experience. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
1 parent 1eabe1b commit c5fed6f

File tree

8 files changed

+610
-327
lines changed

8 files changed

+610
-327
lines changed

web/src/app/api/publishers/route.ts

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import { getServerSession } from 'next-auth'
77

88
import { authOptions } from '@/app/api/auth/[...nextauth]/auth-options'
99
import { checkOrgPublisherAccess } from '@/lib/publisher-permissions'
10+
import {
11+
validatePublisherName,
12+
validatePublisherId,
13+
} from '@/lib/validators/publisher'
1014
import { logger } from '@/util/logger'
1115

1216
import type {
@@ -15,44 +19,6 @@ import type {
1519
} from '@codebuff/common/types/publisher'
1620
import type { NextRequest } from 'next/server'
1721

18-
function validatePublisherName(name: string): string | null {
19-
if (!name || !name.trim()) {
20-
return 'Publisher name is required'
21-
}
22-
23-
const trimmedName = name.trim()
24-
25-
if (trimmedName.length < 2) {
26-
return 'Publisher name must be at least 2 characters long'
27-
}
28-
29-
if (trimmedName.length > 50) {
30-
return 'Publisher name must be no more than 50 characters long'
31-
}
32-
33-
return null
34-
}
35-
function validatePublisherId(id: string): string | null {
36-
const result = PublisherIdSchema.safeParse(id)
37-
if (!result.success) {
38-
return result.error.errors[0]?.message || 'Invalid publisher ID'
39-
}
40-
41-
if (id.length < 3) {
42-
return 'Publisher ID must be at least 3 characters long'
43-
}
44-
45-
if (id.length > 30) {
46-
return 'Publisher ID must be no more than 30 characters long'
47-
}
48-
49-
if (id.startsWith('-') || id.endsWith('-')) {
50-
return 'Publisher ID cannot start or end with a hyphen'
51-
}
52-
53-
return null
54-
}
55-
5622
export async function GET(): Promise<
5723
NextResponse<PublisherProfileResponse[] | { error: string }>
5824
> {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import db from '@codebuff/common/db'
3+
import * as schema from '@codebuff/common/db/schema'
4+
import { eq } from 'drizzle-orm'
5+
import { validatePublisherId } from '@/lib/validators/publisher'
6+
7+
export async function GET(request: NextRequest) {
8+
try {
9+
const { searchParams } = new URL(request.url)
10+
const id = searchParams.get('id')
11+
12+
if (!id) {
13+
return NextResponse.json(
14+
{ valid: false, error: 'Publisher ID is required' },
15+
{ status: 400 }
16+
)
17+
}
18+
19+
// Validate format first
20+
const formatError = validatePublisherId(id)
21+
if (formatError) {
22+
return NextResponse.json(
23+
{ valid: false, error: formatError },
24+
{ status: 200 }
25+
)
26+
}
27+
28+
// Check if ID is already taken
29+
const existingPublisher = await db
30+
.select({ id: schema.publisher.id })
31+
.from(schema.publisher)
32+
.where(eq(schema.publisher.id, id))
33+
.limit(1)
34+
35+
if (existingPublisher.length > 0) {
36+
return NextResponse.json(
37+
{ valid: false, error: 'This publisher ID is already taken' },
38+
{ status: 200 }
39+
)
40+
}
41+
42+
return NextResponse.json(
43+
{ valid: true, error: null },
44+
{ status: 200 }
45+
)
46+
} catch (error) {
47+
console.error('Error validating publisher ID:', error)
48+
return NextResponse.json(
49+
{ valid: false, error: 'Failed to validate publisher ID' },
50+
{ status: 500 }
51+
)
52+
}
53+
}

0 commit comments

Comments
 (0)