You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
3.7 KiB
121 lines
3.7 KiB
import ReportCard from '@/components/ReportCard' |
|
import { RefreshButton } from '@/components/RefreshButton' |
|
import { |
|
Dialog, |
|
DialogContent, |
|
DialogDescription, |
|
DialogHeader, |
|
DialogTitle |
|
} from '@/components/ui/dialog' |
|
import { Skeleton } from '@/components/ui/skeleton' |
|
import { useProfileReportsEvents } from '@/hooks/useProfileReportsEvents' |
|
import { useProfileReportsRelayBuilder } from '@/hooks/useProfileReportsRelayBuilder' |
|
import { RefreshCw } from 'lucide-react' |
|
import { useEffect, useState } from 'react' |
|
import { useTranslation } from 'react-i18next' |
|
|
|
export function ProfileReportsPanel({ pubkey }: { pubkey: string }) { |
|
const { t } = useTranslation() |
|
const relayUrlsBuilder = useProfileReportsRelayBuilder(pubkey) |
|
const { received, made, isLoading, refresh } = useProfileReportsEvents({ |
|
pubkey, |
|
relayUrlsBuilder |
|
}) |
|
const [isRefreshing, setIsRefreshing] = useState(false) |
|
|
|
useEffect(() => { |
|
if (!isLoading) setIsRefreshing(false) |
|
}, [isLoading]) |
|
|
|
const handleRefresh = () => { |
|
setIsRefreshing(true) |
|
refresh() |
|
} |
|
|
|
if (isLoading && received.length === 0 && made.length === 0) { |
|
return ( |
|
<div className="space-y-4 py-2"> |
|
{Array.from({ length: 3 }).map((_, i) => ( |
|
<Skeleton key={i} className="h-32 w-full" /> |
|
))} |
|
</div> |
|
) |
|
} |
|
|
|
return ( |
|
<div className="space-y-8"> |
|
<div className="flex justify-end"> |
|
<RefreshButton onClick={handleRefresh} onLongPress={null} /> |
|
</div> |
|
{isRefreshing && ( |
|
<div |
|
className="flex items-center justify-center gap-2 py-2 text-center text-sm text-green-500" |
|
role="status" |
|
aria-live="polite" |
|
> |
|
<RefreshCw className="h-4 w-4 shrink-0 animate-spin" aria-hidden /> |
|
{t('Refreshing reports...')} |
|
</div> |
|
)} |
|
|
|
<section className="space-y-2" aria-labelledby="profile-reports-received-heading"> |
|
<h2 |
|
id="profile-reports-received-heading" |
|
className="text-sm font-semibold text-foreground" |
|
> |
|
{t('Reports received')} |
|
</h2> |
|
{received.length === 0 ? ( |
|
<p className="py-2 text-sm text-muted-foreground">{t('No reports received')}</p> |
|
) : ( |
|
<div className="space-y-2"> |
|
{received.map((event) => ( |
|
<ReportCard key={event.id} className="w-full" event={event} /> |
|
))} |
|
</div> |
|
)} |
|
</section> |
|
|
|
<section className="space-y-2" aria-labelledby="profile-reports-made-heading"> |
|
<h2 id="profile-reports-made-heading" className="text-sm font-semibold text-foreground"> |
|
{t('Reports made')} |
|
</h2> |
|
{made.length === 0 ? ( |
|
<p className="py-2 text-sm text-muted-foreground">{t('No reports made')}</p> |
|
) : ( |
|
<div className="space-y-2"> |
|
{made.map((event) => ( |
|
<ReportCard key={event.id} className="w-full" event={event} /> |
|
))} |
|
</div> |
|
)} |
|
</section> |
|
</div> |
|
) |
|
} |
|
|
|
export default function ProfileReportsDialog({ |
|
open, |
|
onOpenChange, |
|
pubkey |
|
}: { |
|
open: boolean |
|
onOpenChange: (open: boolean) => void |
|
pubkey: string |
|
}) { |
|
const { t } = useTranslation() |
|
|
|
return ( |
|
<Dialog open={open} onOpenChange={onOpenChange}> |
|
<DialogContent className="flex max-h-[min(90vh,720px)] max-w-lg flex-col overflow-hidden sm:max-w-xl"> |
|
<DialogHeader> |
|
<DialogTitle>{t('Reports')}</DialogTitle> |
|
<DialogDescription>{t('Profile reports dialog description')}</DialogDescription> |
|
</DialogHeader> |
|
<div className="min-h-0 flex-1 overflow-y-auto pr-1"> |
|
{open ? <ProfileReportsPanel key={pubkey} pubkey={pubkey} /> : null} |
|
</div> |
|
</DialogContent> |
|
</Dialog> |
|
) |
|
}
|
|
|