Welcome

import React, { useState, useEffect, useRef, useMemo } from 'react';

import { initializeApp } from 'firebase/app';

import {

getAuth,

signInAnonymously,

onAuthStateChanged,

signInWithCustomToken

} from 'firebase/auth';

import {

getFirestore,

collection,

addDoc,

onSnapshot,

doc,

updateDoc,

deleteDoc,

arrayUnion,

arrayRemove,

increment,

setDoc,

getDoc

} from 'firebase/firestore';

import {

Heart,

MessageCircle,

Repeat,

Share,

ArrowLeft,

Trash2,

X,

Home as HomeIcon,

Search,

Bell,

Mail,

User,

UserPlus,

UserCheck,

Send,

Calendar,

MapPin,

Link as LinkIcon,

Camera

} from 'lucide-react';

// --- Firebase Initialization ---

const firebaseConfig = JSON.parse(__firebase_config);

const app = initializeApp(firebaseConfig);

const auth = getAuth(app);

const db = getFirestore(app);

const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';

// --- Utilities ---

const formatTime = (timestamp) => {

if (!timestamp) return '';

const date = new Date(timestamp);

const now = new Date();

const diffInSeconds = Math.floor((now - date) / 1000);

if (diffInSeconds < 60) return ${diffInSeconds}s;

if (diffInSeconds < 3600) return ${Math.floor(diffInSeconds / 60)}m;

if (diffInSeconds < 86400) return ${Math.floor(diffInSeconds / 3600)}h;

return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });

};

const getRandomColor = (uid) => {

const colors = [

'bg-sky-600', 'bg-emerald-600', 'bg-violet-600',

'bg-rose-600', 'bg-amber-600', 'bg-teal-600', 'bg-indigo-600'

];

let hash = 0;

for (let i = 0; i < uid.length; i++) hash = uid.charCodeAt(i) + ((hash << 5) - hash);

return colors[Math.abs(hash) % colors.length];

};

const getCoverColor = (uid) => {

const colors = [

'bg-slate-700', 'bg-zinc-700', 'bg-neutral-700',

'bg-stone-700', 'bg-blue-900', 'bg-indigo-900'

];

let hash = 0;

for (let i = 0; i < uid.length; i++) hash = uid.charCodeAt(i) + ((hash << 5) - hash);

return colors[Math.abs(hash) % colors.length];

};

// --- Components ---

const Avatar = ({ uid, username, size = "md", onClick, className = "" }) => {

const s = size === "xl" ? "w-24 h-24 text-4xl border-4 border-black" : size === "lg" ? "w-12 h-12 text-lg" : size === "sm" ? "w-8 h-8 text-xs" : "w-10 h-10 text-base";

return (

<div

onClick={onClick}

className=${s} rounded-full ${getRandomColor(uid)} flex-shrink-0 flex items-center justify-center font-bold text-white shadow-sm select-none hover:opacity-90 transition-opacity cursor-pointer ${className}}

>

{username ? username[0].toUpperCase() : '?'}

</div>

);

};

const ActionButton = ({ icon: Icon, count, active, type, onClick }) => {

const colors = {

reply: { base: 'text-[#71767B]', hover: 'group-hover:text-[#1D9BF0]', bg: 'group-hover:bg-[#1D9BF0]/10', active: 'text-[#1D9BF0]' },

repost: { base: 'text-[#71767B]', hover: 'group-hover:text-[#00BA7C]', bg: 'group-hover:bg-[#00BA7C]/10', active: 'text-[#00BA7C]' },

like: { base: 'text-[#71767B]', hover: 'group-hover:text-[#F91880]', bg: 'group-hover:bg-[#F91880]/10', active: 'text-[#F91880]' },

share: { base: 'text-[#71767B]', hover: 'group-hover:text-[#1D9BF0]', bg: 'group-hover:bg-[#1D9BF0]/10', active: 'text-[#1D9BF0]' },

delete: { base: 'text-[#71767B]', hover: 'group-hover:text-red-500', bg: 'group-hover:bg-red-500/10', active: 'text-red-500' },

mail: { base: 'text-[#71767B]', hover: 'group-hover:text-[#1D9BF0]', bg: 'group-hover:bg-[#1D9BF0]/10', active: 'text-[#1D9BF0]' }

};

const style = colors[type] || colors.share;

const isHeart = type === 'like';

const isRepost = type === 'repost';

return (

<button

onClick={(e) => {

e.preventDefault();

e.stopPropagation();

onClick && onClick(e);

}}

className=group flex items-center gap-1.5 transition-colors duration-200 outline-none ${active ? style.active : style.base} ${style.hover} z-10 relative}

>

<div className=relative p-2 rounded-full transition-colors duration-200 ${style.bg}}>

<Icon

size={18}

className={`

transition-transform duration-200

${active && isHeart ? 'animate-heart-pop' : ''}

${active && isRepost ? 'text-[#00BA7C]' : ''}

`}

fill={active && isHeart ? "currentColor" : "none"}

strokeWidth={active && isHeart ? 0 : 2}

/>

{active && isHeart && (

<div className="absolute inset-0 rounded-full animate-heart-ring border-2 border-[#F91880] opacity-0" />

)}

</div>

