import React from 'react' import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd' import { Plus, Trash2, GripVertical, ImageIcon, Link as LinkIcon, Award, ArrowRight, Edit, TextIcon, Briefcase, GraduationCap, Upload, MapPin, BookOpen } from 'lucide-react' import { Input } from "@components/ui/input" import { Textarea } from "@components/ui/textarea" import { Label } from "@components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@components/ui/select" import { Button } from "@components/ui/button" import { useLHSession } from '@components/Contexts/LHSessionContext' import { updateProfile } from '@services/settings/profile' import { getUser } from '@services/users/users' import { toast } from 'react-hot-toast' import { Tabs, TabsList, TabsTrigger, TabsContent } from "@components/ui/tabs" // Define section types and their configurations const SECTION_TYPES = { 'image-gallery': { icon: ImageIcon, label: 'Image Gallery', description: 'Add a collection of images' }, 'text': { icon: TextIcon, label: 'Text', description: 'Add formatted text content' }, 'links': { icon: LinkIcon, label: 'Links', description: 'Add social or professional links' }, 'skills': { icon: Award, label: 'Skills', description: 'Showcase your skills and expertise' }, 'experience': { icon: Briefcase, label: 'Experience', description: 'Add work or project experience' }, 'education': { icon: GraduationCap, label: 'Education', description: 'Add educational background' }, 'affiliation': { icon: MapPin, label: 'Affiliation', description: 'Add organizational affiliations' }, 'courses': { icon: BookOpen, label: 'Courses', description: 'Display authored courses' } } as const // Type definitions interface ProfileImage { url: string; caption?: string; } interface ProfileLink { title: string; url: string; icon?: string; } interface ProfileSkill { name: string; level?: 'beginner' | 'intermediate' | 'advanced' | 'expert'; category?: string; } interface ProfileExperience { title: string; organization: string; startDate: string; endDate?: string; current: boolean; description: string; } interface ProfileEducation { institution: string; degree: string; field: string; startDate: string; endDate?: string; current: boolean; description?: string; } interface ProfileAffiliation { name: string; description: string; logoUrl: string; } interface Course { id: string; title: string; description: string; thumbnail?: string; status: string; } interface BaseSection { id: string; type: keyof typeof SECTION_TYPES; title: string; } interface ImageGallerySection extends BaseSection { type: 'image-gallery'; images: ProfileImage[]; } interface TextSection extends BaseSection { type: 'text'; content: string; } interface LinksSection extends BaseSection { type: 'links'; links: ProfileLink[]; } interface SkillsSection extends BaseSection { type: 'skills'; skills: ProfileSkill[]; } interface ExperienceSection extends BaseSection { type: 'experience'; experiences: ProfileExperience[]; } interface EducationSection extends BaseSection { type: 'education'; education: ProfileEducation[]; } interface AffiliationSection extends BaseSection { type: 'affiliation'; affiliations: ProfileAffiliation[]; } interface CoursesSection extends BaseSection { type: 'courses'; // No need to store courses as they will be fetched from API } type ProfileSection = | ImageGallerySection | TextSection | LinksSection | SkillsSection | ExperienceSection | EducationSection | AffiliationSection | CoursesSection; interface ProfileData { sections: ProfileSection[]; } const UserProfileBuilder = () => { const session = useLHSession() as any const access_token = session?.data?.tokens?.access_token const [profileData, setProfileData] = React.useState({ sections: [] }) const [selectedSection, setSelectedSection] = React.useState(null) const [isSaving, setIsSaving] = React.useState(false) const [isLoading, setIsLoading] = React.useState(true) // Initialize profile data from user data React.useEffect(() => { const fetchUserData = async () => { if (session?.data?.user?.id && access_token) { try { setIsLoading(true) const userData = await getUser(session.data.user.id) if (userData.profile) { try { const profileSections = typeof userData.profile === 'string' ? JSON.parse(userData.profile).sections : userData.profile.sections; setProfileData({ sections: profileSections || [] }); } catch (error) { console.error('Error parsing profile data:', error); setProfileData({ sections: [] }); } } } catch (error) { console.error('Error fetching user data:', error); toast.error('Failed to load profile data'); } finally { setIsLoading(false) } } }; fetchUserData(); }, [session?.data?.user?.id, access_token]) const createEmptySection = (type: keyof typeof SECTION_TYPES): ProfileSection => { const baseSection = { id: `section-${Date.now()}`, type, title: `${SECTION_TYPES[type].label} Section` } switch (type) { case 'image-gallery': return { ...baseSection, type: 'image-gallery', images: [] } case 'text': return { ...baseSection, type: 'text', content: '' } case 'links': return { ...baseSection, type: 'links', links: [] } case 'skills': return { ...baseSection, type: 'skills', skills: [] } case 'experience': return { ...baseSection, type: 'experience', experiences: [] } case 'education': return { ...baseSection, type: 'education', education: [] } case 'affiliation': return { ...baseSection, type: 'affiliation', affiliations: [] } case 'courses': return { ...baseSection, type: 'courses' } } } const addSection = (type: keyof typeof SECTION_TYPES) => { const newSection = createEmptySection(type) setProfileData(prev => ({ ...prev, sections: [...prev.sections, newSection] })) setSelectedSection(profileData.sections.length) } const updateSection = (index: number, updatedSection: ProfileSection) => { const newSections = [...profileData.sections] newSections[index] = updatedSection setProfileData(prev => ({ ...prev, sections: newSections })) } const deleteSection = (index: number) => { setProfileData(prev => ({ ...prev, sections: prev.sections.filter((_, i) => i !== index) })) setSelectedSection(null) } const onDragEnd = (result: any) => { if (!result.destination) return const items = Array.from(profileData.sections) const [reorderedItem] = items.splice(result.source.index, 1) items.splice(result.destination.index, 0, reorderedItem) setProfileData(prev => ({ ...prev, sections: items })) setSelectedSection(result.destination.index) } const handleSave = async () => { setIsSaving(true) const loadingToast = toast.loading('Saving profile...') try { // Get fresh user data before update const userData = await getUser(session.data.user.id) // Update only the profile field userData.profile = profileData const res = await updateProfile(userData, userData.id, access_token) if (res.status === 200) { toast.success('Profile updated successfully', { id: loadingToast }) } else { throw new Error('Failed to update profile') } } catch (error) { console.error('Error updating profile:', error) toast.error('Error updating profile', { id: loadingToast }) } finally { setIsSaving(false) } } if (isLoading) { return (
) } return (
{/* Header */}

Profile Builder
BETA

Customize your professional profile

{/* Main Content */}
{/* Sections Panel */}

Sections

{(provided) => (
{profileData.sections.map((section, index) => ( {(provided, snapshot) => (
setSelectedSection(index)} className={`p-4 bg-white/80 backdrop-blur-xs rounded-lg cursor-pointer border ${ selectedSection === index ? 'border-blue-500 bg-blue-50 ring-2 ring-blue-500/20 shadow-xs' : 'border-gray-200 hover:border-gray-300 hover:bg-gray-50/50 hover:shadow-xs' } ${snapshot.isDragging ? 'shadow-lg ring-2 ring-blue-500/20 rotate-2' : ''}`} >
{React.createElement(SECTION_TYPES[section.type].icon, { size: 16 })}
{section.title}
)}
))} {provided.placeholder}
)}
{/* Editor Panel */}
{selectedSection !== null ? ( updateSection(selectedSection, updatedSection as ProfileSection)} /> ) : (
Select a section to edit or add a new one
)}
) } interface SectionEditorProps { section: ProfileSection; onChange: (section: ProfileSection) => void; } const SectionEditor: React.FC = ({ section, onChange }) => { switch (section.type) { case 'image-gallery': return case 'text': return case 'links': return case 'skills': return case 'experience': return case 'education': return case 'affiliation': return case 'courses': return default: return
Unknown section type
} } const ImageGalleryEditor: React.FC<{ section: ImageGallerySection; onChange: (section: ImageGallerySection) => void; }> = ({ section, onChange }) => { return (

Image Gallery

{/* Title */}
onChange({ ...section, title: e.target.value })} placeholder="Enter section title" />
{/* Images */}
{section.images.map((image, index) => (
{ const newImages = [...section.images] newImages[index] = { ...image, url: e.target.value } onChange({ ...section, images: newImages }) }} placeholder="Enter image URL" />
{ const newImages = [...section.images] newImages[index] = { ...image, caption: e.target.value } onChange({ ...section, images: newImages }) }} placeholder="Image caption" />
{image.url && (
{image.caption
)}
))}
) } const TextEditor: React.FC<{ section: TextSection; onChange: (section: TextSection) => void; }> = ({ section, onChange }) => { return (

Text Content

{/* Title */}
onChange({ ...section, title: e.target.value })} placeholder="Enter section title" />
{/* Content */}