diff --git a/apps/web/src/features/profile/components/ProfileSocialLinksSection.stories.tsx b/apps/web/src/features/profile/components/ProfileSocialLinksSection.stories.tsx new file mode 100644 index 000000000..3736508f5 --- /dev/null +++ b/apps/web/src/features/profile/components/ProfileSocialLinksSection.stories.tsx @@ -0,0 +1,37 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { ProfileSocialLinksSection } from './ProfileSocialLinksSection'; + +const meta: Meta = { + component: ProfileSocialLinksSection, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, +}; +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + socialLinks: { + twitter: 'https://twitter.com/veza_user', + youtube: 'https://youtube.com/@veza_channel', + instagram: 'https://instagram.com/veza_profile', + }, + }, +}; + +export const Empty: Story = { + args: { + socialLinks: null, + }, +}; + +export const SingleLink: Story = { + args: { + socialLinks: { + website: 'https://veza.example.com', + }, + }, +}; diff --git a/apps/web/src/features/profile/components/ProfileSocialLinksSection.tsx b/apps/web/src/features/profile/components/ProfileSocialLinksSection.tsx new file mode 100644 index 000000000..dd55a51ac --- /dev/null +++ b/apps/web/src/features/profile/components/ProfileSocialLinksSection.tsx @@ -0,0 +1,65 @@ +/** + * B2: Section Liens sociaux sur le profil public. + * Affiche Twitter, YouTube, Instagram, etc. avec icĂ´nes et URLs cliquables. + */ +import { + Twitter, + Instagram, + Facebook, + Youtube, + Link as LinkIcon, +} from 'lucide-react'; + +const SOCIAL_KEYS = [ + { key: 'twitter', label: 'Twitter', Icon: Twitter }, + { key: 'instagram', label: 'Instagram', Icon: Instagram }, + { key: 'facebook', label: 'Facebook', Icon: Facebook }, + { key: 'youtube', label: 'YouTube', Icon: Youtube }, + { key: 'website', label: 'Website', Icon: LinkIcon }, +] as const; + +interface ProfileSocialLinksSectionProps { + socialLinks?: Record | null; +} + +function isValidUrl(value: unknown): value is string { + if (typeof value !== 'string') return false; + if (!value.trim()) return false; + return value.startsWith('http://') || value.startsWith('https://'); +} + +export function ProfileSocialLinksSection({ socialLinks }: ProfileSocialLinksSectionProps) { + const entries = SOCIAL_KEYS.filter( + ({ key }) => socialLinks?.[key] != null && isValidUrl(socialLinks[key]), + ).map(({ key, label, Icon }) => ({ + key, + label, + Icon, + href: String(socialLinks![key]), + })); + + if (entries.length === 0) return null; + + return ( +
+

+ Links +

+
+ {entries.map(({ key, label, Icon, href }) => ( + + + {label} + + ))} +
+
+ ); +} diff --git a/apps/web/src/features/profile/pages/user-profile-page/UserProfilePageHeader.tsx b/apps/web/src/features/profile/pages/user-profile-page/UserProfilePageHeader.tsx index 9ade4495e..d9eaef946 100644 --- a/apps/web/src/features/profile/pages/user-profile-page/UserProfilePageHeader.tsx +++ b/apps/web/src/features/profile/pages/user-profile-page/UserProfilePageHeader.tsx @@ -1,4 +1,5 @@ import { MapPin, Calendar, User, Music, Library, Users } from 'lucide-react'; +import { ProfileSocialLinksSection } from '../../components/ProfileSocialLinksSection'; import { Avatar } from '@/components/ui/avatar'; import { Card, CardContent } from '@/components/ui/card'; import { FollowButton } from '../../components/FollowButton'; @@ -108,6 +109,7 @@ export function UserProfilePageHeader({ )}

+ {/* Stats pills */} diff --git a/apps/web/src/mocks/handlers-misc.ts b/apps/web/src/mocks/handlers-misc.ts index 578563405..9488a5c58 100644 --- a/apps/web/src/mocks/handlers-misc.ts +++ b/apps/web/src/mocks/handlers-misc.ts @@ -224,6 +224,7 @@ export const handlersMisc = [ first_name: 'Story', last_name: 'User', avatar_url: `https://i.pravatar.cc/150?u=${params.username}`, + banner_url: params.username === 'demo' ? 'https://picsum.photos/1200/400?random=1' : null, bio: 'Music enthusiast', location: 'Paris, France', birthdate: null, @@ -231,6 +232,14 @@ export const handlersMisc = [ created_at: '2024-01-01T00:00:00Z', followers_count: 42, following_count: 10, + social_links: + params.username === 'demo' + ? { + twitter: 'https://twitter.com/veza_demo', + youtube: 'https://youtube.com/@veza_channel', + instagram: 'https://instagram.com/veza_profile', + } + : undefined, }, }); }),