SkateSpots/src/components/UserStatusIndicator.tsx
shakespeare.diy e29d35f1e4 fix: restore full skate-spots source tree from misplaced src/src/ copy
The entire skate-spots codebase was accidentally copied into src/src/ and
public/public/ instead of src/ and public/ directly. This left the real
src/ directory as blank MKStack template stubs, explaining why the landing
page showed the default template instead of SkateSpots.

Changes made:
- Copied all files from src/src/ up to src/ (App.tsx, AppRouter.tsx, main.tsx,
  all pages, components, hooks, contexts, lib, i18n, test)
- Copied all files from public/public/ up to public/ (images, manifest, etc.)
- Deleted src/src/ and public/public/ nested directories
- Removed HelloWorld.tsx template stub from pages/
- Retained the previously fixed index.css (Tailwind v3 directives)

Full skate-spots feature set is now active:
- All 30+ routes (map, events, spots, coaches, marketplace, wallet, etc.)
- NWCProvider, LanguageProvider, PWAInstallPrompt, AmberCallbackHandler
- Skate community relays (goskatespots.nostr1.com, wotr.relatr.xyz, etc.)
- Outfit Variable font, Amber pre-check in main.tsx
- All hooks (useSkateSpots, useCoaches, useZaps, etc.)
- i18n support (en/es)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-15 22:18:28 +07:00

94 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useUserStatus, SKATING_STATUSES } from '@/hooks/useUserStatus';
import { Badge } from '@/components/ui/badge';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
interface UserStatusIndicatorProps {
pubkey: string;
className?: string;
showLabel?: boolean;
size?: 'sm' | 'md' | 'lg';
}
export function UserStatusIndicator({
pubkey,
className,
showLabel = false,
size = 'sm',
}: UserStatusIndicatorProps) {
const { data: status, isLoading } = useUserStatus(pubkey);
if (isLoading || !status) return null;
const preset = status.statusId
? SKATING_STATUSES.find(s => s.id === status.statusId)
: null;
const emoji = status.emoji || preset?.emoji || '🛹';
const label = preset?.label || status.status;
const sizeClasses = {
sm: 'text-xs px-1.5 py-0',
md: 'text-sm px-2 py-0.5',
lg: 'text-base px-3 py-1',
};
const dotSizeClasses = {
sm: 'w-2 h-2',
md: 'w-2.5 h-2.5',
lg: 'w-3 h-3',
};
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div className={cn('inline-flex items-center gap-1', className)}>
{/* Pulsing dot indicator */}
<span className="relative flex">
<span
className={cn(
'animate-ping absolute inline-flex rounded-full bg-green-400 opacity-75',
dotSizeClasses[size]
)}
/>
<span
className={cn(
'relative inline-flex rounded-full bg-green-500',
dotSizeClasses[size]
)}
/>
</span>
{showLabel && (
<Badge
variant="outline"
className={cn(
'border-green-500/50 text-green-400 font-medium',
sizeClasses[size]
)}
>
{emoji} {label}
</Badge>
)}
</div>
</TooltipTrigger>
<TooltipContent side="top" className="max-w-[200px]">
<div className="text-center">
<div className="text-lg mb-1">{emoji}</div>
<p className="font-bold">{label}</p>
{status.linkedSpot && (
<p className="text-xs text-muted-foreground mt-1">
📍 At a spot
</p>
)}
{status.expiration && (
<p className="text-xs text-muted-foreground mt-1">
⏱️ Auto-clears in {Math.round((status.expiration - Date.now() / 1000) / 60)} min
</p>
)}
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}