11"use client" ;
22
3- import { useState } from "react" ;
3+ import { useState , useEffect , useTransition } from "react" ;
44import { Badge } from "@/components/ui/badge" ;
5+ import { Button } from "@/components/ui/button" ;
6+ import { Input } from "@/components/ui/input" ;
7+ import { Label } from "@/components/ui/label" ;
58import { Card , CardContent } from "@/components/ui/card" ;
9+ import {
10+ Dialog ,
11+ DialogContent ,
12+ DialogDescription ,
13+ DialogFooter ,
14+ DialogHeader ,
15+ DialogTitle ,
16+ DialogTrigger ,
17+ } from "@/components/ui/dialog" ;
618import {
719 Table ,
820 TableBody ,
@@ -11,62 +23,158 @@ import {
1123 TableHeader ,
1224 TableRow ,
1325} from "@/components/ui/table" ;
26+ import { Plus } from "lucide-react" ;
27+ import { addDBPlate } from "@/app/actions" ;
1428
1529export function FlaggedPlatesTable ( { initialData } ) {
16- const [ data ] = useState ( initialData ) ;
30+ const [ data , setData ] = useState ( initialData ) ;
31+ const [ open , setOpen ] = useState ( false ) ;
32+ const [ plateNumber , setPlateNumber ] = useState ( "" ) ;
33+ const [ isPending , startTransition ] = useTransition ( ) ;
34+
35+ // Update data when initialData prop changes (after revalidation)
36+ useEffect ( ( ) => {
37+ setData ( initialData ) ;
38+ } , [ initialData ] ) ;
39+
40+ const handleSubmit = async ( e ) => {
41+ e . preventDefault ( ) ;
42+
43+ const trimmedPlate = plateNumber . trim ( ) ;
44+ if ( ! trimmedPlate ) return ;
45+
46+ if ( trimmedPlate . length > 10 ) {
47+ alert ( "Plate number cannot exceed 10 characters" ) ;
48+ return ;
49+ }
50+
51+ startTransition ( async ( ) => {
52+ try {
53+ const result = await addDBPlate ( trimmedPlate . toUpperCase ( ) , true ) ;
54+ if ( result . success ) {
55+ setData ( ( prev ) => [
56+ {
57+ plate_number : trimmedPlate . toUpperCase ( ) ,
58+ tags : [ ] ,
59+ } ,
60+ ...prev ,
61+ ] ) ;
62+ setPlateNumber ( "" ) ;
63+ setOpen ( false ) ;
64+ }
65+ } catch ( error ) {
66+ console . error ( "Error adding flagged plate:" , error ) ;
67+ }
68+ } ) ;
69+ } ;
1770
1871 return (
19- < Card className = "mt-4 sm:mt-0 dark:bg-[#0e0e10]" >
20- < CardContent className = "py-4 " >
21- < Table >
22- < TableHeader >
23- < TableRow >
24- < TableHead > Plate Number</ TableHead >
25- < TableHead > Tags</ TableHead >
26- </ TableRow >
27- </ TableHeader >
28- < TableBody >
29- { data . length === 0 ? (
72+ < >
73+ < Card className = "mt-4 sm:mt-0 dark:bg-[#0e0e10]" >
74+ < CardContent className = "py-4 " >
75+ < Table >
76+ < TableHeader >
3077 < TableRow >
31- < TableCell colSpan = { 2 } className = "text-center py-4" >
32- No flagged plates found
33- </ TableCell >
78+ < TableHead > Plate Number</ TableHead >
79+ < TableHead > Tags</ TableHead >
3480 </ TableRow >
35- ) : (
36- data . map ( ( plate ) => (
37- < TableRow key = { plate . plate_number } >
38- < TableCell className = "font-medium font-mono text-[#F31260]" >
39- { plate . plate_number }
40- </ TableCell >
41- < TableCell >
42- < div className = "flex flex-wrap items-center gap-1.5" >
43- { plate . tags ?. length > 0 ? (
44- plate . tags . map ( ( tag ) => (
45- < Badge
46- key = { tag . name }
47- variant = "secondary"
48- className = "text-xs py-0.5 px-2"
49- style = { {
50- backgroundColor : tag . color ,
51- color : "#fff" ,
52- } }
53- >
54- { tag . name }
55- </ Badge >
56- ) )
57- ) : (
58- < div className = "text-sm text-gray-500 dark:text-gray-400 italic" >
59- No tags
60- </ div >
61- ) }
62- </ div >
81+ </ TableHeader >
82+ < TableBody >
83+ { data . length === 0 ? (
84+ < TableRow >
85+ < TableCell colSpan = { 2 } className = "text-center py-4" >
86+ No flagged plates found
6387 </ TableCell >
6488 </ TableRow >
65- ) )
66- ) }
67- </ TableBody >
68- </ Table >
69- </ CardContent >
70- </ Card >
89+ ) : (
90+ data . map ( ( plate ) => (
91+ < TableRow key = { plate . plate_number } >
92+ < TableCell className = "font-medium font-mono text-[#F31260]" >
93+ { plate . plate_number }
94+ </ TableCell >
95+ < TableCell >
96+ < div className = "flex flex-wrap items-center gap-1.5" >
97+ { plate . tags ?. length > 0 ? (
98+ plate . tags . map ( ( tag ) => (
99+ < Badge
100+ key = { tag . name }
101+ variant = "secondary"
102+ className = "text-xs py-0.5 px-2"
103+ style = { {
104+ backgroundColor : tag . color ,
105+ color : "#fff" ,
106+ } }
107+ >
108+ { tag . name }
109+ </ Badge >
110+ ) )
111+ ) : (
112+ < div className = "text-sm text-gray-500 dark:text-gray-400 italic" >
113+ No tags
114+ </ div >
115+ ) }
116+ </ div >
117+ </ TableCell >
118+ </ TableRow >
119+ ) )
120+ ) }
121+ </ TableBody >
122+ </ Table >
123+ </ CardContent >
124+ </ Card >
125+
126+ < div className = "flex justify-end items-center mt-4" >
127+ < Dialog open = { open } onOpenChange = { setOpen } >
128+ < DialogTrigger asChild >
129+ < Button >
130+ < Plus className = "h-4 w-4 mr-2" />
131+ Add Flagged Plate
132+ </ Button >
133+ </ DialogTrigger >
134+ < DialogContent className = "sm:max-w-[425px]" >
135+ < DialogHeader >
136+ < DialogTitle > Add Flagged Plate</ DialogTitle >
137+ < DialogDescription >
138+ Add a new plate number to the flagged list for monitoring.
139+ </ DialogDescription >
140+ </ DialogHeader >
141+ < form onSubmit = { handleSubmit } >
142+ < div className = "grid gap-4 py-4" >
143+ < div className = "grid w-full items-center gap-2" >
144+ < Label htmlFor = "plate-number" > Plate Number</ Label >
145+ < Input
146+ id = "plate-number"
147+ value = { plateNumber }
148+ onChange = { ( e ) => setPlateNumber ( e . target . value ) }
149+ onBlur = { ( e ) => setPlateNumber ( e . target . value . toUpperCase ( ) ) }
150+ className = "font-mono text-base p-2 h-10 w-full uppercase"
151+ placeholder = "Enter Plate Number"
152+ maxLength = { 10 }
153+ disabled = { isPending }
154+ autoFocus
155+ />
156+ </ div >
157+ </ div >
158+ < DialogFooter >
159+ < Button
160+ type = "button"
161+ variant = "outline"
162+ onClick = { ( ) => setOpen ( false ) }
163+ disabled = { isPending }
164+ >
165+ Cancel
166+ </ Button >
167+ < Button
168+ type = "submit"
169+ disabled = { isPending || ! plateNumber . trim ( ) }
170+ >
171+ { isPending ? "Adding..." : "Add Plate" }
172+ </ Button >
173+ </ DialogFooter >
174+ </ form >
175+ </ DialogContent >
176+ </ Dialog >
177+ </ div >
178+ </ >
71179 ) ;
72180}
0 commit comments