{count !== undefined && (

<span className=text-[13px] tabular-nums transition-colors duration-200 ${active ? style.active : style.hover}}>

{count > 0 ? count : ''}

</span>

)}

</button>

);

};

// Bottom Nav Item

const NavItem = ({ icon: Icon, active, onClick, badge }) => (

<button

onClick={onClick}

className="flex-1 flex justify-center items-center py-3 hover:bg-white/5 transition-colors active:scale-95 duration-100 relative"

>

<div className="relative">

<Icon

size={26}

strokeWidth={active ? 3 : 2}

className={active ? 'text-[#E7E9EA]' : 'text-[#71767B]'}

/>

{active && <div className="absolute -bottom-1 left-1/2 -translate-x-1/2 w-1 h-1 bg-[#E7E9EA] rounded-full hidden"></div>}

{badge > 0 && (

<div className="absolute -top-1 -right-1 bg-[#1D9BF0] text-white text-[10px] font-bold px-1 min-w-[16px] h-[16px] rounded-full flex items-center justify-center border border-black">

{badge}

</div>

)}

</div>

</button>

);

// --- Main App ---

export default function App() {

const [user, setUser] = useState(null);

const [username, setUsername] = useState('');

// Extra Profile Fields

const [bio, setBio] = useState('');

const [location, setLocation] = useState('');

const [website, setWebsite] = useState('');

// Navigation State

const [view, setView] = useState('feed');

const [activeTab, setActiveTab] = useState('home');

const [feedTab, setFeedTab] = useState('foryou');

// Data State

const [activeTweet, setActiveTweet] = useState(null);

const [activeChatUser, setActiveChatUser] = useState(null);

const [tweets, setTweets] = useState([]);

const [comments, setComments] = useState([]);

const [notifications, setNotifications] = useState([]);

const [messages, setMessages] = useState([]);

const [following, setFollowing] = useState(new Set());

const [loading, setLoading] = useState(true);

const [searchQuery, setSearchQuery] = useState('');

// UI States

const [tweetText, setTweetText] = useState('');

const [messageText, setMessageText] = useState('');

const [isSubmitting, setIsSubmitting] = useState(false);

const [toast, setToast] = useState(null);

// Editing Profile States

const [isEditingProfile, setIsEditingProfile] = useState(false);

const [editName, setEditName] = useState('');

const [editBio, setEditBio] = useState('');

const [editLocation, setEditLocation] = useState('');

const [editWebsite, setEditWebsite] = useState('');

const scrollContainerRef = useRef(null);

// --- Auth & Init ---

useEffect(() => {

const initAuth = async () => {

if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) {

await signInWithCustomToken(auth, __initial_auth_token);

} else {

await signInAnonymously(auth);

}

};

initAuth();

return onAuthStateChanged(auth, (u) => {

setUser(u);

if (u) {

// Load Profile Data

const storedName = localStorage.getItemuser_name_${u.uid});

const storedBio = localStorage.getItemuser_bio_${u.uid});

const storedLoc = localStorage.getItemuser_location_${u.uid});

const storedWeb = localStorage.getItemuser_website_${u.uid});

setUsername(storedName || User${u.uid.substring(0, 4)});

setBio(storedBio || '');

setLocation(storedLoc || '');

setWebsite(storedWeb || '');

}

});

}, []);

const showToast = (msg) => {

setToast(msg);

setTimeout(() => setToast(null), 3000);

};

// --- Data Fetching ---

// 1. Fetch Tweets (Global)

useEffect(() => {

if (!user) return;

const q = collection(db, 'artifacts', appId, 'public', 'data', 'tweets');

const unsub = onSnapshot(q, (snap) => {

const data = snap.docs.map(d => ({ id: d.id, ...d.data() }));

data.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));

setTweets(data);

setLoading(false);

if (activeTweet) {

const updated = data.find(t => t.id === activeTweet.id);

if (updated) setActiveTweet(updated);

}

});

return () => unsub();

}, [user, activeTweet?.id]);

// 2. Fetch Comments

useEffect(() => {

if (!activeTweet || view !== 'thread') {

setComments([]);

return;

}

const q = collection(db, 'artifacts', appId, 'public', 'data', 'comments');

const unsub = onSnapshot(q, (snap) => {

const allComments = snap.docs.map(d => ({ id: d.id, ...d.data() }));

const threadComments = allComments.filter(c => c.tweetId === activeTweet.id);

threadComments.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));

setComments(threadComments);

});

return () => unsub();

}, [activeTweet, view]);

// 3. Fetch Notifications

useEffect(() => {

if (!user) return;

const q = collection(db, 'artifacts', appId, 'users', user.uid, 'notifications');

const unsub = onSnapshot(q, (snap) => {

const data = snap.docs.map(d => ({ id: d.id, ...d.data() }));

data.sort((a, b) => b.createdAt - a.createdAt);

setNotifications(data);

});

return () => unsub();

}, [user]);

// 4. Fetch Following

useEffect(() => {

if (!user) return;

const q = collection(db, 'artifacts', appId, 'users', user.uid, 'following');

const unsub = onSnapshot(q, (snap) => {

const ids = new Set(snap.docs.map(d => d.id));

setFollowing(ids);

});

return () => unsub();

}, [user]);

