@@ -4,13 +4,15 @@ import { useState, useEffect } from "react";
44import { useSession } from "next-auth/react" ;
55import sanitizeHtml from 'sanitize-html' ;
66import { Sheet , SheetContent , SheetHeader , SheetTitle } from "@/components/ui/sheet" ;
7+ import { Drawer , DrawerContent , DrawerTitle , DrawerDescription } from "@/components/ui/drawer" ;
78import { Button } from "@/components/ui/button" ;
89import { Badge } from "@/components/ui/badge" ;
910import { Separator } from "@/components/ui/separator" ;
1011import { Heart , MessageSquare , ChevronDown , Clock , TrendingUp , ChevronUp } from "lucide-react" ;
1112import { formatDistanceToNow } from "date-fns" ;
1213import { el } from "date-fns/locale" ;
1314import { cn } from "@/lib/utils" ;
15+ import { useIsMobile } from "@/hooks/use-mobile" ;
1416import { ConsultationCommentWithUpvotes } from "@/lib/db/consultations" ;
1517import { RegulationData } from "./types" ;
1618
@@ -33,6 +35,7 @@ export default function CommentsOverviewSheet({
3335 totalCount,
3436 regulationData
3537} : CommentsOverviewSheetProps ) {
38+ const isMobile = useIsMobile ( ) ;
3639 const { data : session } = useSession ( ) ;
3740 const [ sortBy , setSortBy ] = useState < SortOption > ( 'recent' ) ;
3841 const [ upvoting , setUpvoting ] = useState < string | null > ( null ) ;
@@ -208,6 +211,175 @@ export default function CommentsOverviewSheet({
208211 return false ;
209212 } ;
210213
214+ const renderContent = ( ) => (
215+ < >
216+ { /* Header */ }
217+ < div className = { cn ( "pr-6 flex-shrink-0" , isMobile && "px-4" ) } >
218+ < div className = "flex items-center justify-between" >
219+ < div >
220+ < div className = "text-xs text-muted-foreground font-medium mb-1" >
221+ ΣΧΟΛΙΑ
222+ </ div >
223+ < div className = "text-left text-lg font-semibold" >
224+ { totalCount } σχόλια συνολικά
225+ </ div >
226+ </ div >
227+ </ div >
228+ </ div >
229+
230+ { /* Sort Controls */ }
231+ < div className = { cn ( "flex gap-2 mb-4 flex-shrink-0" , isMobile && "px-4" ) } >
232+ < Button
233+ variant = { sortBy === 'recent' ? 'default' : 'outline' }
234+ size = "sm"
235+ onClick = { ( ) => setSortBy ( 'recent' ) }
236+ className = "flex items-center gap-1"
237+ >
238+ < Clock className = "h-3 w-3" />
239+ Πρόσφατα
240+ </ Button >
241+ < Button
242+ variant = { sortBy === 'liked' ? 'default' : 'outline' }
243+ size = "sm"
244+ onClick = { ( ) => setSortBy ( 'liked' ) }
245+ className = "flex items-center gap-1"
246+ >
247+ < TrendingUp className = "h-3 w-3" />
248+ Δημοφιλή
249+ </ Button >
250+ </ div >
251+
252+ { /* Comments List */ }
253+ < div className = { cn ( "flex-1 overflow-y-auto overscroll-contain space-y-6" , isMobile && "px-4" ) } >
254+ { sortedComments . length === 0 ? (
255+ < div className = "text-center py-8 text-muted-foreground" >
256+ < MessageSquare className = "h-8 w-8 mx-auto mb-2 opacity-50" />
257+ < p > Δεν υπάρχουν σχόλια ακόμα</ p >
258+ </ div >
259+ ) : (
260+ sortedComments . map ( ( comment , index ) => (
261+ < div key = { comment . id } className = "space-y-3" >
262+ { /* Reference Box */ }
263+ < div
264+ onClick = { ( e ) => handleReferenceClick ( e , comment ) }
265+ className = "bg-muted/30 border border-muted/50 rounded-md p-2 cursor-pointer hover:bg-muted/50 transition-colors"
266+ >
267+ < div className = "flex items-center gap-2" >
268+ < Badge variant = "outline" className = "text-xs" >
269+ { getEntityTypeLabel ( comment . entityType ) }
270+ </ Badge >
271+ < span className = "text-xs text-muted-foreground font-medium" >
272+ { getEntityTitle ( comment ) }
273+ </ span >
274+ </ div >
275+ </ div >
276+
277+ { /* Comment */ }
278+ < div className = "flex items-start gap-3 p-3 bg-background border border-border rounded-lg" >
279+ { /* Upvote Section */ }
280+ < div className = "flex flex-col items-center gap-1 flex-shrink-0" >
281+ < Button
282+ variant = "ghost"
283+ size = "sm"
284+ className = { cn (
285+ "h-6 w-6 p-0" ,
286+ comment . hasUserUpvoted ? "text-[hsl(var(--orange))]" : "text-muted-foreground"
287+ ) }
288+ onClick = { ( e ) => handleUpvote ( e , comment . id ) }
289+ disabled = { ! session || upvoting === comment . id }
290+ >
291+ { upvoting === comment . id ? (
292+ < div className = "animate-spin rounded-full h-3 w-3 border-b border-current" > </ div >
293+ ) : (
294+ < ChevronUp className = "h-4 w-4" />
295+ ) }
296+ </ Button >
297+ < span className = { cn (
298+ "text-xs font-medium" ,
299+ comment . hasUserUpvoted ? "text-[hsl(var(--orange))]" : "text-muted-foreground"
300+ ) } >
301+ { comment . upvoteCount || 0 }
302+ </ span >
303+ </ div >
304+
305+ { /* Comment Content */ }
306+ < div className = "flex-1 min-w-0 space-y-2" >
307+ < div
308+ className = "cursor-pointer hover:bg-muted/20 transition-colors rounded p-2 -m-2"
309+ onClick = { ( ) => handleCommentClick ( comment ) }
310+ >
311+ < div className = "flex items-center gap-2 mb-2" >
312+ < span className = "font-medium text-sm" >
313+ { comment . user ?. name || 'Ανώνυμος' }
314+ </ span >
315+ < span className = "text-xs text-muted-foreground" >
316+ { formatDistanceToNow ( new Date ( comment . createdAt ) , {
317+ addSuffix : true ,
318+ locale : el
319+ } ) }
320+ </ span >
321+ </ div >
322+ < div
323+ className = { cn (
324+ "prose prose-sm max-w-none text-sm" ,
325+ ! expandedComments . has ( comment . id ) && isCommentTruncated ( comment . body ) && "line-clamp-4"
326+ ) }
327+ dangerouslySetInnerHTML = { { __html : getSafeHtmlContent ( comment . body ) } }
328+ />
329+ </ div >
330+
331+ { /* Show More/Less Button */ }
332+ { isCommentTruncated ( comment . body ) && (
333+ < Button
334+ variant = "ghost"
335+ size = "sm"
336+ onClick = { ( e ) => {
337+ e . stopPropagation ( ) ;
338+ toggleCommentExpansion ( comment . id ) ;
339+ } }
340+ className = "h-auto p-0 text-xs text-muted-foreground hover:text-foreground transition-colors"
341+ >
342+ < div className = "flex items-center gap-1" >
343+ { expandedComments . has ( comment . id ) ? (
344+ < >
345+ < ChevronUp className = "h-3 w-3" />
346+ < span > Εμφάνιση λιγότερων</ span >
347+ </ >
348+ ) : (
349+ < >
350+ < ChevronDown className = "h-3 w-3" />
351+ < span > Εμφάνιση περισσότερων</ span >
352+ </ >
353+ ) }
354+ </ div >
355+ </ Button >
356+ ) }
357+ </ div >
358+ </ div >
359+
360+ { /* Separator between comments */ }
361+ { index < sortedComments . length - 1 && (
362+ < Separator className = "my-2" />
363+ ) }
364+ </ div >
365+ ) )
366+ ) }
367+ </ div >
368+ </ >
369+ ) ;
370+
371+ if ( isMobile ) {
372+ return (
373+ < Drawer open = { isOpen } onOpenChange = { ( open ) => ! open && onClose ( ) } >
374+ < DrawerContent className = "max-h-[85vh] flex flex-col" >
375+ < DrawerTitle className = "sr-only" > { totalCount } σχόλια συνολικά</ DrawerTitle >
376+ < DrawerDescription className = "sr-only" > Επισκόπηση σχολίων</ DrawerDescription >
377+ { renderContent ( ) }
378+ </ DrawerContent >
379+ </ Drawer >
380+ ) ;
381+ }
382+
211383 return (
212384 < Sheet open = { isOpen } onOpenChange = { ( open ) => ! open && onClose ( ) } >
213385 < SheetContent
0 commit comments