- Werden Sie Teil der Revolution, die manuelle Dateneingabe fรผr immer verรคndert.
- Schaffen Sie ein System, das sieht, hรถrt und intelligent handelt.
+ Werden Sie Teil der Revolution, die manuelle Dateneingabe fรผr immer verรคndert. Schaffen
+ Sie ein System, das sieht, hรถrt und intelligent handelt.
{
);
};
-export default AboutPage;
\ No newline at end of file
+export default AboutPage;
diff --git a/frontend/src/app/api/auth/[...nextauth]/route.ts b/frontend/src/app/api/auth/[...nextauth]/route.ts
index 0ed68abb..05fb6b9d 100644
--- a/frontend/src/app/api/auth/[...nextauth]/route.ts
+++ b/frontend/src/app/api/auth/[...nextauth]/route.ts
@@ -3,5 +3,3 @@ import { authOptions } from '@/server/auth/options';
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
-
-
diff --git a/frontend/src/app/api/trpc/[trpc]/route.ts b/frontend/src/app/api/trpc/[trpc]/route.ts
index 71436121..fb146f06 100644
--- a/frontend/src/app/api/trpc/[trpc]/route.ts
+++ b/frontend/src/app/api/trpc/[trpc]/route.ts
@@ -13,5 +13,3 @@ const handler = (req: Request) =>
});
export { handler as GET, handler as POST };
-
-
diff --git a/frontend/src/app/api/v1/auth/login/route.ts b/frontend/src/app/api/v1/auth/login/route.ts
index 8b94d9dc..8dc512c1 100644
--- a/frontend/src/app/api/v1/auth/login/route.ts
+++ b/frontend/src/app/api/v1/auth/login/route.ts
@@ -22,7 +22,9 @@ export async function POST(req: Request) {
.setIssuedAt()
.setExpirationTime('7d')
.sign(secret);
- return Response.json({ success: true, token, user: { id: user.id, email: user.email, name: user.name } });
+ return Response.json({
+ success: true,
+ token,
+ user: { id: user.id, email: user.email, name: user.name },
+ });
}
-
-
diff --git a/frontend/src/app/api/v1/auth/register/route.ts b/frontend/src/app/api/v1/auth/register/route.ts
index 1e14880e..086fa83b 100644
--- a/frontend/src/app/api/v1/auth/register/route.ts
+++ b/frontend/src/app/api/v1/auth/register/route.ts
@@ -10,7 +10,8 @@ export async function POST(req: Request) {
if (exists) return Response.json({ success: false, message: 'User exists' }, { status: 409 });
const passwordHash = await hash(password, 10);
const user = await prisma.user.create({ data: { email, passwordHash, name } });
- return Response.json({ success: true, user: { id: user.id, email: user.email, name: user.name } });
+ return Response.json({
+ success: true,
+ user: { id: user.id, email: user.email, name: user.name },
+ });
}
-
-
diff --git a/frontend/src/app/api/v1/forms/[id]/route.ts b/frontend/src/app/api/v1/forms/[id]/route.ts
index dbd1e7cc..5155948f 100644
--- a/frontend/src/app/api/v1/forms/[id]/route.ts
+++ b/frontend/src/app/api/v1/forms/[id]/route.ts
@@ -44,5 +44,3 @@ export async function DELETE(req: Request, ctx: any) {
await prisma.form.delete({ where: { id } });
return Response.json({ success: true });
}
-
-
diff --git a/frontend/src/app/api/v1/forms/[id]/status/route.ts b/frontend/src/app/api/v1/forms/[id]/status/route.ts
index 6a243dab..6a372c83 100644
--- a/frontend/src/app/api/v1/forms/[id]/status/route.ts
+++ b/frontend/src/app/api/v1/forms/[id]/status/route.ts
@@ -12,5 +12,3 @@ export async function PUT(req: Request, ctx: any) {
const updated = await prisma.form.update({ where: { id }, data: { isPublished } });
return Response.json({ success: true, status: updated.isPublished ? 'published' : 'draft' });
}
-
-
diff --git a/frontend/src/app/api/v1/forms/public/[id]/route.ts b/frontend/src/app/api/v1/forms/public/[id]/route.ts
index 2cac59b1..26a592fa 100644
--- a/frontend/src/app/api/v1/forms/public/[id]/route.ts
+++ b/frontend/src/app/api/v1/forms/public/[id]/route.ts
@@ -11,5 +11,3 @@ export async function GET(_req: Request, ctx: any) {
structure: form.schema,
});
}
-
-
diff --git a/frontend/src/app/api/v1/forms/route.ts b/frontend/src/app/api/v1/forms/route.ts
index 7c0d32a2..d11c0dca 100644
--- a/frontend/src/app/api/v1/forms/route.ts
+++ b/frontend/src/app/api/v1/forms/route.ts
@@ -39,7 +39,10 @@ export async function POST(req: Request) {
const body = await req.json();
const { title, description, structure, status, isTemplate } = body || {};
if (!title || !structure) {
- return Response.json({ success: false, message: 'Missing title or structure' }, { status: 400 });
+ return Response.json(
+ { success: false, message: 'Missing title or structure' },
+ { status: 400 },
+ );
}
const isPublished = status === 'published';
const created = await prisma.form.create({
@@ -64,5 +67,3 @@ export async function POST(req: Request) {
updated_at: created.updatedAt,
});
}
-
-
diff --git a/frontend/src/app/api/v1/submissions/route.ts b/frontend/src/app/api/v1/submissions/route.ts
index 0219f840..a437e6dc 100644
--- a/frontend/src/app/api/v1/submissions/route.ts
+++ b/frontend/src/app/api/v1/submissions/route.ts
@@ -2,11 +2,13 @@ import { prisma } from '@/lib/db';
export async function POST(req: Request) {
const { form_id, data } = await req.json();
- if (!form_id || !data) return Response.json({ message: 'Missing form_id or data' }, { status: 400 });
+ if (!form_id || !data)
+ return Response.json({ message: 'Missing form_id or data' }, { status: 400 });
const form = await prisma.form.findUnique({ where: { id: form_id } });
- if (!form || !form.isPublished) return Response.json({ message: 'Form not found or not published' }, { status: 404 });
- const created = await prisma.submission.create({ data: { formId: form_id, data, status: 'PENDING' } });
+ if (!form || !form.isPublished)
+ return Response.json({ message: 'Form not found or not published' }, { status: 404 });
+ const created = await prisma.submission.create({
+ data: { formId: form_id, data, status: 'PENDING' },
+ });
return Response.json({ success: true, id: created.id });
}
-
-
diff --git a/frontend/src/app/api/v1/user/me/route.ts b/frontend/src/app/api/v1/user/me/route.ts
index 0a248d8d..53486536 100644
--- a/frontend/src/app/api/v1/user/me/route.ts
+++ b/frontend/src/app/api/v1/user/me/route.ts
@@ -13,7 +13,10 @@ export async function GET(req: Request) {
const { payload } = await jwtVerify(token, secret);
const user = await prisma.user.findUnique({ where: { id: payload.sub as string } });
if (!user) return Response.json({ success: false, message: 'Not found' }, { status: 404 });
- return Response.json({ success: true, user: { id: user.id, email: user.email, name: user.name } });
+ return Response.json({
+ success: true,
+ user: { id: user.id, email: user.email, name: user.name },
+ });
} catch {
return Response.json({ success: false, message: 'Invalid token' }, { status: 401 });
}
@@ -32,10 +35,11 @@ export async function PUT(req: Request) {
where: { id: payload.sub as string },
data: { ...(name !== undefined && { name }) },
});
- return Response.json({ success: true, user: { id: user.id, email: user.email, name: user.name } });
+ return Response.json({
+ success: true,
+ user: { id: user.id, email: user.email, name: user.name },
+ });
} catch {
return Response.json({ success: false, message: 'Invalid token' }, { status: 401 });
}
}
-
-
diff --git a/frontend/src/app/api/v1/vision/route.ts b/frontend/src/app/api/v1/vision/route.ts
index 11ff31cf..5dbdabaf 100644
--- a/frontend/src/app/api/v1/vision/route.ts
+++ b/frontend/src/app/api/v1/vision/route.ts
@@ -40,29 +40,32 @@ export async function POST(req: NextRequest) {
return NextResponse.json({ content });
} catch (error: any) {
console.error('OpenAI Vision API Error:', error);
-
+
// Handle specific OpenAI errors
if (error.status === 429) {
- return NextResponse.json({
- error: 'OpenAI quota exceeded. Please check your billing at platform.openai.com/account/billing and add payment method or wait for quota reset.'
- }, { status: 429 });
+ return NextResponse.json(
+ {
+ error:
+ 'OpenAI quota exceeded. Please check your billing at platform.openai.com/account/billing and add payment method or wait for quota reset.',
+ },
+ { status: 429 },
+ );
}
-
+
if (error.status === 401) {
- return NextResponse.json({
- error: 'Invalid OpenAI API key. Please check your configuration.'
- }, { status: 401 });
+ return NextResponse.json(
+ {
+ error: 'Invalid OpenAI API key. Please check your configuration.',
+ },
+ { status: 401 },
+ );
}
-
- return NextResponse.json({
- error: error?.message || 'OpenAI Vision API error'
- }, { status: 500 });
+
+ return NextResponse.json(
+ {
+ error: error?.message || 'OpenAI Vision API error',
+ },
+ { status: 500 },
+ );
}
}
-
-
-
-
-
-
-
diff --git a/frontend/src/app/blog/[slug]/MDXContent.tsx b/frontend/src/app/blog/[slug]/MDXContent.tsx
index c1952be9..bd7dfc60 100644
--- a/frontend/src/app/blog/[slug]/MDXContent.tsx
+++ b/frontend/src/app/blog/[slug]/MDXContent.tsx
@@ -10,4 +10,4 @@ interface MDXContentProps {
export function MDXContent({ code }: MDXContentProps) {
const MDXComponent = useMDXComponent(code);
return
;
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/blog/[slug]/MDXContentClient.tsx b/frontend/src/app/blog/[slug]/MDXContentClient.tsx
index 5362b2a8..7ee3a7b7 100644
--- a/frontend/src/app/blog/[slug]/MDXContentClient.tsx
+++ b/frontend/src/app/blog/[slug]/MDXContentClient.tsx
@@ -8,7 +8,7 @@ import dynamic from 'next/dynamic';
// static export AND per-request SSR) crashes; client-only rendering doesn't,
// since the browser's React copy resolves the same call differently. Loading
// via next/dynamic with ssr:false skips server execution altogether.
-export const MDXContentClient = dynamic(
- () => import('./MDXContent').then((m) => m.MDXContent),
- { ssr: false, loading: () =>
Lade Inhaltโฆ
}
-);
+export const MDXContentClient = dynamic(() => import('./MDXContent').then((m) => m.MDXContent), {
+ ssr: false,
+ loading: () =>
Lade Inhaltโฆ
,
+});
diff --git a/frontend/src/app/blog/[slug]/page.tsx b/frontend/src/app/blog/[slug]/page.tsx
index ab1f3c8d..27e77e01 100644
--- a/frontend/src/app/blog/[slug]/page.tsx
+++ b/frontend/src/app/blog/[slug]/page.tsx
@@ -1,6 +1,6 @@
// created_date: 2025-07-10
// last_modified_date: 2025-07-10
-// last_modified_summary: "Dynamic MDX blog post page with CTA."
+// last_modified_summary: "Dynamic MDX blog post page with CTA."
import { allPosts } from '../../../../.contentlayer/generated';
import { notFound } from 'next/navigation';
@@ -8,14 +8,16 @@ import { MDXContentClient } from './MDXContentClient';
import Image from 'next/image';
import Link from 'next/link';
-export const generateStaticParams = async () => allPosts.map(p => ({ slug: p.slug }));
+export const generateStaticParams = async () => allPosts.map((p) => ({ slug: p.slug }));
-interface PageProps { params: Promise<{ slug: string }> }
+interface PageProps {
+ params: Promise<{ slug: string }>;
+}
export default async function BlogPostPage({ params }: PageProps) {
const { slug } = await params;
- const post = allPosts.find(p => p.slug === slug);
-
+ const post = allPosts.find((p) => p.slug === slug);
+
if (!post) {
return notFound();
}
@@ -24,7 +26,13 @@ export default async function BlogPostPage({ params }: PageProps) {
{post.coverImage && (
-
+
)}
{post.title}
@@ -36,10 +44,13 @@ export default async function BlogPostPage({ params }: PageProps) {
{/* CTA */}
Teste den Universal Form Builder selbst
-
+
Zum Builder โ
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/blog/page.tsx b/frontend/src/app/blog/page.tsx
index 7f0c119d..c8c62d37 100644
--- a/frontend/src/app/blog/page.tsx
+++ b/frontend/src/app/blog/page.tsx
@@ -14,11 +14,18 @@ export default function BlogPage() {
return (
- Insights & Gedanken
+
+ Insights & Gedanken
+
- Lass dich von unseren Ideen rund um intelligente Datenerfassung, KI-Gestรผtzte HR-Prozesse und moderne UX inspirieren.
+ Lass dich von unseren Ideen rund um intelligente Datenerfassung, KI-Gestรผtzte HR-Prozesse
+ und moderne UX inspirieren.
-
+
@@ -31,12 +38,24 @@ export default function BlogPage() {
{posts.map((post) => (
-
+
{post.coverImage && (
-
+
)}
-
+
{new Date(post.date).toLocaleDateString('de-CH')}
@@ -45,7 +64,10 @@ export default function BlogPage() {
{post.summary}
-
+
Weiterlesen โ
@@ -54,4 +76,4 @@ export default function BlogPage() {
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/builder/page.tsx b/frontend/src/app/builder/page.tsx
index ff3b6f3c..4fdfc594 100644
--- a/frontend/src/app/builder/page.tsx
+++ b/frontend/src/app/builder/page.tsx
@@ -38,11 +38,7 @@ export default function FormBuilderPage() {
};
if (!showFormBuilder) {
- return (
-
- );
+ return
;
}
return (
@@ -52,4 +48,4 @@ export default function FormBuilderPage() {
onFieldsChange={handleFieldsChange}
/>
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/components/AddFieldWizard.tsx b/frontend/src/app/components/AddFieldWizard.tsx
index aa61a72e..674cd7fc 100644
--- a/frontend/src/app/components/AddFieldWizard.tsx
+++ b/frontend/src/app/components/AddFieldWizard.tsx
@@ -14,12 +14,12 @@ interface AddFieldWizardProps {
className?: string;
}
-export function AddFieldWizard({
- isOpen,
- onClose,
- onAddField,
+export function AddFieldWizard({
+ isOpen,
+ onClose,
+ onAddField,
availableGroups,
- className = ""
+ className = '',
}: AddFieldWizardProps) {
const [step, setStep] = useState<'type' | 'details'>('type');
const [fieldType, setFieldType] = useState
('');
@@ -27,7 +27,7 @@ export function AddFieldWizard({
label: '',
placeholder: '',
required: false,
- group: ''
+ group: '',
});
const handleTypeSelect = (type: string) => {
@@ -50,12 +50,15 @@ export function AddFieldWizard({
required: fieldData.required,
placeholder: fieldData.placeholder.trim() || undefined,
group: fieldData.group.trim() || undefined,
- options: fieldType === 'select' ? [
- { value: '', label: `${fieldData.label} auswรคhlen` },
- { value: 'option1', label: 'Option 1' },
- { value: 'option2', label: 'Option 2' }
- ] : undefined,
- rows: fieldType === 'textarea' ? 3 : undefined
+ options:
+ fieldType === 'select'
+ ? [
+ { value: '', label: `${fieldData.label} auswรคhlen` },
+ { value: 'option1', label: 'Option 1' },
+ { value: 'option2', label: 'Option 2' },
+ ]
+ : undefined,
+ rows: fieldType === 'textarea' ? 3 : undefined,
};
onAddField(newField);
@@ -69,7 +72,7 @@ export function AddFieldWizard({
label: '',
placeholder: '',
required: false,
- group: ''
+ group: '',
});
onClose();
};
@@ -83,21 +86,37 @@ export function AddFieldWizard({
tel: 'Telefon',
date: 'Datum',
select: 'Auswahl',
- textarea: 'Textbereich'
+ textarea: 'Textbereich',
};
return labels[type] || type;
};
return (
-
-
e.stopPropagation()}>
+
+
e.stopPropagation()}
+ >
{/* Header */}
@@ -105,7 +124,9 @@ export function AddFieldWizard({
Neues Feld hinzufรผgen
- {step === 'type' ? 'Wรคhlen Sie einen Feldtyp' : `${getFieldTypeLabel(fieldType)}-Feld konfigurieren`}
+ {step === 'type'
+ ? 'Wรคhlen Sie einen Feldtyp'
+ : `${getFieldTypeLabel(fieldType)}-Feld konfigurieren`}
@@ -114,24 +135,37 @@ export function AddFieldWizard({
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg"
>
-
+
{/* Progress Indicator */}
-
+
{step === 'type' ? '1' : 'โ'}
-
-
@@ -149,11 +183,8 @@ export function AddFieldWizard({
Wรคhlen Sie den passenden Feldtyp fรผr Ihre Daten aus.
-
-
+
+
)}
@@ -162,8 +193,18 @@ export function AddFieldWizard({
@@ -184,7 +225,7 @@ export function AddFieldWizard({
name="fieldLabel"
label="Feldbezeichnung"
value={fieldData.label}
- onChange={(e) => setFieldData(prev => ({ ...prev, label: e.target.value }))}
+ onChange={(e) => setFieldData((prev) => ({ ...prev, label: e.target.value }))}
placeholder="z.B. Vollstรคndiger Name"
required
/>
@@ -195,7 +236,9 @@ export function AddFieldWizard({
name="fieldPlaceholder"
label="Platzhaltertext (optional)"
value={fieldData.placeholder}
- onChange={(e) => setFieldData(prev => ({ ...prev, placeholder: e.target.value }))}
+ onChange={(e) =>
+ setFieldData((prev) => ({ ...prev, placeholder: e.target.value }))
+ }
placeholder="z.B. Max Mustermann"
/>
@@ -206,10 +249,10 @@ export function AddFieldWizard({
name="fieldGroup"
label="Gruppe (optional)"
value={fieldData.group}
- onChange={(e) => setFieldData(prev => ({ ...prev, group: e.target.value }))}
+ onChange={(e) => setFieldData((prev) => ({ ...prev, group: e.target.value }))}
options={[
{ value: '', label: 'Keine Gruppe' },
- ...availableGroups.map(group => ({ value: group, label: group }))
+ ...availableGroups.map((group) => ({ value: group, label: group })),
]}
/>
)}
@@ -220,15 +263,16 @@ export function AddFieldWizard({
type="checkbox"
id="fieldRequired"
checked={fieldData.required}
- onChange={(e) => setFieldData(prev => ({ ...prev, required: e.target.checked }))}
+ onChange={(e) =>
+ setFieldData((prev) => ({ ...prev, required: e.target.checked }))
+ }
className="h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
/>
-
- Pflichtfeld
-
+ Pflichtfeld
- Dieses Feld muss ausgefรผllt werden, bevor das Formular abgesendet werden kann.
+ Dieses Feld muss ausgefรผllt werden, bevor das Formular abgesendet werden
+ kann.
@@ -248,11 +292,15 @@ export function AddFieldWizard({
onChange={() => {}}
placeholder={fieldData.placeholder || 'Platzhaltertext...'}
required={fieldData.required}
- options={fieldType === 'select' ? [
- { value: '', label: `${fieldData.label || 'Feld'} auswรคhlen` },
- { value: 'option1', label: 'Option 1' },
- { value: 'option2', label: 'Option 2' }
- ] : undefined}
+ options={
+ fieldType === 'select'
+ ? [
+ { value: '', label: `${fieldData.label || 'Feld'} auswรคhlen` },
+ { value: 'option1', label: 'Option 1' },
+ { value: 'option2', label: 'Option 2' },
+ ]
+ : undefined
+ }
rows={fieldType === 'textarea' ? 3 : undefined}
/>
@@ -265,29 +313,17 @@ export function AddFieldWizard({
{step === 'details' && (
-
+
โ Zurรผck
)}
-
+
Abbrechen
{step === 'details' && (
-
+
Feld hinzufรผgen
)}
@@ -296,4 +332,4 @@ export function AddFieldWizard({
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/components/BreadcrumbNavigation.tsx b/frontend/src/app/components/BreadcrumbNavigation.tsx
index ec9c6cf2..c223e153 100644
--- a/frontend/src/app/components/BreadcrumbNavigation.tsx
+++ b/frontend/src/app/components/BreadcrumbNavigation.tsx
@@ -18,7 +18,12 @@ export function BreadcrumbNavigation({ items }: BreadcrumbNavigationProps) {
{items.map((item, index) => (
{index > 0 && (
-
+
)}
@@ -26,8 +31,8 @@ export function BreadcrumbNavigation({ items }: BreadcrumbNavigationProps) {
@@ -37,31 +42,39 @@ export function BreadcrumbNavigation({ items }: BreadcrumbNavigationProps) {
)}
) : (
-
+
{item.label}
)}
))}
-
+
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/components/BuilderBottomBar.tsx b/frontend/src/app/components/BuilderBottomBar.tsx
index e6454c84..c3783e8c 100644
--- a/frontend/src/app/components/BuilderBottomBar.tsx
+++ b/frontend/src/app/components/BuilderBottomBar.tsx
@@ -66,4 +66,4 @@ export function BuilderBottomBar({
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/components/BuilderToolbar.tsx b/frontend/src/app/components/BuilderToolbar.tsx
index c95ad6a8..d7e7abe3 100644
--- a/frontend/src/app/components/BuilderToolbar.tsx
+++ b/frontend/src/app/components/BuilderToolbar.tsx
@@ -83,4 +83,4 @@ export function BuilderToolbar({
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/components/Button.tsx b/frontend/src/app/components/Button.tsx
index 33b19cdd..5b3afc72 100644
--- a/frontend/src/app/components/Button.tsx
+++ b/frontend/src/app/components/Button.tsx
@@ -7,29 +7,33 @@ interface ButtonProps extends React.ButtonHTMLAttributes
{
className?: string;
}
-export function Button({
- variant = 'primary',
- size = 'md',
- children,
- className = "",
- ...props
+export function Button({
+ variant = 'primary',
+ size = 'md',
+ children,
+ className = '',
+ ...props
}: ButtonProps) {
- const baseClasses = "font-semibold rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500/20 transition-all duration-200 transform hover:scale-105 active:scale-95";
-
+ const baseClasses =
+ 'font-semibold rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500/20 transition-all duration-200 transform hover:scale-105 active:scale-95';
+
const sizeClasses = {
- sm: "px-4 py-2 text-sm",
- md: "px-6 py-3 text-sm",
- lg: "px-8 py-4 text-base"
+ sm: 'px-4 py-2 text-sm',
+ md: 'px-6 py-3 text-sm',
+ lg: 'px-8 py-4 text-base',
};
-
+
const variantClasses = {
- primary: "bg-gradient-to-r from-blue-600 to-indigo-600 text-white hover:from-blue-700 hover:to-indigo-700 shadow-lg hover:shadow-xl",
- secondary: "bg-gradient-to-r from-gray-600 to-gray-700 text-white hover:from-gray-700 hover:to-gray-800 shadow-lg hover:shadow-xl",
- outline: "border-2 border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50 hover:border-gray-300 dark:hover:border-gray-500 backdrop-blur-sm"
+ primary:
+ 'bg-gradient-to-r from-blue-600 to-indigo-600 text-white hover:from-blue-700 hover:to-indigo-700 shadow-lg hover:shadow-xl',
+ secondary:
+ 'bg-gradient-to-r from-gray-600 to-gray-700 text-white hover:from-gray-700 hover:to-gray-800 shadow-lg hover:shadow-xl',
+ outline:
+ 'border-2 border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50 hover:border-gray-300 dark:hover:border-gray-500 backdrop-blur-sm',
};
-
- const disabledClasses = props.disabled ? "opacity-50 cursor-not-allowed hover:bg-current" : "";
-
+
+ const disabledClasses = props.disabled ? 'opacity-50 cursor-not-allowed hover:bg-current' : '';
+
return (
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/components/ConfirmDialog.tsx b/frontend/src/app/components/ConfirmDialog.tsx
index 1bbb20d4..2f1c4aaa 100644
--- a/frontend/src/app/components/ConfirmDialog.tsx
+++ b/frontend/src/app/components/ConfirmDialog.tsx
@@ -21,7 +21,7 @@ export function ConfirmDialog({
}: ConfirmDialogProps) {
React.useEffect(() => {
if (!isOpen) return;
-
+
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') onCancel();
};
@@ -40,7 +40,9 @@ export function ConfirmDialog({
>
{title}
-
{message}
+
+ {message}
+
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/app/components/DynamicForm.tsx b/frontend/src/app/components/DynamicForm.tsx
index af778ee7..0a76bf2c 100644
--- a/frontend/src/app/components/DynamicForm.tsx
+++ b/frontend/src/app/components/DynamicForm.tsx
@@ -23,14 +23,18 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
const [fields, setFields] = useState
(initialFields);
const [formData, setFormData] = useState(() => {
const data: FormData = {};
- initialFields.forEach(field => {
+ initialFields.forEach((field) => {
data[field.name] = '';
});
return data;
});
-
- const { validateForm, validateSingleField, getFieldError, hasErrors, clearErrors } = useFormValidation(fields);
- const { savedData, saveNow, clearSavedData, getLastSaveTime, hasSavedData } = useAutoSave(formData, fields);
+
+ const { validateForm, validateSingleField, getFieldError, hasErrors, clearErrors } =
+ useFormValidation(fields);
+ const { savedData, saveNow, clearSavedData, getLastSaveTime, hasSavedData } = useAutoSave(
+ formData,
+ fields,
+ );
const { saveTemplate } = useTemplateManager();
const [showSaveTemplateModal, setShowSaveTemplateModal] = useState(false);
const [showGroupManager, setShowGroupManager] = useState(false);
@@ -38,7 +42,7 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
// Load saved data on component mount
useEffect(() => {
- if (savedData && Object.keys(formData).every(key => !formData[key])) {
+ if (savedData && Object.keys(formData).every((key) => !formData[key])) {
// Only load if current form is empty
setFormData(savedData.formData);
if (savedData.fields.length !== fields.length) {
@@ -48,11 +52,13 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
}
}, [savedData]); // Only run when savedData changes, not on every render
- const handleInputChange = (e: React.ChangeEvent) => {
+ const handleInputChange = (
+ e: React.ChangeEvent,
+ ) => {
const { name, value } = e.target;
- setFormData(prev => ({
+ setFormData((prev) => ({
...prev,
- [name]: value
+ [name]: value,
}));
};
@@ -64,7 +70,7 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const errors = validateForm(formData);
-
+
if (errors.length === 0) {
clearSavedData(); // Clear auto-save data on successful submit
onSubmit(formData);
@@ -85,10 +91,8 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
const handleDeleteGroup = (groupName: string) => {
// Move all fields from this group to 'Allgemeine Felder'
- const updatedFields = fields.map(field =>
- field.group === groupName
- ? { ...field, group: undefined }
- : field
+ const updatedFields = fields.map((field) =>
+ field.group === groupName ? { ...field, group: undefined } : field,
);
setFields(updatedFields);
onFieldsChange?.(updatedFields);
@@ -96,7 +100,7 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
const getAvailableGroups = () => {
const groups = new Set();
- fields.forEach(field => {
+ fields.forEach((field) => {
if (field.group) {
groups.add(field.group);
}
@@ -107,9 +111,9 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
const addField = (fieldConfig: FieldConfig) => {
const newFields = [...fields, fieldConfig];
setFields(newFields);
- setFormData(prev => ({
+ setFormData((prev) => ({
...prev,
- [fieldConfig.name]: ''
+ [fieldConfig.name]: '',
}));
onFieldsChange?.(newFields);
};
@@ -128,7 +132,7 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
range: 'Bereich',
file: 'Datei',
url: 'URL',
- password: 'Passwort'
+ password: 'Passwort',
};
const fieldConfig: FieldConfig = {
@@ -138,23 +142,26 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
label: fieldNames[type] || type,
required: false,
placeholder: type === 'select' ? undefined : `${fieldNames[type]} eingeben...`,
- options: type === 'select' ? [
- { value: '', label: 'Auswahl treffen' },
- { value: 'option1', label: 'Option 1' },
- { value: 'option2', label: 'Option 2' }
- ] : undefined,
- rows: type === 'textarea' ? 3 : undefined
+ options:
+ type === 'select'
+ ? [
+ { value: '', label: 'Auswahl treffen' },
+ { value: 'option1', label: 'Option 1' },
+ { value: 'option2', label: 'Option 2' },
+ ]
+ : undefined,
+ rows: type === 'textarea' ? 3 : undefined,
};
addField(fieldConfig);
};
const removeField = (fieldId: string) => {
- const newFields = fields.filter(field => field.id !== fieldId);
+ const newFields = fields.filter((field) => field.id !== fieldId);
setFields(newFields);
- const fieldToRemove = fields.find(field => field.id === fieldId);
+ const fieldToRemove = fields.find((field) => field.id === fieldId);
if (fieldToRemove) {
- setFormData(prev => {
+ setFormData((prev) => {
const newData = { ...prev };
delete newData[fieldToRemove.name];
return newData;
@@ -164,8 +171,8 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
};
const updateField = (fieldId: string, updates: Partial) => {
- const newFields = fields.map(field =>
- field.id === fieldId ? { ...field, ...updates } : field
+ const newFields = fields.map((field) =>
+ field.id === fieldId ? { ...field, ...updates } : field,
);
setFields(newFields);
onFieldsChange?.(newFields);
@@ -203,7 +210,11 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
@@ -225,8 +236,18 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic
{fields.length === 0 && (
@@ -242,19 +263,25 @@ export function DynamicForm({ initialFields, onSubmit, onFieldsChange }: Dynamic