// 5. Fetch Messages

useEffect(() => {

if (!user) return;

const q = collection(db, 'artifacts', appId, 'public', 'data', 'direct_messages');

const unsub = onSnapshot(q, (snap) => {

const allMsgs = snap.docs.map(d => ({ id: d.id, ...d.data() }));

const myMsgs = allMsgs.filter(m => m.from === user.uid || m.to === user.uid);

myMsgs.sort((a, b) => a.createdAt - b.createdAt);

setMessages(myMsgs);

});

return () => unsub();

}, [user]);

// --- Computed Data ---

const filteredTweets = useMemo(() => {

let result = tweets;

if (activeTab === 'profile') {

result = result.filter(t => t.uid === user?.uid);

} else if (activeTab === 'search' && searchQuery) {

const lowerQ = searchQuery.toLowerCase();

result = result.filter(t => t.text?.toLowerCase().includes(lowerQ) || t.username?.toLowerCase().includes(lowerQ));

} else if (activeTab === 'home' && feedTab === 'following') {

result = result.filter(t => following.has(t.uid));

}

return result;

}, [tweets, activeTab, feedTab, following, searchQuery, user]);

const conversations = useMemo(() => {

const map = new Map();

messages.forEach(msg => {

const otherUid = msg.from === user.uid ? msg.to : msg.from;

const otherName = msg.from === user.uid ? msg.toUsername : msg.fromUsername;

if (!map.has(otherUid)) {

map.set(otherUid, {

uid: otherUid,

username: otherName || 'User',

lastMsg: msg,

unread: 0

});

} else {

const conv = map.get(otherUid);

if (msg.createdAt > conv.lastMsg.createdAt) {

conv.lastMsg = msg;

conv.username = otherName || conv.username;

}

}

});

return Array.from(map.values()).sort((a, b) => b.lastMsg.createdAt - a.lastMsg.createdAt);

}, [messages, user]);

const currentChatMessages = useMemo(() => {

if (!activeChatUser) return [];

return messages.filter(m =>

(m.from === user.uid && m.to === activeChatUser.uid) ||

(m.from === activeChatUser.uid && m.to === user.uid)

);

}, [messages, activeChatUser, user]);

// --- Actions ---

const handlePost = async (isReply = false) => {

if (!tweetText.trim()) return;

setIsSubmitting(true);

try {

if (isReply && activeTweet) {

await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'comments'), {

text: tweetText,

uid: user.uid,

username,

createdAt: Date.now(),

tweetId: activeTweet.id,

likes: []

});

await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'tweets', activeTweet.id), {

replyCount: increment(1)

});

showToast("Reply sent");

} else {

await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'tweets'), {

text: tweetText,

uid: user.uid,

username,

createdAt: Date.now(),

likes: [],

reposts: [],

replyCount: 0

});

showToast("Posted");

}

setTweetText('');

} catch (e) {

console.error(e);

showToast("Error posting");

}

setIsSubmitting(false);

};

const handleLike = async (docId, likes, authorUid, isComment = false) => {

const isLiked = likes.includes(user.uid);

const col = isComment ? 'comments' : 'tweets';

const ref = doc(db, 'artifacts', appId, 'public', 'data', col, docId);

await updateDoc(ref, {

likes: isLiked ? arrayRemove(user.uid) : arrayUnion(user.uid)

});

};

const handleRepost = async (tweet) => {

const isReposted = tweet.reposts?.includes(user.uid);

const ref = doc(db, 'artifacts', appId, 'public', 'data', 'tweets', tweet.id);

await updateDoc(ref, {

reposts: isReposted ? arrayRemove(user.uid) : arrayUnion(user.uid)

});

showToast(isReposted ? "Repost removed" : "Reposted");

};

const handleFollow = async (targetUid) => {

if (targetUid === user.uid) return;

const isFollowing = following.has(targetUid);

const ref = doc(db, 'artifacts', appId, 'users', user.uid, 'following', targetUid);

if (isFollowing) {

await deleteDoc(ref);

showToast("Unfollowed");

} else {

await setDoc(ref, { since: Date.now() });

showToast("Following");

}

};

const handleSendMessage = async () => {

if (!messageText.trim() || !activeChatUser) return;

try {

await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'direct_messages'), {

text: messageText,

from: user.uid,

fromUsername: username,

to: activeChatUser.uid,

toUsername: activeChatUser.username,

createdAt: Date.now()

});

setMessageText('');

} catch (e) {

showToast("Failed to send");

}

};

const handleDelete = async (id, isComment = false) => {

if (!confirm("Delete this?")) return;

try {

const col = isComment ? 'comments' : 'tweets';

await deleteDoc(doc(db, 'artifacts', appId, 'public', 'data', col, id));

if (isComment && activeTweet) {

await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'tweets', activeTweet.id), {

replyCount: increment(-1)

});

}

if (!isComment && view === 'thread') setView('feed');

showToast("Deleted");

} catch (e) { showToast("Error deleting"); }

};

const openEditProfile = () => {

setEditName(username);

setEditBio(bio);

setEditLocation(location);

setEditWebsite(website);

setIsEditingProfile(true);

};

