frontend changes
This commit is contained in:
parent
81ad734f47
commit
8b5c53ef4c
@ -3,7 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack -p 3001",
|
||||
"dev": "next dev -p 3001",
|
||||
"build": "next build",
|
||||
"start": "next start -p 3001",
|
||||
"lint": "next lint"
|
||||
|
||||
@ -1,18 +1,11 @@
|
||||
import type React from "react"
|
||||
import type { Metadata } from "next"
|
||||
import { Poppins } from "next/font/google"
|
||||
import { AuthProvider } from "@/contexts/auth-context"
|
||||
import { AppLayout } from "@/components/layout/app-layout"
|
||||
import { ToastProvider } from "@/components/ui/toast"
|
||||
import "./globals.css"
|
||||
import "@tldraw/tldraw/tldraw.css"
|
||||
|
||||
const poppins = Poppins({
|
||||
subsets: ["latin"],
|
||||
weight: ["300", "400", "500", "600", "700"],
|
||||
variable: "--font-poppins",
|
||||
})
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Codenuk - AI-Powered Project Builder",
|
||||
description: "Build scalable applications with AI-generated architecture and code",
|
||||
@ -27,10 +20,16 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>{`
|
||||
html {
|
||||
font-family: ${poppins.style.fontFamily};
|
||||
--font-sans: ${poppins.variable};
|
||||
font-family: 'Poppins', sans-serif;
|
||||
--font-sans: 'Poppins', sans-serif;
|
||||
}
|
||||
`}</style>
|
||||
</head>
|
||||
|
||||
@ -884,6 +884,8 @@ function FeatureSelectionStep({
|
||||
}: { template: Template; onNext: (selected: TemplateFeature[]) => void; onBack: () => void }) {
|
||||
const { fetchFeatures, createFeature, updateFeature, deleteFeature } = useTemplates()
|
||||
const [features, setFeatures] = useState<TemplateFeature[]>([])
|
||||
const [essentialFeatures, setEssentialFeatures] = useState<TemplateFeature[]>([])
|
||||
const [customFeatures, setCustomFeatures] = useState<TemplateFeature[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
|
||||
@ -917,6 +919,9 @@ function FeatureSelectionStep({
|
||||
})
|
||||
console.log('[FeatureSelectionStep] All features with types:', data.map(f => ({ name: f.name, type: f.feature_type })))
|
||||
setFeatures(data)
|
||||
// Separate custom features from essential features
|
||||
setEssentialFeatures(data.filter(f => f.feature_type !== 'custom'))
|
||||
setCustomFeatures(data.filter(f => f.feature_type === 'custom'))
|
||||
} catch (e) {
|
||||
console.error('[FeatureSelectionStep] Error loading features:', e)
|
||||
setError(e instanceof Error ? e.message : 'Failed to load features')
|
||||
@ -1085,10 +1090,10 @@ function FeatureSelectionStep({
|
||||
<div className="max-w-7xl mx-auto space-y-8">
|
||||
<div className="text-center space-y-4">
|
||||
<h1 className="text-4xl font-bold text-white">Select Features for {template.title}</h1>
|
||||
<p className="text-xl text-white/60 max-w-3xl mx-auto">Choose defaults or add your own custom features.</p>
|
||||
<p className="text-xl text-white/60 max-w-3xl mx-auto">Choose from essential and suggested features.</p>
|
||||
</div>
|
||||
|
||||
{features.length > 0 && section('Template Features', features)}
|
||||
{essentialFeatures.length > 0 && section('Essential Features', essentialFeatures)}
|
||||
|
||||
{/* Add custom feature with AI */}
|
||||
<div className="bg-white/5 border border-white/10 rounded-xl p-6 space-y-4">
|
||||
@ -1110,7 +1115,7 @@ function FeatureSelectionStep({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{section('Your Custom Features', custom)}
|
||||
{customFeatures.length > 0 && section('Custom Features', customFeatures)}
|
||||
|
||||
{(showAIModal || editingFeature) && (
|
||||
<AICustomFeatureCreator
|
||||
@ -1138,7 +1143,7 @@ function FeatureSelectionStep({
|
||||
<div className="space-x-4">
|
||||
<Button variant="outline" onClick={onBack} className="border-white/20 text-white hover:bg-white/10 cursor-pointer">Back</Button>
|
||||
<Button
|
||||
onClick={() => onNext(features.filter(f => selectedIds.has(f.id)))}
|
||||
onClick={() => onNext([...essentialFeatures, ...customFeatures].filter(f => selectedIds.has(f.id)))}
|
||||
disabled={selectedIds.size < 3}
|
||||
className={`bg-orange-500 hover:bg-orange-400 text-black cursor-pointer font-semibold py-2 rounded-lg shadow ${selectedIds.size < 3 ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
>
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
*/
|
||||
|
||||
// Main backend URL - change this to update all API calls
|
||||
export const BACKEND_URL = 'http://192.168.1.20:8000';
|
||||
// export const BACKEND_URL = 'https://backend.codenuk.com';
|
||||
// export const BACKEND_URL = 'http://192.168.1.31:8000';
|
||||
export const BACKEND_URL = 'https://backend.codenuk.com';
|
||||
|
||||
|
||||
// Realtime notifications socket URL (Template Manager emits notifications)
|
||||
|
||||
@ -384,56 +384,15 @@ class TemplateService {
|
||||
|
||||
// Features API
|
||||
async getFeaturesForTemplate(templateId: string): Promise<TemplateFeature[]> {
|
||||
// Use merged endpoint to include custom features (returns custom_feature.id for custom items)
|
||||
const dedupe = (items: TemplateFeature[]) => {
|
||||
const byKey = new Map<string, TemplateFeature>()
|
||||
|
||||
const toKey = (f: TemplateFeature) => {
|
||||
const normName = (f.name || '').trim().toLowerCase()
|
||||
// Use normalized name for all features to enable proper deduplication
|
||||
// between template_features and custom_features tables
|
||||
return normName
|
||||
}
|
||||
|
||||
const prefer = (a: TemplateFeature, b: TemplateFeature): TemplateFeature => {
|
||||
// Prefer user-created, then higher usage_count, then newer updated_at
|
||||
const aUser = !!a.created_by_user
|
||||
const bUser = !!b.created_by_user
|
||||
if (aUser !== bUser) return aUser ? a : b
|
||||
const aUsage = typeof a.usage_count === 'number' ? a.usage_count : -1
|
||||
const bUsage = typeof b.usage_count === 'number' ? b.usage_count : -1
|
||||
if (aUsage !== bUsage) return aUsage > bUsage ? a : b
|
||||
const aTime = a.updated_at ? Date.parse(a.updated_at) : 0
|
||||
const bTime = b.updated_at ? Date.parse(b.updated_at) : 0
|
||||
return aTime >= bTime ? a : b
|
||||
}
|
||||
|
||||
for (const item of items) {
|
||||
const key = toKey(item)
|
||||
const existing = byKey.get(key)
|
||||
if (!existing) {
|
||||
byKey.set(key, item)
|
||||
} else {
|
||||
byKey.set(key, prefer(existing, item))
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[getFeaturesForTemplate] Deduplication results:', {
|
||||
originalCount: items.length,
|
||||
deduplicatedCount: byKey.size,
|
||||
duplicatesRemoved: items.length - byKey.size
|
||||
})
|
||||
|
||||
return Array.from(byKey.values())
|
||||
}
|
||||
|
||||
try {
|
||||
const merged = await this.makeRequest<TemplateFeature[]>(`/api/templates/${templateId}/features`)
|
||||
return dedupe(merged)
|
||||
console.log('[getFeaturesForTemplate] Raw merged features (no deduplication):', merged)
|
||||
return merged
|
||||
} catch {
|
||||
// Fallback to compatible route in features router
|
||||
const defaults = await this.makeRequest<TemplateFeature[]>(`/api/features/templates/${templateId}/features`)
|
||||
return dedupe(defaults)
|
||||
console.log('[getFeaturesForTemplate] Raw fallback features (no deduplication):', defaults)
|
||||
return defaults
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user