188 lines
5.1 KiB
TypeScript
188 lines
5.1 KiB
TypeScript
import { useState } from 'react';
|
|
import { ShareButton } from './ShareButton';
|
|
import { CopyLinkButton } from './CopyLinkButton';
|
|
import { type SharePlatform, type ShareData, getShareUrl } from '@/lib/social-utils';
|
|
import { trackShare } from '@/lib/analytics';
|
|
|
|
export type SocialShareVariant = 'default' | 'compact' | 'footer' | 'floating';
|
|
|
|
interface SocialShareButtonsProps extends ShareData {
|
|
articleId: string;
|
|
variant?: SocialShareVariant;
|
|
className?: string;
|
|
onShare?: (platform: SharePlatform) => void;
|
|
}
|
|
|
|
const PLATFORMS: SharePlatform[] = ['facebook', 'twitter', 'whatsapp', 'telegram', 'email', 'link'];
|
|
|
|
export function SocialShareButtons({
|
|
articleId,
|
|
title,
|
|
url,
|
|
excerpt,
|
|
image,
|
|
tags,
|
|
variant = 'default',
|
|
className = '',
|
|
onShare,
|
|
}: SocialShareButtonsProps) {
|
|
const [isTracking, setIsTracking] = useState(false);
|
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
|
|
const shareData: ShareData = {
|
|
title,
|
|
url,
|
|
excerpt,
|
|
image,
|
|
tags,
|
|
};
|
|
|
|
const handleShare = async (platform: SharePlatform) => {
|
|
try {
|
|
// Track the share event
|
|
setIsTracking(true);
|
|
await trackShare({
|
|
articleId,
|
|
platform,
|
|
userAgent: navigator.userAgent,
|
|
// Note: We don't send IP address from frontend for privacy reasons
|
|
// Backend should extract it from the request if needed
|
|
});
|
|
|
|
// Call the onShare callback if provided
|
|
if (onShare) {
|
|
onShare(platform);
|
|
}
|
|
|
|
// Open share URL in new window for social platforms
|
|
if (platform !== 'link') {
|
|
const shareUrl = getShareUrl(platform, shareData);
|
|
window.open(shareUrl, '_blank', 'noopener,noreferrer');
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to track share:', error);
|
|
// Still open the share URL even if tracking fails
|
|
if (platform !== 'link') {
|
|
const shareUrl = getShareUrl(platform, shareData);
|
|
window.open(shareUrl, '_blank', 'noopener,noreferrer');
|
|
}
|
|
} finally {
|
|
setIsTracking(false);
|
|
}
|
|
};
|
|
|
|
const handleCopyLink = async (success: boolean) => {
|
|
if (success) {
|
|
await handleShare('link');
|
|
}
|
|
};
|
|
|
|
// Determine layout based on variant
|
|
const getLayoutClasses = () => {
|
|
switch (variant) {
|
|
case 'compact':
|
|
return 'flex items-center space-x-1';
|
|
case 'footer':
|
|
return 'flex flex-col sm:flex-row items-center justify-center space-y-2 sm:space-y-0 sm:space-x-4';
|
|
case 'floating':
|
|
return 'fixed right-4 bottom-4 flex flex-col space-y-2 z-50';
|
|
default:
|
|
return 'flex flex-wrap items-center gap-2';
|
|
}
|
|
};
|
|
|
|
const getButtonSize = () => {
|
|
switch (variant) {
|
|
case 'compact':
|
|
return 'sm' as const;
|
|
case 'footer':
|
|
return 'default' as const;
|
|
case 'floating':
|
|
return 'default' as const;
|
|
default:
|
|
return 'default' as const;
|
|
}
|
|
};
|
|
|
|
const getButtonVariant = () => {
|
|
switch (variant) {
|
|
case 'compact':
|
|
return 'ghost' as const;
|
|
case 'footer':
|
|
return 'outline' as const;
|
|
case 'floating':
|
|
return 'default' as const;
|
|
default:
|
|
return 'outline' as const;
|
|
}
|
|
};
|
|
|
|
const showLabels = variant === 'footer';
|
|
|
|
// For compact variant, only show a single share button that expands on hover
|
|
if (variant === 'compact') {
|
|
return (
|
|
<div
|
|
className={`relative ${className}`}
|
|
onMouseEnter={() => setIsExpanded(true)}
|
|
onMouseLeave={() => setIsExpanded(false)}
|
|
>
|
|
<div className="flex items-center space-x-1">
|
|
<ShareButton
|
|
platform="link"
|
|
onClick={() => handleShare('link')}
|
|
size={getButtonSize()}
|
|
variant={getButtonVariant()}
|
|
disabled={isTracking}
|
|
/>
|
|
|
|
{isExpanded && (
|
|
<div className="flex items-center space-x-1 animate-in slide-in-from-right-2">
|
|
{PLATFORMS.filter(p => p !== 'link').map((platform) => (
|
|
<ShareButton
|
|
key={platform}
|
|
platform={platform}
|
|
onClick={() => handleShare(platform)}
|
|
size={getButtonSize()}
|
|
variant={getButtonVariant()}
|
|
disabled={isTracking}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className={`${getLayoutClasses()} ${className}`}>
|
|
{PLATFORMS.map((platform) => {
|
|
if (platform === 'link') {
|
|
return (
|
|
<CopyLinkButton
|
|
key={platform}
|
|
url={url}
|
|
size={getButtonSize()}
|
|
variant={getButtonVariant()}
|
|
showLabel={showLabels}
|
|
onCopy={handleCopyLink}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<ShareButton
|
|
key={platform}
|
|
platform={platform}
|
|
onClick={() => handleShare(platform)}
|
|
size={getButtonSize()}
|
|
variant={getButtonVariant()}
|
|
disabled={isTracking}
|
|
showLabel={showLabels}
|
|
/>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
} |