const handleUpdateProfile = (e) => {

e.preventDefault();

if (!editName.trim()) return;

// Save to Local Storage for consistency/persistence on same device

localStorage.setItemuser_name_${user.uid}, editName);

localStorage.setItemuser_bio_${user.uid}, editBio);

localStorage.setItemuser_location_${user.uid}, editLocation);

localStorage.setItemuser_website_${user.uid}, editWebsite);

// Update State

setUsername(editName);

setBio(editBio);

setLocation(editLocation);

setWebsite(editWebsite);

setIsEditingProfile(false);

showToast("Profile updated");

};

// --- Navigation Actions ---

const openThread = (tweet) => {

setActiveTweet(tweet);

setView('thread');

setTweetText('');

};

const openChat = (uid, uName) => {

setActiveChatUser({ uid, username: uName });

setView('chat');

setActiveTab('messages');

};

// --- Render Helpers ---

const TweetCard = ({ data, isComment = false, isMain = false }) => {

const isLiked = data.likes?.includes(user?.uid) ?? false;

const isReposted = !isComment && (data.reposts?.includes(user?.uid) ?? false);

const canDelete = user?.uid === data.uid;

const isFollowing = following.has(data.uid);

return (

<article

onClick={() => !isMain && !isComment && openThread(data)}

className={`

${isMain ? 'p-4' : 'px-4 py-3 border-b border-[#2F3336] hover:bg-[#080808] cursor-pointer'}

transition-colors duration-200

`}

>

<div className=flex ${isMain ? 'flex-col gap-3' : 'gap-3'}}>

{!isMain && <Avatar uid={data.uid} username={data.username} onClick={(e) => { e.stopPropagation(); openChat(data.uid, data.username); }} />}

<div className="flex-1 min-w-0">

{/* Header */}

<div className="flex justify-between items-start relative z-0">

<div className="flex items-center gap-2 mb-1 min-w-0">

{isMain && <Avatar uid={data.uid} username={data.username} size="lg" onClick={() => openChat(data.uid, data.username)} />}

<div className=flex ${isMain ? 'flex-col' : 'gap-1.5 items-center'} min-w-0}>

<span className="font-bold text-white truncate text-[15px]">{data.username}</span>

<span className="text-[#71767B] text-[15px] truncate">@{data.username?.toLowerCase().replace(/\s/g, '')}</span>

{!isMain && <span className="text-[#71767B] text-[15px]">· {formatTime(data.createdAt)}</span>}

</div>

{/* Follow Button */}

{user.uid !== data.uid && (

<button

onClick={(e) => { e.stopPropagation(); handleFollow(data.uid); }}

className=ml-2 p-1 rounded-full transition-colors ${isFollowing ? 'text-[#1D9BF0] bg-[#1D9BF0]/10' : 'text-[#71767B] hover:bg-[#1D9BF0]/10 hover:text-[#1D9BF0]'}}

>

{isFollowing ? <UserCheck size={16} /> : <UserPlus size={16} />}

</button>

)}

</div>

{canDelete && !isMain && (

<div className="-mr-2 -mt-1">

<ActionButton icon={Trash2} type="delete" onClick={() => handleDelete(data.id, isComment)} />

</div>

)}

</div>

{/* Content */}

<div className=text-white whitespace-pre-wrap leading-normal break-words ${isMain ? 'text-[17px] mt-3 mb-3' : 'text-[15px] mt-0.5'}}>

{data.text}

</div>

{/* Actions Bar */}

<div className=flex justify-between ${isMain ? 'justify-around py-2 border-b border-[#2F3336]' : 'max-w-[425px] mt-3 -ml-2'}}>

<ActionButton icon={MessageCircle} type="reply" count={data.replyCount || 0} onClick={() => !isMain && !isComment && openThread(data)} />

{!isComment && <ActionButton icon={Repeat} type="repost" count={data.reposts?.length || 0} active={isReposted} onClick={() => handleRepost(data)} />}

<ActionButton icon={Heart} type="like" count={data.likes?.length || 0} active={isLiked} onClick={() => handleLike(data.id, data.likes || [], data.uid, isComment)} />

<ActionButton icon={Mail} type="mail" onClick={() => openChat(data.uid, data.username)} />

{isMain && canDelete && <ActionButton icon={Trash2} type="delete" onClick={() => handleDelete(data.id, isComment)} />}

</div>

</div>

</div>

</article>

);

};

const NotificationItem = ({ note }) => {

let icon = <Heart size={16} fill="currentColor" className="text-[#F91880]" />;

let text = "liked your post";

if (note.type === 'repost') { icon = <Repeat size={16} className="text-[#00BA7C]" />; text = "reposted your post"; }

if (note.type === 'reply') { icon = <MessageCircle size={16} className="text-[#1D9BF0]" />; text = "replied to you"; }

if (note.type === 'follow') { icon = <UserPlus size={16} className="text-[#1D9BF0]" />; text = "followed you"; }

return (

<div className="p-4 border-b border-[#2F3336] hover:bg-[#080808] flex gap-3 animate-fade-in">

<div className="pt-1 w-8 flex justify-end">{icon}</div>

<div className="flex-1">

<Avatar uid={note.fromUid} username={note.fromUsername} size="sm" onClick={() => openChat(note.fromUid, note.fromUsername)} />

<p className="mt-2 text-[15px]">

<span className="font-bold">{note.fromUsername}</span> <span className="text-[#71767B]">{text}</span>

</p>

{note.text && <p className="text-[#71767B] mt-1 text-[14px] line-clamp-2">"{note.text}"</p>}

</div>

</div>

);

};

