diff --git a/client/components/ProfileEditor.tsx b/client/components/ProfileEditor.tsx new file mode 100644 index 00000000..60048f43 --- /dev/null +++ b/client/components/ProfileEditor.tsx @@ -0,0 +1,591 @@ +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { + Globe, + Briefcase, + Award, + Clock, + MapPin, + DollarSign, + Zap, + Plus, + Trash2, + Copy, + CheckCircle2, +} from "lucide-react"; +import { type AethexUserProfile } from "@/lib/aethex-database-adapter"; + +interface SkillItem { + name: string; + level: "beginner" | "intermediate" | "expert"; +} + +interface WorkExperienceItem { + company: string; + title: string; + duration: string; + description?: string; +} + +interface PortfolioItem { + title: string; + url: string; + description?: string; +} + +interface ProfileEditorProps { + profile: AethexUserProfile; + onSave: (updates: Partial) => Promise; + isSaving?: boolean; + username?: string; +} + +const ARMS = [ + { id: "foundation", label: "Foundation", color: "bg-red-500" }, + { id: "gameforge", label: "GameForge", color: "bg-green-500" }, + { id: "labs", label: "Labs", color: "bg-yellow-500" }, + { id: "corp", label: "Corp", color: "bg-blue-500" }, + { id: "devlink", label: "Dev-Link", color: "bg-cyan-500" }, +]; + +export function ProfileEditor({ + profile, + onSave, + isSaving = false, + username, +}: ProfileEditorProps) { + const [formData, setFormData] = useState({ + bio_detailed: profile.bio_detailed || "", + twitter_url: profile.twitter_url || "", + linkedin_url: profile.linkedin_url || "", + github_url: profile.github_url || "", + portfolio_url: profile.portfolio_url || "", + youtube_url: profile.youtube_url || "", + twitch_url: profile.twitch_url || "", + hourly_rate: profile.hourly_rate?.toString() || "", + availability_status: profile.availability_status || "available", + timezone: profile.timezone || "", + location: profile.location || "", + languages: (profile.languages as string[]) || [], + skills_detailed: (profile.skills_detailed as SkillItem[]) || [], + work_experience: (profile.work_experience as WorkExperienceItem[]) || [], + portfolio_items: (profile.portfolio_items as PortfolioItem[]) || [], + arm_affiliations: (profile.arm_affiliations as string[]) || [], + }); + + const [newSkill, setNewSkill] = useState({ name: "", level: "intermediate" as const }); + const [newLanguage, setNewLanguage] = useState(""); + const [newWorkExp, setNewWorkExp] = useState({ company: "", title: "", duration: "" }); + const [newPortfolio, setNewPortfolio] = useState({ title: "", url: "" }); + const [copied, setCopied] = useState(false); + + const profileUrl = username ? `https://${username}.aethex.me` : ""; + + const handleSubmit = async () => { + await onSave({ + ...formData, + hourly_rate: formData.hourly_rate ? parseFloat(formData.hourly_rate) : undefined, + skills_detailed: formData.skills_detailed, + languages: formData.languages, + work_experience: formData.work_experience, + portfolio_items: formData.portfolio_items, + arm_affiliations: formData.arm_affiliations, + }); + }; + + const addSkill = () => { + if (newSkill.name.trim()) { + setFormData({ + ...formData, + skills_detailed: [...formData.skills_detailed, newSkill], + }); + setNewSkill({ name: "", level: "intermediate" }); + } + }; + + const removeSkill = (index: number) => { + setFormData({ + ...formData, + skills_detailed: formData.skills_detailed.filter((_, i) => i !== index), + }); + }; + + const addLanguage = () => { + if (newLanguage.trim()) { + setFormData({ + ...formData, + languages: [...formData.languages, newLanguage], + }); + setNewLanguage(""); + } + }; + + const removeLanguage = (index: number) => { + setFormData({ + ...formData, + languages: formData.languages.filter((_, i) => i !== index), + }); + }; + + const addWorkExp = () => { + if (newWorkExp.company.trim() && newWorkExp.title.trim()) { + setFormData({ + ...formData, + work_experience: [...formData.work_experience, newWorkExp], + }); + setNewWorkExp({ company: "", title: "", duration: "" }); + } + }; + + const removeWorkExp = (index: number) => { + setFormData({ + ...formData, + work_experience: formData.work_experience.filter((_, i) => i !== index), + }); + }; + + const addPortfolio = () => { + if (newPortfolio.title.trim() && newPortfolio.url.trim()) { + setFormData({ + ...formData, + portfolio_items: [...formData.portfolio_items, newPortfolio], + }); + setNewPortfolio({ title: "", url: "" }); + } + }; + + const removePortfolio = (index: number) => { + setFormData({ + ...formData, + portfolio_items: formData.portfolio_items.filter((_, i) => i !== index), + }); + }; + + const toggleArmAffiliation = (armId: string) => { + setFormData({ + ...formData, + arm_affiliations: formData.arm_affiliations.includes(armId) + ? formData.arm_affiliations.filter((a) => a !== armId) + : [...formData.arm_affiliations, armId], + }); + }; + + const copyProfileUrl = () => { + navigator.clipboard.writeText(profileUrl); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( + + + Basic + Social + Skills + Experience + Arms + + + {/* BASIC INFO TAB */} + + + + Profile Link + Your public profile URL + + +
+ + +
+
+
+ + + + About You + + +
+ +