@@ -132,8 +132,6 @@ export function LicensesContent() {
132132 } ;
133133
134134 const handleSearch = ( ) => {
135- // Search is handled through the hook with the debounced search query
136- // This function is here for explicit search button click
137135 fetchLicenses ( ) ;
138136 } ;
139137
@@ -245,137 +243,135 @@ export function LicensesContent() {
245243 </ div >
246244
247245 { /* Licenses Table */ }
248- < div className = "border rounded-md" >
246+ < div className = "border border-border/30 rounded-md" >
249247 { isLoading ? (
250248 < div className = "p-8 text-center" >
251249 < p className = "text-muted-foreground" > { translate ( "loading_licenses" , "licenses" , { default : "Loading licenses..." } ) } </ p >
252250 </ div >
253251 ) : (
254- < div className = "rounded-md border" >
255- < Table >
256- < TableHeader >
257- < TableRow >
258- < TableHead className = "w-[200px]" > { translate ( "software_name" , "licenses" , { default : "Software" } ) } </ TableHead >
259- < TableHead > { translate ( "license_key" , "licenses" , { default : "License Key" } ) } </ TableHead >
260- < TableHead > { translate ( "expiry_date" , "licenses" , { default : "Expiry Date" } ) } </ TableHead >
261- < TableHead > { translate ( "tags" , "licenses" , { default : "Tags" } ) } </ TableHead >
262- < TableHead className = "text-right" > { translate ( "actions" , "licenses" , { default : "Actions" } ) } </ TableHead >
263- </ TableRow >
264- </ TableHeader >
265- { licensesToDisplay . length > 0 ? (
266- < TableBody >
267- { licensesToDisplay . map ( ( license ) => {
268- return (
269- < TableRow key = { license . doc_id } >
270- < TableCell className = "font-medium" >
271- < div className = "flex items-center gap-2" >
272- < Key className = "h-4 w-4 text-muted-foreground" />
273- < span > { license . title || 'N/A' } </ span >
274- </ div >
275- </ TableCell >
276- < TableCell className = "font-mono" >
252+ < Table >
253+ < TableHeader >
254+ < TableRow >
255+ < TableHead className = "w-[200px]" > { translate ( "software_name" , "licenses" , { default : "Software" } ) } </ TableHead >
256+ < TableHead > { translate ( "license_key" , "licenses" , { default : "License Key" } ) } </ TableHead >
257+ < TableHead > { translate ( "expiry_date" , "licenses" , { default : "Expiry Date" } ) } </ TableHead >
258+ < TableHead > { translate ( "tags" , "licenses" , { default : "Tags" } ) } </ TableHead >
259+ < TableHead className = "text-right" > { translate ( "actions" , "licenses" , { default : "Actions" } ) } </ TableHead >
260+ </ TableRow >
261+ </ TableHeader >
262+ { licensesToDisplay . length > 0 ? (
263+ < TableBody >
264+ { licensesToDisplay . map ( ( license ) => {
265+ return (
266+ < TableRow key = { license . doc_id } >
267+ < TableCell className = "font-medium" >
268+ < div className = "flex items-center gap-2" >
269+ < Key className = "h-4 w-4 text-muted-foreground" />
270+ < span > { license . title || 'N/A' } </ span >
271+ </ div >
272+ </ TableCell >
273+ < TableCell className = "font-mono" >
274+ < div className = "flex items-center gap-2" >
275+ < span >
276+ { viewLicenseKey === license . doc_id ? license . license_key : "••••-••••-••••-••••" }
277+ </ span >
278+ { license . license_key && (
279+ < >
280+ < Button
281+ variant = "ghost"
282+ size = "icon"
283+ className = "h-6 w-6"
284+ onClick = { ( ) => toggleLicenseKeyVisibility ( license . doc_id ) }
285+ >
286+ { viewLicenseKey === license . doc_id ? < EyeOff className = "h-3 w-3" /> : < Eye className = "h-3 w-3" /> }
287+ </ Button >
288+ < Button
289+ variant = "ghost"
290+ size = "icon"
291+ className = "h-6 w-6"
292+ onClick = { ( ) => copyToClipboard ( license . doc_id , "license_key" , license . license_key ) }
293+ >
294+ { copiedField ?. id === license . doc_id && copiedField ?. field === "license_key" ? (
295+ < Check className = "h-3 w-3" />
296+ ) : (
297+ < Copy className = "h-3 w-3" />
298+ ) }
299+ </ Button >
300+ </ >
301+ ) }
302+ </ div >
303+ </ TableCell >
304+ < TableCell >
305+ { license . expires_at && (
277306 < div className = "flex items-center gap-2" >
278- < span >
279- { viewLicenseKey === license . doc_id ? license . license_key : "••••-••••-••••-••••" }
307+ < span className = { ` ${ isExpired ( license . expires_at ) ? 'text-red-500' : ( daysUntilExpiry ( license . expires_at ) < 30 ? 'text-amber-500' : 'text-green-500' ) } ` } >
308+ { formatDate ( license . expires_at ) }
280309 </ span >
281- { license . license_key && (
282- < >
283- < Button
284- variant = "ghost"
285- size = "icon"
286- className = "h-6 w-6"
287- onClick = { ( ) => toggleLicenseKeyVisibility ( license . doc_id ) }
288- >
289- { viewLicenseKey === license . doc_id ? < EyeOff className = "h-3 w-3" /> : < Eye className = "h-3 w-3" /> }
290- </ Button >
291- < Button
292- variant = "ghost"
293- size = "icon"
294- className = "h-6 w-6"
295- onClick = { ( ) => copyToClipboard ( license . doc_id , "license_key" , license . license_key ) }
296- >
297- { copiedField ?. id === license . doc_id && copiedField ?. field === "license_key" ? (
298- < Check className = "h-3 w-3" />
299- ) : (
300- < Copy className = "h-3 w-3" />
301- ) }
302- </ Button >
303- </ >
304- ) }
305- </ div >
306- </ TableCell >
307- < TableCell >
308- { license . expires_at && (
309- < div className = "flex items-center gap-2" >
310- < span className = { `${ isExpired ( license . expires_at ) ? 'text-red-500' : ( daysUntilExpiry ( license . expires_at ) < 30 ? 'text-amber-500' : 'text-green-500' ) } ` } >
311- { formatDate ( license . expires_at ) }
312- </ span >
313- { isExpired ( license . expires_at ) ? (
314- < Badge variant = "destructive" className = "text-xs" >
315- { translate ( "expired" , "licenses" , { default : "Expired" } ) }
316- </ Badge >
317- ) : daysUntilExpiry ( license . expires_at ) < 30 ? (
318- < Badge variant = "outline" className = "text-xs text-amber-500 border-amber-500" >
319- { translate ( "expiring_soon" , "licenses" , { default : "Expiring soon" } ) }
320- </ Badge >
321- ) : null }
322- </ div >
323- ) }
324- { ! license . expires_at && '-' }
325- </ TableCell >
326- < TableCell >
327- < div className = "flex flex-wrap gap-1" >
328- { license . tags ?. map ( ( tag ) => (
329- < Badge key = { tag } variant = "secondary" className = "text-xs" >
330- { tag }
310+ { isExpired ( license . expires_at ) ? (
311+ < Badge variant = "destructive" className = "text-xs" >
312+ { translate ( "expired" , "licenses" , { default : "Expired" } ) }
313+ </ Badge >
314+ ) : daysUntilExpiry ( license . expires_at ) < 30 ? (
315+ < Badge variant = "outline" className = "text-xs text-amber-500 border-amber-500" >
316+ { translate ( "expiring_soon" , "licenses" , { default : "Expiring soon" } ) }
331317 </ Badge >
332- ) ) }
318+ ) : null }
333319 </ div >
334- </ TableCell >
335- < TableCell className = "text-right" >
336- < DropdownMenu >
337- < DropdownMenuTrigger asChild >
338- < Button variant = "ghost" size = "icon" >
339- < MoreHorizontal className = "h-4 w-4" />
340- </ Button >
341- </ DropdownMenuTrigger >
342- < DropdownMenuContent align = "end" >
343- < DropdownMenuItem onClick = { ( ) => handleEditLicense ( license ) } >
344- { translate ( "edit" , "licenses" , { default : "Edit" } ) }
345- </ DropdownMenuItem >
346- < DropdownMenuItem onClick = { ( ) => confirmDelete ( license . doc_id ) } className = "text-red-500" >
347- { translate ( "delete" , "licenses" , { default : "Delete" } ) }
348- </ DropdownMenuItem >
349- </ DropdownMenuContent >
350- </ DropdownMenu >
351- </ TableCell >
352- </ TableRow >
353- ) ;
354- } ) }
355- </ TableBody >
356- ) : (
357- < TableBody >
358- < TableRow >
359- < TableCell colSpan = { 5 } className = "h-24 text-center" >
360- < p className = "text-muted-foreground" >
361- { searchQuery || selectedTag !== 'all'
362- ? translate ( "no_matching_licenses" , "licenses" , { default : "No matching licenses found" } )
363- : translate ( "no_licenses_found" , "licenses" , { default : "No licenses found" } ) }
364- </ p >
365- < Button
366- variant = "outline"
367- onClick = { handleAddLicense }
368- className = "mt-4"
369- >
370- < Plus className = "mr-2 h-4 w-4" />
371- { translate ( "add_license" , "licenses" , { default : "Add License" } ) }
372- </ Button >
373- </ TableCell >
374- </ TableRow >
375- </ TableBody >
376- ) }
377- </ Table >
378- </ div >
320+ ) }
321+ { ! license . expires_at && '-' }
322+ </ TableCell >
323+ < TableCell >
324+ < div className = "flex flex-wrap gap-1" >
325+ { license . tags ?. map ( ( tag ) => (
326+ < Badge key = { tag } variant = "secondary" className = "text-xs" >
327+ { tag }
328+ </ Badge >
329+ ) ) }
330+ </ div >
331+ </ TableCell >
332+ < TableCell className = "text-right" >
333+ < DropdownMenu >
334+ < DropdownMenuTrigger asChild >
335+ < Button variant = "ghost" size = "icon" >
336+ < MoreHorizontal className = "h-4 w-4" />
337+ </ Button >
338+ </ DropdownMenuTrigger >
339+ < DropdownMenuContent align = "end" >
340+ < DropdownMenuItem onClick = { ( ) => handleEditLicense ( license ) } >
341+ { translate ( "edit" , "licenses" , { default : "Edit" } ) }
342+ </ DropdownMenuItem >
343+ < DropdownMenuItem onClick = { ( ) => confirmDelete ( license . doc_id ) } className = "text-red-500" >
344+ { translate ( "delete" , "licenses" , { default : "Delete" } ) }
345+ </ DropdownMenuItem >
346+ </ DropdownMenuContent >
347+ </ DropdownMenu >
348+ </ TableCell >
349+ </ TableRow >
350+ ) ;
351+ } ) }
352+ </ TableBody >
353+ ) : (
354+ < TableBody >
355+ < TableRow >
356+ < TableCell colSpan = { 5 } className = "h-24 text-center" >
357+ < p className = "text-muted-foreground" >
358+ { searchQuery || selectedTag !== 'all'
359+ ? translate ( "no_matching_licenses" , "licenses" , { default : "No matching licenses found" } )
360+ : translate ( "no_licenses_found" , "licenses" , { default : "No licenses found" } ) }
361+ </ p >
362+ < Button
363+ variant = "outline"
364+ onClick = { handleAddLicense }
365+ className = "mt-4"
366+ >
367+ < Plus className = "mr-2 h-4 w-4" />
368+ { translate ( "add_license" , "licenses" , { default : "Add License" } ) }
369+ </ Button >
370+ </ TableCell >
371+ </ TableRow >
372+ </ TableBody >
373+ ) }
374+ </ Table >
379375 ) }
380376 </ div >
381377
@@ -451,7 +447,7 @@ export function LicensesContent() {
451447 license = { {
452448 doc_id : selectedLicense . doc_id ,
453449 title : selectedLicense . title ,
454- data : "" , // We need to add this required field - it will be populated with encrypted data
450+ data : "" ,
455451 license_key : selectedLicense . license_key ,
456452 notes : selectedLicense . notes || "" ,
457453 expires_at : selectedLicense . expires_at || undefined ,
@@ -486,4 +482,4 @@ export function LicensesContent() {
486482 </ Dialog >
487483 </ div >
488484 ) ;
489- }
485+ }
0 commit comments