// --- Render Main ---

if (loading) return (

<div className="h-screen w-full bg-black flex items-center justify-center">

<div className="w-8 h-8 border-[3px] border-[#1D9BF0] border-t-transparent rounded-full animate-spin"></div>

</div>

);

return (

<div className="flex justify-center min-h-screen bg-black text-white font-sans antialiased selection:bg-[#1D9BF0] selection:text-white">

{/* Edit Profile Modal */}

{isEditingProfile && (

<div className="fixed inset-0 z-[60] flex items-center justify-center bg-[#5B7083]/40 p-4">

<div className="bg-black w-full max-w-lg rounded-2xl shadow-2xl border border-[#2F3336] animate-scale-in flex flex-col max-h-[90vh] overflow-hidden">

{/* Modal Header */}

<div className="flex justify-between items-center px-4 py-3 border-b border-[#2F3336]">

<div className="flex items-center gap-4">

<button onClick={() => setIsEditingProfile(false)} className="hover:bg-[#EFF3F4]/10 p-2 rounded-full -ml-2"><X size={20}/></button>

<h2 className="font-bold text-xl">Edit Profile</h2>

</div>

<button onClick={handleUpdateProfile} className="bg-[#E7E9EA] text-black px-5 py-1.5 rounded-full font-bold text-sm hover:bg-white transition-colors">Save</button>

</div>

{/* Modal Body */}

<div className="overflow-y-auto p-0 flex-1 custom-scrollbar">

{/* Visual Header */}

<div className="relative mb-6">

<div className="h-32 bg-slate-700 opacity-80 flex items-center justify-center">

<div className="bg-black/40 p-3 rounded-full hover:bg-black/50 cursor-pointer backdrop-blur-sm"><Camera size={22} className="text-white"/></div>

</div>

<div className="absolute -bottom-8 left-4 p-1 bg-black rounded-full">

<div className="relative">

<Avatar uid={user.uid} size="xl" className="border-0" />

<div className="absolute inset-0 flex items-center justify-center bg-black/30 rounded-full hover:bg-black/40 cursor-pointer">

<Camera size={20} className="text-white"/>

</div>

</div>

</div>

</div>

{/* Form Fields */}

<div className="mt-12 px-4 space-y-5 pb-6">

{/* Name */}

<div className="border border-[#333639] rounded px-3 py-2 focus-within:border-[#1D9BF0] focus-within:ring-1 focus-within:ring-[#1D9BF0] transition-all bg-black group">

<div className="flex justify-between">

<label className="text-xs text-[#71767B] group-focus-within:text-[#1D9BF0]">Name</label>

<span className="text-xs text-[#71767B]">{editName.length} / 50</span>

</div>

<input

value={editName}

onChange={e => setEditName(e.target.value)}

className="bg-transparent w-full text-white outline-none text-[17px] mt-1"

maxLength={50}

/>

</div>

{/* Bio */}

<div className="border border-[#333639] rounded px-3 py-2 focus-within:border-[#1D9BF0] focus-within:ring-1 focus-within:ring-[#1D9BF0] transition-all bg-black group">

<div className="flex justify-between">

<label className="text-xs text-[#71767B] group-focus-within:text-[#1D9BF0]">Bio</label>

<span className="text-xs text-[#71767B]">{editBio.length} / 160</span>

</div>

<textarea

value={editBio}

onChange={e => setEditBio(e.target.value)}

className="bg-transparent w-full text-white outline-none text-[17px] mt-1 resize-none h-24"

maxLength={160}

/>

</div>

{/* Location */}

<div className="border border-[#333639] rounded px-3 py-2 focus-within:border-[#1D9BF0] focus-within:ring-1 focus-within:ring-[#1D9BF0] transition-all bg-black group">

<label className="text-xs text-[#71767B] block group-focus-within:text-[#1D9BF0]">Location</label>

<input

value={editLocation}

onChange={e => setEditLocation(e.target.value)}

className="bg-transparent w-full text-white outline-none text-[17px] mt-1"

maxLength={30}

/>

</div>

{/* Website */}

<div className="border border-[#333639] rounded px-3 py-2 focus-within:border-[#1D9BF0] focus-within:ring-1 focus-within:ring-[#1D9BF0] transition-all bg-black group">

<label className="text-xs text-[#71767B] block group-focus-within:text-[#1D9BF0]">Website</label>

<input

value={editWebsite}

onChange={e => setEditWebsite(e.target.value)}

className="bg-transparent w-full text-white outline-none text-[17px] mt-1"

maxLength={100}

placeholder="Add your website"

/>

</div>

</div>

</div>

</div>

</div>

)}

{toast && (

<div className="fixed bottom-20 left-1/2 -translate-x-1/2 bg-[#1D9BF0] text-white px-5 py-2.5 rounded-full shadow-[0_8px_30px_rgb(0,0,0,0.3)] z-50 text-[15px] font-medium animate-toast-up">

{toast}

</div>

)}

<div className="w-full max-w-[600px] border-x border-[#2F3336] flex flex-col h-screen relative">

{/* === HEADER === */}

{view === 'thread' || view === 'chat' ? (

<header className="sticky top-0 z-20 bg-black/75 backdrop-blur-md border-b border-[#2F3336] px-4 h-[53px] flex items-center gap-6">

<button

onClick={() => {

if (view === 'chat') {

setActiveChatUser(null);

setView('feed');

} else {

setView('feed');

}

}}

className="p-2 -ml-2 hover:bg-[#EFF3F4]/10 rounded-full transition-colors group"

>

<ArrowLeft size={20} className="text-white group-hover:text-white" />

</button>

<h2 className="text-[20px] font-bold leading-6 text-[#E7E9EA]">

{view === 'chat' ? (activeChatUser?.username || 'Chat') : 'Post'}

</h2>

</header>

) : (

<header className="sticky top-0 z-20 bg-black/75 backdrop-blur-md border-b border-[#2F3336] transition-all">

<div className="px-4 h-[53px] flex items-center justify-between relative">

{/* Left: Avatar */}

<div className="z-30">

<button onClick={() => { setActiveTab('profile'); setView('feed'); }} className="p-1 rounded-full hover:bg-[#EFF3F4]/10 transition-colors">

<Avatar uid={user?.uid || 'anon'} username={username} size="sm" />

</button>

</div>

{/* Center: Title/Search */}

<div className="absolute left-1/2 -translate-x-1/2 flex items-center justify-center">

{activeTab === 'home' && <div className="w-8 h-8"></div>}

{activeTab === 'search' && (

<input

className="bg-[#202327] rounded-full py-2 px-5 text-[15px] w-64 text-white placeholder-[#71767B] focus:outline-none focus:bg-black focus:border focus:border-[#1D9BF0] transition-all"

placeholder="Search"

value={searchQuery}

onChange={e => setSearchQuery(e.target.value)}

/>

)}

{activeTab === 'notifications' && <span className="font-bold text-[17px]">Notifications</span>}

{activeTab === 'messages' && <span className="font-bold text-[17px]">Messages</span>}

{activeTab === 'profile' && (

<div className="flex flex-col items-center">

<span className="font-bold text-[17px]">{username}</span>

<span className="text-xs text-[#71767B]">{filteredTweets.length} posts</span>

</div>

)}

</div>

<div className="w-8"></div>

</div>

{/* Home Tabs */}

{activeTab === 'home' && (

<div className="flex w-full mt-1">

<button onClick={() => setFeedTab('foryou')} className="flex-1 h-[53px] hover:bg-[#EFF3F4]/10 transition-colors relative flex justify-center items-center cursor-pointer">

<div className="relative h-full flex items-center">

<span className=text-[15px] font-bold ${feedTab === 'foryou' ? 'text-[#E7E9EA]' : 'text-[#71767B]'}}>For you</span>

{feedTab === 'foryou' && <div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-14 h-[4px] bg-[#1D9BF0] rounded-full"></div>}

</div>

</button>

<button onClick={() => setFeedTab('following')} className="flex-1 h-[53px] hover:bg-[#EFF3F4]/10 transition-colors relative flex justify-center items-center cursor-pointer">

<div className="relative h-full flex items-center">

<span className=text-[15px] font-bold ${feedTab === 'following' ? 'text-[#E7E9EA]' : 'text-[#71767B]'}}>Following</span>

{feedTab === 'following' && <div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-[70px] h-[4px] bg-[#1D9BF0] rounded-full"></div>}

</div>

</button>

</div>

)}

</header>

)}

{/* === SCROLLABLE CONTENT === */}

<div ref={scrollContainerRef} className="flex-1 overflow-y-auto custom-scrollbar scroll-smooth">

{/* PROFILE VIEW */}

{activeTab === 'profile' && view === 'feed' && (

<div className="animate-fade-in pb-20">

{/* Banner */}

<div className=h-32 w-full ${getCoverColor(user.uid)} relative}></div>

{/* Profile Header */}

<div className="px-4 relative mb-4">

<div className="flex justify-between items-start">

<div className="-mt-10 mb-3">

<Avatar uid={user.uid} username={username} size="xl" />

</div>

<button

onClick={openEditProfile}

className="mt-3 border border-[#536471] text-white font-bold px-4 py-1.5 rounded-full text-[15px] hover:bg-white/10 transition-colors"

>

Edit profile

</button>

</div>

<div>

<h2 className="text-[20px] font-extrabold leading-6 text-[#E7E9EA]">{username}</h2>

<p className="text-[#71767B] text-[15px] mb-3">@{username?.toLowerCase().replace(/\s/g, '')}</p>

{bio && <p className="text-[15px] text-[#E7E9EA] mb-3 whitespace-pre-wrap">{bio}</p>}

<div className="flex flex-wrap gap-y-1 gap-x-4 text-[#71767B] text-[15px] mb-3 items-center">

{location && <div className="flex items-center gap-1"><MapPin size={16} /> {location}</div>}

{website && (

<div className="flex items-center gap-1">

<LinkIcon size={16} />

<a href={website.startsWith('http') ? website : https://${website}} target="_blank" rel="noopener noreferrer" className="text-[#1D9BF0] hover:underline truncate max-w-[200px]">{website.replace(/^https?:\/\//, '')}</a>

</div>

)}

<div className="flex items-center gap-1"><Calendar size={16} /> Joined {user.metadata.creationTime ? new Date(user.metadata.creationTime).toLocaleDateString(undefined, { month: 'long', year: 'numeric' }) : 'recently'}</div>

</div>

<div className="flex gap-4 text-[15px]">

<span className="text-[#71767B]"><span className="font-bold text-[#E7E9EA]">{following.size}</span> Following</span>

<span className="text-[#71767B]"><span className="font-bold text-[#E7E9EA]">0</span> Followers</span>

</div>

</div>

</div>

{/* Profile Tabs */}

<div className="flex border-b border-[#2F3336] mt-2">

<div className="flex-1 h-[53px] hover:bg-[#EFF3F4]/10 transition-colors relative flex justify-center items-center cursor-pointer">

<div className="relative h-full flex items-center">

<span className="text-[15px] font-bold text-[#E7E9EA]">Posts</span>

<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-14 h-[4px] bg-[#1D9BF0] rounded-full"></div>

</div>

</div>

<div className="flex-1 h-[53px] hover:bg-[#EFF3F4]/10 flex justify-center items-center text-[#71767B] font-bold text-[15px]">Replies</div>

<div className="flex-1 h-[53px] hover:bg-[#EFF3F4]/10 flex justify-center items-center text-[#71767B] font-bold text-[15px]">Likes</div>

</div>

{/* Own Tweets */}

{filteredTweets.length === 0 ? (

<div className="p-8 text-center text-[#71767B]">

You haven't posted anything yet.

</div>

) : (

filteredTweets.map(t => <TweetCard key={t.id} data={t} />)

)}

</div>

)}

{/* HOME / SEARCH FEED */}

{(activeTab === 'home' || activeTab === 'search') && view === 'feed' && (

<div className="animate-fade-in pb-20">

{/* Compose (Only on Home/For You) */}

{activeTab === 'home' && feedTab === 'foryou' && (

<div className="border-b border-[#2F3336] px-4 py-3 pb-2 hidden sm:block">

<div className="flex gap-3">

<div className="pt-1"><Avatar uid={user?.uid || 'anon'} username={username} /></div>

<div className="flex-1">

<textarea

value={tweetText}

onChange={(e) => { setTweetText(e.target.value); e.target.style.height = 'auto'; e.target.style.height = e.target.scrollHeight + 'px'; }}

placeholder="What is happening?!"

className="w-full bg-transparent text-[20px] text-[#E7E9EA] placeholder-[#71767B] border-none outline-none resize-none min-h-[56px] py-2 leading-7"

rows={1}

/>

<div className="flex justify-end border-t border-[#2F3336] pt-3 mt-1">

<button onClick={() => handlePost(false)} disabled={!tweetText.trim() || isSubmitting} className="bg-[#1D9BF0] hover:bg-[#1a8cd8] disabled:opacity-50 text-white font-bold px-4 py-1.5 rounded-full text-[15px]">Post</button>

</div>

</div>

</div>

</div>

)}

{/* Feed List */}

{filteredTweets.length === 0 ? (

<div className="p-10 text-center text-[#71767B]">

{feedTab === 'following' ? (

<div className="flex flex-col items-center">

<p className="text-[20px] font-bold text-white mb-2">Welcome to your timeline!</p>

<p className="max-w-xs mb-4">When you follow people, you'll see their Tweets here.</p>

<button onClick={() => setFeedTab('foryou')} className="bg-[#1D9BF0] text-white font-bold px-5 py-2 rounded-full">Find people in For You</button>

</div>

) : (

<p>No posts found.</p>

)}

</div>

) : (

filteredTweets.map(t => <TweetCard key={t.id} data={t} />)

)}

</div>

)}

{/* NOTIFICATIONS */}

{activeTab === 'notifications' && view === 'feed' && (

<div className="animate-fade-in pb-20">

{notifications.length === 0 ? (

<div className="p-12 text-center text-[#71767B]">

<p className="font-bold text-xl text-white mb-2">No notifications yet</p>

<p>When someone likes or replies, you'll see it here.</p>

</div>

) : (

notifications.map(n => <NotificationItem key={n.id} note={n} />)

)}

</div>

)}

{/* MESSAGES LIST */}

{activeTab === 'messages' && view === 'feed' && (

<div className="animate-fade-in pb-20">

{conversations.length === 0 ? (

<div className="p-12 text-center text-[#71767B]">

<div className="w-full flex justify-center mb-4"><Mail size={48} /></div>

<p className="font-bold text-xl text-white mb-2">Welcome to your inbox!</p>

<p className="max-w-xs mx-auto">Drop a line, share Tweets and more with private conversations.</p>

</div>

) : (

conversations.map(c => (

<div

key={c.uid}

onClick={() => openChat(c.uid, c.username)}

className="p-4 border-b border-[#2F3336] hover:bg-[#080808] flex gap-3 cursor-pointer"

>

<Avatar uid={c.uid} username={c.username} />

<div className="flex-1 overflow-hidden">

<div className="flex justify-between">

<span className="font-bold text-[15px]">{c.username}</span>

<span className="text-[#71767B] text-[13px]">{formatTime(c.lastMsg.createdAt)}</span>

</div>

<p className="text-[#71767B] text-[15px] truncate">

{c.lastMsg.from === user.uid ? 'You: ' : ''}{c.lastMsg.text}

</p>

</div>

</div>

))

)}

</div>

)}

{/* CHAT VIEW */}

{view === 'chat' && activeChatUser && (

<div className="flex flex-col h-[calc(100vh-53px)]">

<div className="flex-1 overflow-y-auto p-4 flex flex-col gap-3">

{currentChatMessages.map(m => {

const isMe = m.from === user.uid;

return (

<div key={m.id} className=flex ${isMe ? 'justify-end' : 'justify-start'}}>

<div className=max-w-[75%] px-4 py-2 rounded-2xl text-[15px] break-words ${isMe ? 'bg-[#1D9BF0] text-white rounded-br-none' : 'bg-[#2F3336] text-white rounded-bl-none'}}>

{m.text}

</div>

</div>

);

})}

<div ref={(el) => el?.scrollIntoView({ behavior: 'smooth' })} />

</div>

<div className="p-3 border-t border-[#2F3336] flex gap-2 items-center">

<input

className="flex-1 bg-[#202327] rounded-full px-4 py-2 focus:outline-none focus:border-[#1D9BF0] border border-transparent text-white"

placeholder="Start a new message"

value={messageText}

onChange={e => setMessageText(e.target.value)}

onKeyDown={e => e.key === 'Enter' && handleSendMessage()}

/>

<button onClick={handleSendMessage} disabled={!messageText.trim()} className="text-[#1D9BF0] p-2 hover:bg-[#1D9BF0]/10 rounded-full disabled:opacity-50">

<Send size={20} />

</button>

</div>

</div>

)}

{/* THREAD VIEW */}

{view === 'thread' && activeTweet && (

<div className="animate-slide-left pb-40">

<TweetCard data={activeTweet} isMain={true} />

<div className="border-b border-[#2F3336] px-4 py-3">

<div className="flex gap-3">

<div className="pt-1"><Avatar uid={user?.uid || 'anon'} username={username} /></div>

<div className="flex-1">

<textarea

value={tweetText}

onChange={(e) => { setTweetText(e.target.value); e.target.style.height = 'auto'; e.target.style.height = e.target.scrollHeight + 'px'; }}

placeholder="Post your reply"

className="w-full bg-transparent text-[20px] text-[#E7E9EA] placeholder-[#71767B] border-none outline-none resize-none min-h-[24px] py-2"

rows={1}

autoFocus

/>

<div className="flex justify-end pt-2">

<button onClick={() => handlePost(true)} disabled={!tweetText.trim() || isSubmitting} className="bg-[#1D9BF0] hover:bg-[#1a8cd8] disabled:opacity-50 text-white font-bold px-4 py-1.5 rounded-full text-[15px]">Reply</button>

</div>

</div>

</div>

</div>

<div>

{comments.map(c => <TweetCard key={c.id} data={c} isComment={true} />)}

{comments.length === 0 && <div className="h-32"></div>}

</div>

</div>

)}

</div>

{/* === BOTTOM NAVIGATION === */}

{view !== 'chat' && (

<nav className="h-[53px] border-t border-[#2F3336] bg-black flex justify-around items-center px-2 pb-safe z-50">

<NavItem icon={HomeIcon} active={activeTab === 'home'} onClick={() => { setActiveTab('home'); setView('feed'); }} />

<NavItem icon={Search} active={activeTab === 'search'} onClick={() => setActiveTab('search')} />

<NavItem icon={Bell} active={activeTab === 'notifications'} onClick={() => setActiveTab('notifications')} badge={notifications.filter(n => !n.read).length} />

<NavItem icon={Mail} active={activeTab === 'messages'} onClick={() => setActiveTab('messages')} />

<NavItem icon={User} active={activeTab === 'profile'} onClick={() => setActiveTab('profile')} />

</nav>

)}

</div>

{/* --- Styles --- */}

<style>{`

.custom-scrollbar::-webkit-scrollbar { width: 0px; background: transparent; }

@keyframes heartPop { 0% { transform: scale(1); } 50% { transform: scale(1.4); } 100% { transform: scale(1); } }

.animate-heart-pop { animation: heartPop 0.45s cubic-bezier(0.175, 0.885, 0.32, 1.275); }

@keyframes heartRing { 0% { transform: scale(0.5); opacity: 1; border-width: 2px; } 100% { transform: scale(2); opacity: 0; border-width: 0px; } }

.animate-heart-ring { animation: heartRing 0.45s ease-out; }

@keyframes toastUp { from { opacity: 0; transform: translate(-50%, 20px); } to { opacity: 1; transform: translate(-50%, 0); } }

.animate-toast-up { animation: toastUp 0.3s ease-out; }

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

.animate-fade-in { animation: fadeIn 0.2s ease-out; }

@keyframes scaleIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }

.animate-scale-in { animation: scaleIn 0.2s cubic-bezier(0.4, 0, 0.2, 1); }

`}</style>

</div>

);

}