Replace native selects with shadcn Select across all pages
Build & Auto-Repair / build (push) Has been cancelled

- lead-scoring-settings.tsx: Feature type dropdown
- bug-report-modal.tsx: Severity dropdown
- client-portal/support/page.tsx: Severity dropdown
- time-tracking/page.tsx: Timer project + manual entry project dropdowns
- proposals/new/page.tsx: Lead + customer dropdowns
This commit is contained in:
2026-07-01 15:39:00 +02:00
parent 2979078edd
commit a02f013f38
5 changed files with 103 additions and 50 deletions
+20 -12
View File
@@ -137,21 +137,29 @@ export default function NewProposalPage() {
</div>
<div>
<label className="text-sm font-medium">Lead (optional)</label>
<select value={leadId} onChange={(e) => setLeadId(e.target.value)} className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm">
<option value="">Select lead...</option>
{leads.map((l: any) => (
<option key={l.id} value={l.id}>{l.contact_name || l.company_name}</option>
))}
</select>
<Select value={leadId} onValueChange={setLeadId}>
<SelectTrigger className="h-9 w-full">
<SelectValue placeholder="Select lead..." />
</SelectTrigger>
<SelectContent>
{leads.map((l: any) => (
<SelectItem key={l.id} value={l.id}>{l.contact_name || l.company_name}</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<label className="text-sm font-medium">Customer (optional)</label>
<select value={customerId} onChange={(e) => setCustomerId(e.target.value)} className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm">
<option value="">Select customer...</option>
{customers.map((c: any) => (
<option key={c.id} value={c.id}>{c.company_name || `${c.first_name} ${c.last_name}`}</option>
))}
</select>
<Select value={customerId} onValueChange={setCustomerId}>
<SelectTrigger className="h-9 w-full">
<SelectValue placeholder="Select customer..." />
</SelectTrigger>
<SelectContent>
{customers.map((c: any) => (
<SelectItem key={c.id} value={c.id}>{c.company_name || `${c.first_name} ${c.last_name}`}</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<label className="text-sm font-medium">VAT %</label>
+30 -13
View File
@@ -6,6 +6,13 @@ import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Card } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { Play, Square, Plus, Trash2, Clock, Briefcase, User, TrendingUp, DollarSign } from "lucide-react"
import { toast } from "sonner"
@@ -29,7 +36,7 @@ export default function TimeTrackingPage() {
const [showManual, setShowManual] = useState(false)
// Manual entry form
const [manualProject, setManualProject] = useState("")
const [manualProject, setManualProject] = useState("none")
const [manualDesc, setManualDesc] = useState("")
const [manualDate, setManualDate] = useState(new Date().toISOString().split("T")[0])
const [manualHours, setManualHours] = useState("")
@@ -41,7 +48,7 @@ export default function TimeTrackingPage() {
// Timer
const [timerRunning, setTimerRunning] = useState(false)
const [timerSeconds, setTimerSeconds] = useState(0)
const [timerProject, setTimerProject] = useState("")
const [timerProject, setTimerProject] = useState("none")
const [timerDesc, setTimerDesc] = useState("")
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null)
const startTimeRef = useRef<Date | null>(null)
@@ -92,7 +99,7 @@ export default function TimeTrackingPage() {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
projectId: timerProject || null,
projectId: timerProject === "none" ? null : timerProject,
description: timerDesc,
date: new Date().toISOString().split("T")[0],
startTime: startTimeRef.current?.toISOString(),
@@ -103,7 +110,7 @@ export default function TimeTrackingPage() {
}),
})
setTimerDesc("")
setTimerProject("")
setTimerProject("none")
setTimerSeconds(0)
fetchData()
} catch (e) {
@@ -124,7 +131,7 @@ export default function TimeTrackingPage() {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
projectId: manualProject || null,
projectId: manualProject === "none" ? null : manualProject,
description: manualDesc,
date: manualDate,
durationMinutes: totalMins,
@@ -212,10 +219,15 @@ export default function TimeTrackingPage() {
<div className="flex items-end gap-3">
<div className="flex-1 space-y-2">
<Input placeholder="What are you working on?" value={timerDesc} onChange={(e) => setTimerDesc(e.target.value)} className="h-9" disabled={timerRunning} />
<select value={timerProject} onChange={(e) => setTimerProject(e.target.value)} className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm" disabled={timerRunning}>
<option value="">No project</option>
{projects.map((p: any) => <option key={p.id} value={p.id}>{p.name}</option>)}
</select>
<Select value={timerProject} onValueChange={setTimerProject} disabled={timerRunning}>
<SelectTrigger className="h-9 w-full">
<SelectValue placeholder="No project" />
</SelectTrigger>
<SelectContent>
<SelectItem value="none">No project</SelectItem>
{projects.map((p: any) => <SelectItem key={p.id} value={p.id}>{p.name}</SelectItem>)}
</SelectContent>
</Select>
</div>
<div className="text-3xl font-mono font-bold tabular-nums px-4 py-1">{formatTimer(timerSeconds)}</div>
{!timerRunning ? (
@@ -238,10 +250,15 @@ export default function TimeTrackingPage() {
<div className="space-y-3 p-3 rounded-lg border bg-muted/20">
<div className="grid gap-3 md:grid-cols-2">
<Input placeholder="Description *" value={manualDesc} onChange={(e) => setManualDesc(e.target.value)} className="h-8 text-sm" />
<select value={manualProject} onChange={(e) => setManualProject(e.target.value)} className="flex h-8 w-full rounded-md border border-input bg-transparent px-3 text-sm shadow-sm">
<option value="">No project</option>
{projects.map((p: any) => <option key={p.id} value={p.id}>{p.name}</option>)}
</select>
<Select value={manualProject} onValueChange={setManualProject}>
<SelectTrigger className="h-8 w-full">
<SelectValue placeholder="No project" />
</SelectTrigger>
<SelectContent>
<SelectItem value="none">No project</SelectItem>
{projects.map((p: any) => <SelectItem key={p.id} value={p.id}>{p.name}</SelectItem>)}
</SelectContent>
</Select>
</div>
<div className="flex gap-3 flex-wrap">
<Input type="date" value={manualDate} onChange={(e) => setManualDate(e.target.value)} className="h-8 w-40 text-sm" />
+18 -10
View File
@@ -1,6 +1,13 @@
"use client"
import { useEffect, useState } from "react"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { LifeBuoy, Send } from "lucide-react"
interface Ticket {
@@ -107,16 +114,17 @@ export default function ClientSupport() {
<div>
<label className="block text-sm text-[#8a8a95] mb-1">Severity</label>
<select
value={severity}
onChange={(e) => setSeverity(e.target.value)}
className="w-full bg-[#1a1a24] border border-[#2a2a35] rounded-lg px-3 py-2 text-sm text-white outline-none focus:border-[#1BB0CE]/50"
>
<option value="low">Low</option>
<option value="medium">Medium</option>
<option value="high">High</option>
<option value="critical">Critical</option>
</select>
<Select value={severity} onValueChange={setSeverity}>
<SelectTrigger className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="low">Low</SelectItem>
<SelectItem value="medium">Medium</SelectItem>
<SelectItem value="high">High</SelectItem>
<SelectItem value="critical">Critical</SelectItem>
</SelectContent>
</Select>
</div>
{submitError && (
@@ -5,6 +5,13 @@ import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { Plus, Trash2, RefreshCw, Gauge } from "lucide-react"
import { toast } from "sonner"
@@ -142,11 +149,16 @@ export function LeadScoringSettings() {
</div>
<div>
<label className="text-xs font-medium">Type</label>
<select value={newFeature.featureType} onChange={e => setNewFeature(p => ({ ...p, featureType: e.target.value }))} className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm">
<option value="keyword">Keyword Match</option>
<option value="boolean">Boolean (has value)</option>
<option value="range">Range</option>
</select>
<Select value={newFeature.featureType} onValueChange={v => setNewFeature(p => ({ ...p, featureType: v }))}>
<SelectTrigger className="h-9 w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="keyword">Keyword Match</SelectItem>
<SelectItem value="boolean">Boolean (has value)</SelectItem>
<SelectItem value="range">Range</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<label className="text-xs font-medium">Weight</label>
+18 -10
View File
@@ -2,6 +2,13 @@
import { useState } from "react"
import { motion, AnimatePresence } from "framer-motion"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { X, Bug, Loader2, CheckCircle } from "lucide-react"
interface BugReportModalProps {
@@ -151,16 +158,17 @@ export function BugReportModal({ open, onClose }: BugReportModalProps) {
<label className="mb-1.5 block text-sm font-medium text-[#8A9078] dark:text-[#CCCCCC]">
Severity
</label>
<select
value={severity}
onChange={(e) => setSeverity(e.target.value)}
className="w-full rounded-lg border border-[#D4D8CC] dark:border-[#333333] bg-white dark:bg-[#1E1E1E] px-3 py-2 text-sm text-[#2D3020] dark:text-white focus:border-[#C84B4B] focus:outline-none focus:ring-1 focus:ring-[#C84B4B]"
>
<option value="low">Low Minor cosmetic issue</option>
<option value="medium">Medium Affects functionality</option>
<option value="high">High Major feature broken</option>
<option value="critical">Critical System is blocked</option>
</select>
<Select value={severity} onValueChange={setSeverity}>
<SelectTrigger className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="low">Low Minor cosmetic issue</SelectItem>
<SelectItem value="medium">Medium Affects functionality</SelectItem>
<SelectItem value="high">High Major feature broken</SelectItem>
<SelectItem value="critical">Critical System is blocked</SelectItem>
</SelectContent>
</Select>
</div>
<div className="rounded-lg bg-[#FAFAF6] dark:bg-[#1A1A1A] px-3 py-2">