From e5f3277a6c644e2730d546f01f5d5b05e7148c7f Mon Sep 17 00:00:00 2001 From: adarsshkg-codebank Date: Mon, 23 Feb 2026 17:20:57 +0530 Subject: [PATCH 1/3] CI pipeline --- .github/workflows/ci.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..6e09b4f9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +jobs: + lint-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + + - name: Run lint + run: bun run lint + + - name: Run tests + run: bun run test + + - name: Run build + run: bun run build From 8ee3912e5918fec81c30da6d684efdafecf631bd Mon Sep 17 00:00:00 2001 From: adarsshkg-codebank Date: Mon, 23 Feb 2026 18:21:15 +0530 Subject: [PATCH 2/3] fix:lint errors --- src/components/Header.test.tsx | 2 +- src/components/app-sidebar.test.tsx | 4 +- src/components/app-sidebar.tsx | 4 +- src/components/editor-canvas.test.tsx | 6 +-- src/components/editor-sidebar-tabs.test.tsx | 2 +- src/components/field-properties.test.tsx | 4 +- src/components/field-properties.tsx | 6 +-- src/components/fields/field-items.test.tsx | 2 +- src/components/fields/field-preview.test.tsx | 5 ++- src/components/fields/field-preview.tsx | 2 +- src/components/nav-main.tsx | 2 +- src/components/ui/badge.test.tsx | 2 +- src/components/ui/button.test.tsx | 2 +- src/components/ui/complex-primitives.test.tsx | 8 ++-- src/components/ui/field.test.tsx | 4 +- src/components/ui/field.tsx | 2 +- src/components/ui/input.test.tsx | 2 +- src/components/ui/primitives.test.tsx | 4 +- src/components/ui/toast.tsx | 3 +- .../validation-rule-builder.test.tsx | 4 +- src/components/validation-rule-builder.tsx | 27 ++++++------- src/hooks/use-mobile.test.ts | 4 +- src/hooks/use-toast.ts | 40 +++++++++---------- src/lib/auth-client.test.ts | 2 +- src/lib/utils.test.ts | 6 +-- src/lib/validation-engine.test.ts | 15 +++---- src/lib/validation-engine.ts | 4 +- src/main.tsx | 1 - src/routes/_layout.analytics.index.tsx | 2 +- src/routes/_layout.analytics.responses.tsx | 22 +++++----- src/routes/_layout.analytics.tsx | 2 +- src/routes/_layout.dashboard.tsx | 5 +-- src/routes/_layout.editor.$formId.tsx | 4 +- src/routes/_layout.editor.index.tsx | 2 +- src/routes/_layout.my-responses.tsx | 2 +- src/routes/_layout.tsx | 2 +- src/routes/email-verified.tsx | 6 +-- src/routes/form.$formId.tsx | 20 +++++----- src/routes/index.tsx | 2 +- 39 files changed, 116 insertions(+), 122 deletions(-) diff --git a/src/components/Header.test.tsx b/src/components/Header.test.tsx index 676df3bc..ae8d9a4d 100644 --- a/src/components/Header.test.tsx +++ b/src/components/Header.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import Header from './Header'; // Mock TanStack Router Link diff --git a/src/components/app-sidebar.test.tsx b/src/components/app-sidebar.test.tsx index 512cbb22..49b7baac 100644 --- a/src/components/app-sidebar.test.tsx +++ b/src/components/app-sidebar.test.tsx @@ -1,8 +1,8 @@ import { render, screen } from '@testing-library/react'; -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; +import { RouterProvider, createMemoryHistory, createRootRoute, createRouter } from '@tanstack/react-router'; import { AppSidebar } from './app-sidebar'; import { SidebarProvider } from '@/components/ui/sidebar'; -import { createRouter, createMemoryHistory, RouterProvider, createRootRoute } from '@tanstack/react-router'; // Mock useIsMobile hook vi.mock('@/hooks/use-mobile', () => ({ diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index 3ed0c32f..dc226630 100644 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -73,7 +73,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { const navigate = useNavigate() const { data: session } = authClient.useSession() - const userName = session?.user?.name || session?.user?.email || 'User' + const userName = session?.user.name || session?.user.email || 'User' const userInitial = userName.charAt(0).toUpperCase() const handleLogout = async () => { @@ -114,7 +114,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) {
{userName} - {session?.user?.email && session?.user?.name && ( + {session?.user.email && session.user.name && ( {session.user.email} )}
diff --git a/src/components/editor-canvas.test.tsx b/src/components/editor-canvas.test.tsx index 8cccf729..c6ec997e 100644 --- a/src/components/editor-canvas.test.tsx +++ b/src/components/editor-canvas.test.tsx @@ -1,10 +1,10 @@ -import { render, screen, fireEvent } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { EditorCanvas } from './editor-canvas'; import type { CanvasField } from './fields/field-preview'; -const mockFields: CanvasField[] = [ +const mockFields: Array = [ { id: '1', type: 'text', label: 'Field 1' }, { id: '2', type: 'number', label: 'Field 2' }, ]; diff --git a/src/components/editor-sidebar-tabs.test.tsx b/src/components/editor-sidebar-tabs.test.tsx index 4c40004e..a9d5a584 100644 --- a/src/components/editor-sidebar-tabs.test.tsx +++ b/src/components/editor-sidebar-tabs.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { TabsLine } from './editor-sidebar-tabs'; describe('TabsLine', () => { diff --git a/src/components/field-properties.test.tsx b/src/components/field-properties.test.tsx index e58a923b..51ef361e 100644 --- a/src/components/field-properties.test.tsx +++ b/src/components/field-properties.test.tsx @@ -1,6 +1,6 @@ -import { render, screen, fireEvent } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { FieldProperties } from './field-properties'; import type { CanvasField } from './fields/field-preview'; diff --git a/src/components/field-properties.tsx b/src/components/field-properties.tsx index 552f1390..38d19e9e 100644 --- a/src/components/field-properties.tsx +++ b/src/components/field-properties.tsx @@ -14,7 +14,10 @@ */ import { useEffect, useState } from 'react' +import { ChevronDown } from 'lucide-react' +import { ValidationRuleBuilder } from './validation-rule-builder' import type { CanvasField } from './fields/field-preview' +import type { ValidationConfig } from '@/lib/validation-engine' import { Button } from '@/components/ui/button' import { Dialog, @@ -38,9 +41,6 @@ import { CollapsibleContent, CollapsibleTrigger, } from '@/components/ui/collapsible' -import { ChevronDown } from 'lucide-react' -import { ValidationRuleBuilder } from './validation-rule-builder' -import type { ValidationConfig } from '@/lib/validation-engine' interface FieldPropertiesProps { field: CanvasField | null // Field being edited (null when no field selected) diff --git a/src/components/fields/field-items.test.tsx b/src/components/fields/field-items.test.tsx index 593af319..f5b3487a 100644 --- a/src/components/fields/field-items.test.tsx +++ b/src/components/fields/field-items.test.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react'; -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { FieldItems } from './field-items'; describe('FieldItems', () => { diff --git a/src/components/fields/field-preview.test.tsx b/src/components/fields/field-preview.test.tsx index 95a3daaa..d86b650d 100644 --- a/src/components/fields/field-preview.test.tsx +++ b/src/components/fields/field-preview.test.tsx @@ -1,7 +1,8 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { describe, it, expect, vi } from 'vitest'; -import { FieldPreview, type CanvasField } from './field-preview'; +import { describe, expect, it, vi } from 'vitest'; +import { FieldPreview } from './field-preview'; +import type {CanvasField} from './field-preview'; const mockField: CanvasField = { id: 'test-id', diff --git a/src/components/fields/field-preview.tsx b/src/components/fields/field-preview.tsx index 4709b9ec..311a5ff3 100644 --- a/src/components/fields/field-preview.tsx +++ b/src/components/fields/field-preview.tsx @@ -1,4 +1,5 @@ import { Settings, Star, Trash2 } from 'lucide-react' +import type { ValidationConfig } from '@/lib/validation-engine' import { Card } from '@/components/ui/card' import { Input } from '@/components/ui/input' import { Checkbox } from '@/components/ui/checkbox' @@ -6,7 +7,6 @@ import { Label } from '@/components/ui/label' import { Button } from '@/components/ui/button' import { Field, FieldContent, FieldLabel } from '@/components/ui/field' import { Slider } from '@/components/ui/slider' -import type { ValidationConfig } from '@/lib/validation-engine' export interface CanvasField { id: string diff --git a/src/components/nav-main.tsx b/src/components/nav-main.tsx index 9a91c2e7..5d0ccf11 100644 --- a/src/components/nav-main.tsx +++ b/src/components/nav-main.tsx @@ -1,8 +1,8 @@ 'use client' import { ChevronRight } from 'lucide-react' -import type { LucideIcon } from 'lucide-react' import { Link } from '@tanstack/react-router' +import type { LucideIcon } from 'lucide-react' import { Collapsible, diff --git a/src/components/ui/badge.test.tsx b/src/components/ui/badge.test.tsx index 5cccd8ae..d37e7cb0 100644 --- a/src/components/ui/badge.test.tsx +++ b/src/components/ui/badge.test.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react'; -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { Badge } from './badge'; describe('Badge', () => { diff --git a/src/components/ui/button.test.tsx b/src/components/ui/button.test.tsx index fdd740db..68c93613 100644 --- a/src/components/ui/button.test.tsx +++ b/src/components/ui/button.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { Button } from './button'; describe('Button', () => { diff --git a/src/components/ui/complex-primitives.test.tsx b/src/components/ui/complex-primitives.test.tsx index 58a140ef..236a82fb 100644 --- a/src/components/ui/complex-primitives.test.tsx +++ b/src/components/ui/complex-primitives.test.tsx @@ -1,14 +1,14 @@ -import { render, screen, fireEvent } from '@testing-library/react'; -import { describe, it, expect, vi } from 'vitest'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; import { Switch } from './switch'; import { Slider } from './slider'; import { Sheet, - SheetTrigger, SheetContent, + SheetDescription, SheetHeader, SheetTitle, - SheetDescription + SheetTrigger } from './sheet'; describe('Interactive UI Components', () => { diff --git a/src/components/ui/field.test.tsx b/src/components/ui/field.test.tsx index bbd3f88f..1bf8561b 100644 --- a/src/components/ui/field.test.tsx +++ b/src/components/ui/field.test.tsx @@ -1,12 +1,12 @@ import { render, screen } from '@testing-library/react'; -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { Field, - FieldLabel, FieldContent, FieldDescription, FieldError, FieldGroup, + FieldLabel, FieldLegend, FieldSet } from './field'; diff --git a/src/components/ui/field.tsx b/src/components/ui/field.tsx index 53aac96c..c4c1e3cf 100644 --- a/src/components/ui/field.tsx +++ b/src/components/ui/field.tsx @@ -203,7 +203,7 @@ function FieldError({ ...new Map(errors.map((error) => [error?.message, error])).values(), ] - if (uniqueErrors?.length == 1) { + if (uniqueErrors.length == 1) { return uniqueErrors[0]?.message } diff --git a/src/components/ui/input.test.tsx b/src/components/ui/input.test.tsx index 794be45e..ef8f7b99 100644 --- a/src/components/ui/input.test.tsx +++ b/src/components/ui/input.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { Input } from './input'; describe('Input', () => { diff --git a/src/components/ui/primitives.test.tsx b/src/components/ui/primitives.test.tsx index 4ee9d980..2cc5f6b5 100644 --- a/src/components/ui/primitives.test.tsx +++ b/src/components/ui/primitives.test.tsx @@ -1,5 +1,5 @@ -import { render, screen, fireEvent } from '@testing-library/react'; -import { describe, it, expect, vi } from 'vitest'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; import { Checkbox } from './checkbox'; import { Separator } from './separator'; import { Skeleton } from './skeleton'; diff --git a/src/components/ui/toast.tsx b/src/components/ui/toast.tsx index fdfb99fe..d7e071ad 100644 --- a/src/components/ui/toast.tsx +++ b/src/components/ui/toast.tsx @@ -1,7 +1,8 @@ import * as React from "react" import * as ToastPrimitives from "@radix-ui/react-toast" -import { cva, type VariantProps } from "class-variance-authority" +import { cva } from "class-variance-authority" import { X } from "lucide-react" +import type {VariantProps} from "class-variance-authority"; import { cn } from "@/lib/utils" diff --git a/src/components/validation-rule-builder.test.tsx b/src/components/validation-rule-builder.test.tsx index 19114aa9..423c247f 100644 --- a/src/components/validation-rule-builder.test.tsx +++ b/src/components/validation-rule-builder.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react'; -import { describe, it, expect, vi, beforeAll } from 'vitest'; -import { ValidationRuleBuilder } from './validation-rule-builder'; +import { beforeAll, describe, expect, it, vi } from 'vitest'; import userEvent from '@testing-library/user-event'; +import { ValidationRuleBuilder } from './validation-rule-builder'; // Mock pointer capture for Radix UI beforeAll(() => { diff --git a/src/components/validation-rule-builder.tsx b/src/components/validation-rule-builder.tsx index ff786e1d..da5ece3c 100644 --- a/src/components/validation-rule-builder.tsx +++ b/src/components/validation-rule-builder.tsx @@ -12,8 +12,9 @@ * are pre-configured and users just need to set parameters. */ -import { useState, useMemo } from 'react' -import { Plus, X, Info, AlertTriangle, CheckCircle2 } from 'lucide-react' +import { useMemo, useState } from 'react' +import { AlertTriangle, CheckCircle2, Info, Plus, X } from 'lucide-react' +import type { RuleTemplate, ValidationConfig } from '@/lib/validation-engine'; import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' @@ -32,11 +33,11 @@ import { TooltipTrigger, } from '@/components/ui/tooltip' import { - RULE_TEMPLATES, - getRulesForFieldType, PREDEFINED_PATTERNS, - type ValidationConfig, - type RuleTemplate, + RULE_TEMPLATES, + + + getRulesForFieldType } from '@/lib/validation-engine' interface ValidationRuleBuilderProps { @@ -75,10 +76,6 @@ const CATEGORY_COLORS: Record = { 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-200', } -interface ActiveRule { - ruleId: string - params?: Record -} export function ValidationRuleBuilder({ fieldType, @@ -86,10 +83,10 @@ export function ValidationRuleBuilder({ onChange, }: ValidationRuleBuilderProps) { // State for currently active validation rules on this field - const [activeRules, setActiveRules] = useState(() => { + const [activeRules, setActiveRules] = useState>(() => { // Initialize active rules from existing validation config // This ensures the UI reflects the current validation state - const rules: ActiveRule[] = [] + const rules: Array = [] if (currentValidation.minLength !== undefined) { rules.push({ ruleId: 'minLength', @@ -135,9 +132,9 @@ export function ValidationRuleBuilder({ // Group rules by category const rulesByCategory = useMemo(() => { - const grouped: Record = {} + const grouped: Record> = {} for (const rule of applicableRules) { - if (!grouped[rule.category]) { + if (!(rule.category in grouped)) { grouped[rule.category] = [] } grouped[rule.category].push(rule) @@ -147,7 +144,7 @@ export function ValidationRuleBuilder({ // Build validation config from active rules const buildConfig = ( - rules: ActiveRule[], + rules: Array, required?: boolean, ): ValidationConfig => { const config: ValidationConfig = { diff --git a/src/hooks/use-mobile.test.ts b/src/hooks/use-mobile.test.ts index 9104d5dd..34e1276c 100644 --- a/src/hooks/use-mobile.test.ts +++ b/src/hooks/use-mobile.test.ts @@ -1,5 +1,5 @@ -import { renderHook, act } from '@testing-library/react'; -import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { act, renderHook } from '@testing-library/react'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { useIsMobile } from './use-mobile'; describe('useIsMobile', () => { diff --git a/src/hooks/use-toast.ts b/src/hooks/use-toast.ts index d4d79a4c..c6515f93 100644 --- a/src/hooks/use-toast.ts +++ b/src/hooks/use-toast.ts @@ -51,24 +51,24 @@ type ActionType = typeof actionTypes type Action = | { - type: ActionType['ADD_TOAST'] - toast: ToasterToast - } + type: ActionType['ADD_TOAST'] + toast: ToasterToast + } | { - type: ActionType['UPDATE_TOAST'] - toast: Partial - } + type: ActionType['UPDATE_TOAST'] + toast: Partial + } | { - type: ActionType['DISMISS_TOAST'] - toastId?: ToasterToast['id'] - } + type: ActionType['DISMISS_TOAST'] + toastId?: ToasterToast['id'] + } | { - type: ActionType['REMOVE_TOAST'] - toastId?: ToasterToast['id'] - } + type: ActionType['REMOVE_TOAST'] + toastId?: ToasterToast['id'] + } interface State { - toasts: ToasterToast[] + toasts: Array } // Store timeout references for proper cleanup @@ -120,8 +120,8 @@ export const reducer = (state: State, action: Action): State => { addToRemoveQueue(toastId) } else { // Queue all toasts for removal - state.toasts.forEach((toast) => { - addToRemoveQueue(toast.id) + state.toasts.forEach((t) => { + addToRemoveQueue(t.id) }) } @@ -131,9 +131,9 @@ export const reducer = (state: State, action: Action): State => { toasts: state.toasts.map((t) => t.id === toastId || toastId === undefined ? { - ...t, - open: false, - } + ...t, + open: false, + } : t, ), } @@ -181,10 +181,10 @@ function toast({ ...props }: Toast) { const id = genId() // Update function to modify existing toast - const update = (props: ToasterToast) => + const update = (newProps: ToasterToast) => dispatch({ type: 'UPDATE_TOAST', - toast: { ...props, id }, + toast: { ...newProps, id }, }) // Dismiss function to close toast immediately diff --git a/src/lib/auth-client.test.ts b/src/lib/auth-client.test.ts index 652e307b..f9409ffe 100644 --- a/src/lib/auth-client.test.ts +++ b/src/lib/auth-client.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { authClient } from './auth-client'; describe('authClient', () => { diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index c8a99d71..eed162b7 100644 --- a/src/lib/utils.test.ts +++ b/src/lib/utils.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { cn } from './utils'; describe('cn utility', () => { @@ -7,12 +7,12 @@ describe('cn utility', () => { }); it('handles conditional classes (truthy)', () => { - const isActive = true; + const isActive = true as boolean; expect(cn('base', isActive && 'active')).toBe('base active'); }); it('handles conditional classes (falsy)', () => { - const isActive = false; + const isActive = false as boolean; expect(cn('base', isActive && 'active')).toBe('base'); }); diff --git a/src/lib/validation-engine.test.ts b/src/lib/validation-engine.test.ts index 8a401309..ae21e92e 100644 --- a/src/lib/validation-engine.test.ts +++ b/src/lib/validation-engine.test.ts @@ -1,15 +1,16 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { - validateField, - validateForm, + PREDEFINED_PATTERNS, + RULE_TEMPLATES, + buildValidationConfig, - getRulesForFieldType, combinePatterns, getPatternDescription, - PREDEFINED_PATTERNS, - RULE_TEMPLATES, - type ValidationConfig, + getRulesForFieldType, + validateField, + validateForm } from './validation-engine'; +import type {ValidationConfig} from './validation-engine'; describe('Validation Engine', () => { describe('getPatternDescription', () => { diff --git a/src/lib/validation-engine.ts b/src/lib/validation-engine.ts index 01c33eef..9f98e261 100644 --- a/src/lib/validation-engine.ts +++ b/src/lib/validation-engine.ts @@ -632,7 +632,7 @@ export function buildValidationConfig( * Combine multiple regex patterns with AND logic * This creates a pattern that matches if ALL patterns match */ -export function combinePatterns(patterns: string[]): string { +export function combinePatterns(patterns: Array): string { if (patterns.length === 0) return '' if (patterns.length === 1) return patterns[0] @@ -644,7 +644,7 @@ export function combinePatterns(patterns: string[]): string { /** * Get rules applicable to a field type */ -export function getRulesForFieldType(fieldType: string): RuleTemplate[] { +export function getRulesForFieldType(fieldType: string): Array { const textTypes = ['text', 'textarea', 'Input', 'input'] const numberTypes = ['number', 'slider', 'cgpa'] diff --git a/src/main.tsx b/src/main.tsx index c950f24c..ddb56cda 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -23,7 +23,6 @@ declare module '@tanstack/react-router' { const rootElement = document.getElementById('app') if (rootElement && !rootElement.innerHTML) { - const queryClient = new QueryClient() const root = ReactDOM.createRoot(rootElement) root.render( diff --git a/src/routes/_layout.analytics.index.tsx b/src/routes/_layout.analytics.index.tsx index 5032909e..9291a3a8 100644 --- a/src/routes/_layout.analytics.index.tsx +++ b/src/routes/_layout.analytics.index.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from '@tanstack/react-router' import { useQuery } from '@tanstack/react-query' -import { Loader2, AlertCircle, FileText, Users, ClipboardList } from 'lucide-react' +import { AlertCircle, ClipboardList, FileText, Loader2, Users } from 'lucide-react' import { formsApi } from '@/api/forms' import { Card, diff --git a/src/routes/_layout.analytics.responses.tsx b/src/routes/_layout.analytics.responses.tsx index 6a7c7e1b..15a570b1 100644 --- a/src/routes/_layout.analytics.responses.tsx +++ b/src/routes/_layout.analytics.responses.tsx @@ -1,9 +1,10 @@ import { createFileRoute } from '@tanstack/react-router' import { useQuery } from '@tanstack/react-query' -import { Loader2, AlertCircle, FileText } from 'lucide-react' -import { responsesApi } from '@/api/responses' -import { formsApi, type Form } from '@/api/forms' +import { AlertCircle, FileText, Loader2 } from 'lucide-react' import type { FormResponseForOwner } from '@/api/responses' +import type { Form } from '@/api/forms'; +import { responsesApi } from '@/api/responses' +import { formsApi } from '@/api/forms' import { Card, CardContent, @@ -114,18 +115,13 @@ function ResponsesPage() { {/* Loading / Error handling */} - {(isFormsLoading || isAllResponsesLoading) && ( + {isAllResponsesLoading && (
Loading responses...
)} - {forms && forms.length === 0 && ( -
- No forms found. Create a form first to collect responses. -
- )} {/* Show aggregated responses grouped by form */} {allResponses && allResponses.length > 0 ? ( @@ -135,19 +131,19 @@ function ResponsesPage() { {group.formTitle || 'Untitled Form'} - {group.responses?.length + {group.responses.length ? `${group.responses.length} response${group.responses.length === 1 ? '' : 's'}` : 'No responses yet'} - {group.responses && group.responses.length > 0 ? ( + {group.responses.length > 0 ? (
{group.responses.map((response, idx) => (

Response #{idx + 1}

- {Object.entries(response.answers || {}).map(([k, v]) => ( + {Object.entries(response.answers).map(([k, v]) => (
{k}:
@@ -167,7 +163,7 @@ function ResponsesPage() { ))}
) : ( - !isFormsLoading && !isAllResponsesLoading && ( + !isAllResponsesLoading && (
No responses received yet.
) )} diff --git a/src/routes/_layout.analytics.tsx b/src/routes/_layout.analytics.tsx index 0e9724e2..1cb253d9 100644 --- a/src/routes/_layout.analytics.tsx +++ b/src/routes/_layout.analytics.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, Outlet } from '@tanstack/react-router' +import { Outlet, createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/_layout/analytics')({ component: AnalyticsLayout, diff --git a/src/routes/_layout.dashboard.tsx b/src/routes/_layout.dashboard.tsx index 61cfc48c..cc955084 100644 --- a/src/routes/_layout.dashboard.tsx +++ b/src/routes/_layout.dashboard.tsx @@ -1,14 +1,13 @@ import { createFileRoute, useNavigate } from '@tanstack/react-router' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' -import { authClient } from '@/lib/auth-client' -import { useEffect, useMemo } from 'react' +import { useEffect, useMemo, useState } from 'react' import { AlertCircle, FileX, Plus, Search } from 'lucide-react' +import { authClient } from '@/lib/auth-client' import { FormCard } from '@/components/form-card' import { Button } from '@/components/ui/button' import { Card } from '@/components/ui/card' import { formsApi } from '@/api/forms' import { Input } from '@/components/ui/input' -import { useState } from 'react' import { useToast } from '@/hooks/use-toast' export const Route = createFileRoute('/_layout/dashboard')({ diff --git a/src/routes/_layout.editor.$formId.tsx b/src/routes/_layout.editor.$formId.tsx index 8cb3c43e..721ea7be 100644 --- a/src/routes/_layout.editor.$formId.tsx +++ b/src/routes/_layout.editor.$formId.tsx @@ -24,8 +24,8 @@ import { AlertCircle, Loader2 } from 'lucide-react' import type { CanvasField } from '@/components/fields/field-preview' import type { CreateFieldInput, - UpdateFormInput, UpdateFieldInput, + UpdateFormInput, } from '@/api/forms' import { ResizableHandle, @@ -229,7 +229,7 @@ function EditFormComponent() { // This ensures we send the correct data structure to the backend const fieldTypeMap: Record< string, - { fieldType: string; fieldValueType: string } + { fieldType: string; fieldValueType: string } | undefined > = { text: { fieldType: 'text', fieldValueType: 'string' }, number: { fieldType: 'number', fieldValueType: 'number' }, diff --git a/src/routes/_layout.editor.index.tsx b/src/routes/_layout.editor.index.tsx index e1db40d2..6f0915cc 100644 --- a/src/routes/_layout.editor.index.tsx +++ b/src/routes/_layout.editor.index.tsx @@ -1,7 +1,7 @@ import { useState } from 'react' import { createFileRoute, useNavigate } from '@tanstack/react-router' import { useMutation } from '@tanstack/react-query' -import { FileText, ArrowRight } from 'lucide-react' +import { ArrowRight, FileText } from 'lucide-react' import type { CreateFormInput } from '@/api/forms' import { Button } from '@/components/ui/button' diff --git a/src/routes/_layout.my-responses.tsx b/src/routes/_layout.my-responses.tsx index ff2ffc41..c39db642 100644 --- a/src/routes/_layout.my-responses.tsx +++ b/src/routes/_layout.my-responses.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, Link } from '@tanstack/react-router' +import { Link, createFileRoute } from '@tanstack/react-router' import { useQuery } from '@tanstack/react-query' import { AlertCircle, Calendar, CheckCircle, ClipboardList, ExternalLink, FileEdit, Loader2 } from 'lucide-react' import { formatDistanceToNow } from 'date-fns' diff --git a/src/routes/_layout.tsx b/src/routes/_layout.tsx index c6df39a1..ef30027b 100644 --- a/src/routes/_layout.tsx +++ b/src/routes/_layout.tsx @@ -5,6 +5,7 @@ import { useMatches, useNavigate, } from '@tanstack/react-router' +import { useEffect } from 'react' import { SidebarInset, SidebarProvider, @@ -13,7 +14,6 @@ import { import { AppSidebar } from '@/components/app-sidebar' import { Separator } from '@/components/ui/separator' import { authClient } from '@/lib/auth-client' -import { useEffect } from 'react' import { Breadcrumb, BreadcrumbItem, diff --git a/src/routes/email-verified.tsx b/src/routes/email-verified.tsx index 858cac45..19b6bc0e 100644 --- a/src/routes/email-verified.tsx +++ b/src/routes/email-verified.tsx @@ -1,7 +1,7 @@ -import { createFileRoute, Link } from '@tanstack/react-router' -import { Button } from '@/components/ui/button' -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card' +import { Link, createFileRoute } from '@tanstack/react-router' import { CheckCircle2 } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' export const Route = createFileRoute('/email-verified')({ component: EmailVerified, diff --git a/src/routes/form.$formId.tsx b/src/routes/form.$formId.tsx index 72e03101..49210a1f 100644 --- a/src/routes/form.$formId.tsx +++ b/src/routes/form.$formId.tsx @@ -10,9 +10,9 @@ * - Success confirmation after submission */ -import { createFileRoute, Link } from '@tanstack/react-router' +import { Link, createFileRoute } from '@tanstack/react-router' import { useMutation, useQuery } from '@tanstack/react-query' -import { useState, useEffect } from 'react' +import { useEffect, useState } from 'react' import { AlertCircle, ArrowRight, @@ -24,6 +24,7 @@ import { Star, } from 'lucide-react' import type { FormField } from '@/api/forms' +import type { ValidationError } from '@/lib/validation-engine'; import { Input } from '@/components/ui/input' import { Checkbox } from '@/components/ui/checkbox' import { Switch } from '@/components/ui/switch' @@ -35,9 +36,9 @@ import { fieldsApi, formsApi } from '@/api/forms' import { responsesApi } from '@/api/responses' import { useToast } from '@/hooks/use-toast' import { - validateForm, + validateField, - type ValidationError, + validateForm } from '@/lib/validation-engine' export const Route = createFileRoute('/form/$formId')({ @@ -52,7 +53,7 @@ function FormResponsePage() { const [responses, setResponses] = useState>({}) const [submitted, setSubmitted] = useState(false) const [draftResponseId, setDraftResponseId] = useState(null) - const [validationErrors, setValidationErrors] = useState( + const [validationErrors, setValidationErrors] = useState>( [], ) const [touchedFields, setTouchedFields] = useState>(new Set()) @@ -339,7 +340,7 @@ function FormResponsePage() {
- {!formWithFields.fields || formWithFields.fields.length === 0 ? ( + {formWithFields.fields.length === 0 ? (
This form has no fields yet.
@@ -373,7 +374,7 @@ function FormResponsePage() { }) )} - {formWithFields.fields && formWithFields.fields.length > 0 && ( + {formWithFields.fields.length > 0 && (