MS
Mayank Sriavstava

Chat Profile Section - Copy this React, Tailwind Component to your project

Import React, { useState, useEffect, useRef } from "react"; import { PiWarningCircleLight } from "react icons/pi"; import { RxCross2 } from "react icons/rx"; import { BsCheck2, BsCheck2All } from "react icons/bs"; import { FaBars, FaPaperclip, FaMicrophone, FaEyeDropper, FaPaperPlane, FaSearch, FaStar, FaPrint, FaTrash, FaArrowLeft, FaFileImage, FaRegStar, } from "react icons/fa"; import { BiDotsVerticalRounded } from "react icons/bi"; import { IoIosArrowBack, IoIosArrowRoundBack } from "react icons/io"; import { MdDelete, MdPrint } from "react icons/md"; import { TbMessageFilled } from "react icons/tb"; import { useOutletContext } from "react router dom"; const ChatApplication = () => { const [isSidebarOpen, setIsSidebarOpen] = useState(true); const [message , setMessage] = useState(""); const [isTyping , setIsTyping] = useState(false); const [selectedChat, setSelectedChat] = useState(null); const [isProfileOpen, setIsProfileOpen] = useState(false); const messagesEndRef = useRef(null); const[isMob, setIsMob] = useState(false); const { isMobile , setIsMobile } = useOutletContext(); useEffect(() => { const handleResize = () => { setIsMob(window.innerWidth <= 850); }; // Set initial value handleResize(); window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []); const contacts = [ { id: 1, name: "John Smith", avatar: "https://images.unsplash.com/photo 1472099645785 5658abf4ff4e", lastMessage: "How are you doing?", unread: 2, isOnline: true, isTyping: false, isPinned: true, userId: "JS123", email: "john.smith@example.com", phone: "+1 234 567 8901", shiftTiming: "9:00 AM 5:00 PM", address: "123 Main St, New York, NY", gender: "Male", dob: "1990 05 15", joinedDate: "2022 01 10", }, { id: 2, name: "Sarah Johnson", avatar: "https://images.unsplash.com/photo 1438761681033 6461ffad8d80", lastMessage: "See you tomorrow!", unread: 1, isOnline: true, isTyping: true, isPinned: true, userId: "SJ456", email: "sarah.j@example.com", phone: "+1 234 567 8902", shiftTiming: "10:00 AM 6:00 PM", address: "456 Oak St, Boston, MA", gender: "Female", dob: "1992 08 20", joinedDate: "2022 02 15", }, { id: 3, name: "Mike Wilson", avatar: "https://images.unsplash.com/photo 1500648767791 00dcc994a43e", lastMessage: "Let's meet tomorrow", unread: 0, isOnline: false, isTyping: false, isPinned: false, userId: "MW789", email: "mike.w@example.com", phone: "+1 234 567 8903", shiftTiming: "8:00 AM 4:00 PM", address: "789 Pine St, Chicago, IL", gender: "Male", dob: "1988 12 10", joinedDate: "2022 03 20", }, ]; const messages = [ { id: 1, text: "Hi there!", sender: "user", timestamp: "09:30 AM" }, { id: 2, text: "Hello! How are you?", sender: "other", timestamp: "09:31 AM", }, { id: 3, text: "I'm doing great, thanks! kckca kkakkxk meimkcd mcekmc cmmasao eowmcmc maqmocl", sender: "user", timestamp: "09:32 AM", }, ]; useEffect(() => { scrollToBottom(); }, [messages]); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; const handleMessageSubmit = (e) => { e.preventDefault(); if (message.trim()) { setMessage(""); } }; const handleTyping = (e) => { setMessage(e.target.value); setIsTyping(true); setTimeout(() => setIsTyping(false), 2000); }; const ProfileSection = ({ user, isMobile }) => ( <div className={`w [350px] border l border border bg card rounded lg overflow y auto ${ isMobile ? "absolute top 0 right 0 w [350px] h full z 20" : "" }`} > <div className="flex justify between items center p 4 mb 2"> <button onClick={() => setIsProfileOpen(false)} className="p 1 hover:bg gray 400 bg gray 100 rounded full" > <IoIosArrowRoundBack className="text 2xl" /> </button> <span className={`px 3 py 1 rounded md ${ user.isOnline ? "bg [#058C1C] text white" : "bg gray 300" }`} > {user.isOnline ? "Active" : "Inactive"} </span> </div> <div className="flex flex col items center pb 4 border b border border"> <img src={user.avatar} alt={user.name} className="w 20 h 20 rounded full object cover mb 4" /> <h2 className="text xl font semibold mb 2">{user.name}</h2> <p className="text [#6F767E]">User ID: {user.userId}</p> </div> <div className="mt 4 space y 3 p 3"> <div className="p 3 border border gray 200 rounded lg"> <p className="text sm text [#6F767E]">Email</p> <p>{user.email}</p> </div> <div className="p 3 border border gray 200 rounded lg"> <p className="text sm text [#6F767E]">Phone Number</p> <p>{user.phone}</p> </div> <div className="p 3 border border gray 200 rounded lg"> <p className="text sm text [#6F767E]">Shift</p> <p>{user.shiftTiming}</p> </div> <div className="p 3 border border gray 200 rounded lg"> <p className="text sm text [#6F767E]">Address</p> <p>{user.address}</p> </div> <div className="p 3 border border gray 200 rounded lg"> <p className="text sm text [#6F767E]">Gender</p> <p>{user.gender}</p> </div> <div className="p 3 border border gray 200 rounded lg"> <p className="text sm text [#6F767E]">Date of Birth</p> <p>{user.dob}</p> </div> <div className="p 3 border border gray 200 rounded lg"> <p className="text sm text [#6F767E]">Joined Date</p> <p>{user.joinedDate}</p> </div> </div> </div> ); const renderContacts = (isPinned) => { return contacts .filter((contact) => contact.isPinned === isPinned) .map((contact) => ( <div key={contact.id} onClick={() => setSelectedChat(contact)} className={`flex items center p 3 rounded lg cursor pointer ${ selectedChat?.id === contact.id ? "bg [#E3F3E4] text gray 500" : "hover:bg [#E3F3E4]" }`}> <div className="relative"> <img src={contact.avatar} alt={contact.name} className={` ${isMobile?"w 8 h 8":"w 12 h 12"} rounded full object cover`} /> {contact.isOnline && ( <div className="absolute bottom 0 right 0 w 3 h 3 bg [#01B507] rounded full border 2 border card" /> )} </div> <div className="ml 3 flex 1"> <div className="flex justify between "><h3 className={`font semibold ${isMobile?"text xs":"text sm"} `}>{contact.name}</h3> <p className="text [10px] mt 1 text [#777777]">10:30 AM</p></div> <p className={` ${isMobile?"text [10px]":"text xs"} ${contact.isTyping ? "text [#258C60]" : ""}`}> {contact.isTyping ? "Typing..." : contact.lastMessage} </p> </div> {contact.unread > 0 && ( <div className="bg [#058C1C] text destructive foreground rounded full w 4 h 4 mt 5 flex items center justify center text xs"> {contact.unread} </div> )} {contact.unread === 0 && ( <div className="text [#01B507] flex items center justify center mt 3"> <BsCheck2All /> </div> )} </div> )); }; return ( <div className="flex max w [calc(100vw 50px)] gap 4 h [calc(100vh 150px)] bg gray 100"> {/* Sidebar */} <div className={`${ isSidebarOpen ? (isMob?"w [30%]" : "w [24%]"):"w 0" } rounded lg mr 2 bg white transition all duration 300 overflow y auto`}> <div className="p 4"> <div className="flex items center justify between mb 4"> <h2 className="text heading text 2xl font bold font heading" style={{ fontFamily: "Inter", // Font applied }}> Chat </h2> <button onClick={() => setIsSidebarOpen(false)} className="lg:hidden p 2 hover:bg muted rounded full" aria label="Close sidebar"> <FaBars /> </button> </div> <div className=" mb 4"> <input type="text" placeholder="Search..." className="w full pl 10 pr 4 py 2 bg muted rounded lg focus:ring 2 focus:ring ring focus:outline none" /> </div> {/* Pinned Contacts */} <div className="mb 4"> <h3 className="text sm font semibold text gray 400 mb 2 flex"> <FaEyeDropper className="mr 2 mt 1" /> PINNED </h3> <div className="space y 2">{renderContacts(true)}</div> </div> {/* All Messages */} <div> <h3 className="text sm font semibold text gray 400 mb 2 flex"> <TbMessageFilled className="mr 2 mt 1"/> All Messages </h3> <div className="space y 2">{renderContacts(false)}</div> </div> </div> </div> {/* Main Chat Area */} <div className="flex 1 flex flex col bg white rounded lg"> {/* Chat Header */} <div className="bg white rounded t lg p 4 border b [1px] border gray 300 flex items center "> <button onClick={() => setIsSidebarOpen(true)} className="lg:hidden p 2 mr 2 hover:bg muted rounded full" aria label="Open sidebar"> <FaBars /> </button> {selectedChat ? ( <div className="bg white justify between flex items center w full"> <div className="ml 3 flex"> <IoIosArrowBack className="mr 3 bg gray 100 rounded sm text md cursor pointer" onClick={() => setSelectedChat(null)} /> <h3 className="font [700] cursor pointer mt 1 items center" onClick={() => setIsProfileOpen(!isProfileOpen)}> {selectedChat.name} </h3>{" "} <p className="ml 3 mt [1px] text [#7D0A99] bg [#f6eaf9] px 2 py 1/2 rounded md font semibold text sm"> Admin </p> </div> <div className="flex items center border border solid [1px] rounded xl"> <button className="p [8px] hover:bg muted border rounded tl xl rounded bl xl border solid [1px]"> <MdPrint /> </button> <button className="p [8px] hover:bg muted border border solid [1px]"> <FaRegStar /> </button> <button className="p [8px] hover:bg muted border solid [1px] rounded tr xl rounded br xl border"> <MdDelete /> </button> </div> </div> ) : ( <p className="text accent">Select a chat to start messaging</p> )} </div> {/* Messages */} <div className="flex 1 overflow y auto p 4 space y 4"> <div className="p 3 border border [#E8CA7C] bg [#FFFAEA] rounded lg"> <p className="text sm text [#945E12] ">Please reply in a professional manner and avoid using SMS language, emojis etc. Use of unprofessional language may lead to rejection of your application.</p> </div> <div className="flex justify end rounded br none"> <div className="w full max w md bg [#01B507] text white rounded lg rounded br none "> <div className="flex flex col p 4 space x 3 "> <p className="ml 2">Hi, Alex!</p> <p className="mt 2"> <span className="font semibold">Reason Of decline Request:</span> There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration. </p> <div className="flex justify end items center space x 2 mt 1"> <span className={`text xs `}> 10:00 AM </span> <button className={`p 1 rounded full`}> <BiDotsVerticalRounded size={16} /> </button> </div> </div> <div className="border t border white "></div> <div className="mt 4 p 4"> <button className="w full py 2 bg white text [#015B11] font semibold rounded md hover:bg gray 100"> Re Request </button> </div> </div> </div> {messages.map((msg) => ( <div key={msg.id} className={`flex ${msg.sender === "user" ? "justify end" : ""}`}> <div className={`max w [70%] rounded lg p 3 ${ msg.sender === "user" ? "bg [#01B507] text primary foreground rounded br none" : "bg muted rounded bl none" }`}> <p>{msg.text}</p> <div className="flex justify end items center space x 2 mt 1"> <span className={`text xs ${ msg.sender === "user" ? "" : "text [#757575]" } `}> {msg.timestamp} </span> <button className={`p 1 ${ msg.sender === "user" ? "" : "text [#757575]" } rounded full`}> <BiDotsVerticalRounded size={16} /> </button> </div> </div> </div> ))} <div ref={messagesEndRef} /> <div className="max w md ml auto bg [#01B507] rounded br none text white p 1 rounded lg "> {/* Inner Message Box */} <div className="bg white text gray 700 rounded md p 3 mb 4 shadow sm"> {/* Header */} <div className="flex items center justify between"> <h3 className="font semibold text [#058C1C]">Minerva Barnett <span className="text xs ml 1 text gray 400">6.30 pm</span></h3> <span className="text xs text gray 400"><RxCross2 className="text xl cursor pointer"/> </span> </div> {/* Message Text */} <p className="mt 2 text sm"> The point of using Lorem Ipsum is that it has a more or less normal distribution of letters, as opposed to using 'Content here, content here'. </p> </div> {/* Footer Text */} <p className="text sm p 3"> Hello! Good Morning Alex. Lorem ipsum dolor sit amet lorem uipsum dolor sit amet. </p> {/* Timestamp */} <div className="text right text xs text white mt 2 pr 2 pb 2">6.34 pm</div> </div> <div className="max w lg bg green 50 border flex flex col justify start border gray 200 rounded lg p 0"> {/* Header */} <div className="bg [#E3F3E4] text [#202224] font bold text sm p 4 py 2 rounded md"> Request: Create Divyajoti store </div> {/* Content */} <div className="text [#272727] font medium p 4 pt 2 bg [#fcfffc] border border gray 300 border t 0 border l 0 border r 0 border solid [2px]"> <p className="mb 2">Hi, Alex!</p> <p className="mb 2"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s. </p> <p className="mb 2"> <span className="font semibold">Request:</span>{' '} <span className="text [#048C1C]"> ‘Your message to the admin for approved request has been successfully delivered.’ </span> </p> <p className="mb 2"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text. </p> <p className="mb 4">Thank you!</p> <p className="font bold text sm mb 4"> Submission Deadline: <span className="font bold">25 April, 2024</span> </p> <span className="text xs text [#048C1C] flex justify end">6.34 pm <BiDotsVerticalRounded size={16} /> </span> </div> {/* Footer */} <div className="flex items center justify between py 4 pl 4"> <button className="px 10 py 3 bg [#048C1C] text white text sm font semibold rounded md hover:bg green 600"> Open Request </button> </div> {/* Error Message */} </div> <p className="mt 3 text sm text red 600 flex"> <PiWarningCircleLight className="text lg mr 2 mt [2px]"/> The deadline for the assignment submission has expired. You can still upload the assignment with a note. </p> </div> {/* Message Input */} <form onSubmit={handleMessageSubmit} className="p 4 bg white border t [2px] rounded b lg border gray 300"> <div className="flex items center space x 2"> <button type="button" className="p 2 hover:bg muted rounded full" aria label="Attach file"> <FaMicrophone className="text [#9D9D9D]" /> </button> <input type="text" value={message} onChange={handleTyping} placeholder="Write message..." className="flex 1 p 2 border border transparent rounded sm focus:outline none hover:border gray 300" /> <button type="button" className="p 2 hover:bg muted rounded full" aria label="Voice message"> <FaPaperclip className="text [#9D9D9D]" /> </button> <button type="button" className="p 2 hover:bg muted rounded full" aria label="Voice message"> <FaFileImage className="text [#9D9D9D]" /> </button> <button type="submit" className="py 2 bg [#1E9833] text xs text white px 4 flex gap 2 rounded sm hover:bg opacity 90 transition colors" aria label="Send message"> Send <FaPaperPlane className="mt 1" /> </button> </div> </form> </div> {/* Profile Section Outside Chat Container */} {isProfileOpen && selectedChat && <ProfileSection user={selectedChat} isMobile={isMobile} />} </div> ); }; export default ChatApplication; update it, when for isMobile false the profile is opening from left side, but ismobile is true it should take of main chat area,when closing the profile section clicking onaroow prsent on top the main chat area reappear. dont change any other thing

Prompt
Component Preview

About

ChatProfileSection - A responsive chat profile area with user details, online status, and message history. Built with React and Tailwi. Get component free!

Share

Last updated 1 month ago