Skip to content

Commit

Permalink
Merge pull request #7 from phertyameen/develop
Browse files Browse the repository at this point in the history
initial commit from message.pg
  • Loading branch information
Ibinola authored Sep 15, 2024
2 parents 60fdbdd + 468cb77 commit 95ae409
Show file tree
Hide file tree
Showing 14 changed files with 585 additions and 5 deletions.
21 changes: 21 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@
color: #61dafb;
}

/* messages section */
/* In your CSS file */
.scrollbar-custom {
scrollbar-width: thin;
scrollbar-color: #4A90E2 #F5F5F5; /* Thumb color and track color */
}

.scrollbar-custom::-webkit-scrollbar {
width: 12px;
}

.scrollbar-custom::-webkit-scrollbar-thumb {
background-color: #4A90E2; /* Thumb color */
border-radius: 6px;
}

.scrollbar-custom::-webkit-scrollbar-track {
background-color: #F5F5F5; /* Track color */
}


@keyframes App-logo-spin {
from {
transform: rotate(0deg);
Expand Down
19 changes: 19 additions & 0 deletions src/assets/svgs/dangerAlertIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions src/assets/svgs/delete-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions src/assets/svgs/file-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/svgs/foward-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/svgs/img.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 49 additions & 0 deletions src/components/messageComponent/ChatHeader.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from "react";
import ViewProfileMenu from "./ViewProfileMenu";

const ChatHeader = ({ selectedUser, messages, setFileList, setSentMessages }) => {
// handling File Click
const handleFileClick = () => {
if (selectedUser) {
const userMessages = messages.find(
(msg) => msg.name === selectedUser.name
);

const files = userMessages.chatMessages
.flatMap((msg) => msg.files)
.filter((file) => file);

setFileList(files); // Set the files to display in the chat section
}
};

// Your logic for deleting a chat
const handleDeleteChat = () => {
// setSelectedUser(null); // Clear selected user
setFileList([]); // Clear file list
setSentMessages([]); // Clear sent messages
};

return (
<div className="py-[18px] px-[14px] border-b flex items-center justify-between bg-white">
<div className="flex items-center space-x-2">
<div className="px-4 py-2 bg-[#4CAF50] rounded-full text-white">
{selectedUser.initials}
</div>
<div>
<h3 className="font-semibold">{selectedUser.name}</h3>
<p className="text-sm text-gray-500">Email not available</p>
</div>

</div>
{/*ViewProfileMenu */}
<ViewProfileMenu
handleFileClick={handleFileClick}
handleDeleteChat={handleDeleteChat}
userName={selectedUser.name}
/>
</div>
);
};

export default ChatHeader;
35 changes: 35 additions & 0 deletions src/components/messageComponent/ChatMessages.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from "react";

const ChatMessages = ({ sentMessages, fileList }) => {
return (
<div className="flex-1 p-4 space-y-4 overflow-y-auto bg-gray-50">
{sentMessages.map((message, idx) => (
<div key={idx} className="flex items-end justify-end space-x-2">
<div className="relative">
<div className="bg-blue-500 text-white p-3 rounded-lg max-w-md">
<p className="text-sm">{message.text}</p>
</div>
<span className="absolute left-0 top-12 text-xs text-[#969CA6] self-end">
{message.time}
</span>
</div>
</div>
))}

{fileList.length > 0 && (
<div className="p-3 rounded-lg max-w-md bg-gray-100">
<h4 className="font-semibold mb-2">Files:</h4>
{fileList.map((file, idx) => (
<div key={idx} className="flex items-center space-x-2">
<p className="text-sm">
{file.fileName} ({file.fileSize})
</p>
</div>
))}
</div>
)}
</div>
);
};

export default ChatMessages;
67 changes: 67 additions & 0 deletions src/components/messageComponent/InputArea.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useState, useRef } from "react";
import fileSvg from "../../assets/svgs/file-icon.svg";
import imgSvg from "../../assets/svgs/img.svg";

const InputArea = ({ onSendMessage, onSendFile }) => { // Add onSendFile prop
const [inputMessage, setInputMessage] = useState("");
const fileInputRef = useRef(null);

const handleSendMessage = () => {
if (inputMessage.trim()) {
onSendMessage(inputMessage);
setInputMessage("");
}
};

const handleFileSelect = (e) => {
const file = e.target.files[0];
if (file) {
onSendFile(file); // Send selected file back to parent component
setInputMessage("");
}
};

return (
<div className="p-4 border-t flex items-center space-x-4 bg-white">
<div className="relative flex-1">
<input
type="text"
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
placeholder="Type a message"
className="w-full border rounded-lg p-2 pr-14 active:border-[#207DF7] outline-none bg-transparent"
/>
<div className="absolute inset-y-0 right-2 flex items-center space-x-2">
<img
src={imgSvg}
alt="image"
className="cursor-pointer"
onClick={() => fileInputRef.current.click()} // Trigger file input
/>
<img
src={fileSvg}
alt="file"
className="cursor-pointer"
onClick={() => fileInputRef.current.click()} // Trigger file input
/>
</div>
</div>
<button
onClick={handleSendMessage}
className="py-[11px] px-[24px] bg-blue-500 text-white rounded-lg hover:bg-blue-600"
>
Send
</button>

{/* Hidden file input */}
<input
type="file"
ref={fileInputRef}
style={{ display: 'none' }}
onChange={handleFileSelect}
/>
</div>
);
};

export default InputArea;
50 changes: 50 additions & 0 deletions src/components/messageComponent/MessageConfirmDelete.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from "react";
import alertSvg from "../../assets/svgs/dangerAlertIcon.svg";

const MessageConfirmDelete = ({ isOpen, onClose, onConfirm, userName }) => {
if (!isOpen) return null; // Don't render if modal is not open

return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
<div className="bg-white rounded-lg shadow-lg p-6 w-96 relative">
{/* Close Button */}
<button
onClick={onClose}
className="absolute top-4 right-4 text-gray-400 hover:text-gray-600"
>
Close x
</button>

{/* Alert Icon */}
<div className="flex justify-center mb-4">
<img src={alertSvg} alt="Alert" className="w-12 h-12 text-red-500" />
</div>

{/* Title */}
<h2 className="text-center text-xl font-semibold mb-4">
Delete Chat with {userName}?
</h2>
<p className="text-gray-600 text-center mb-6">
This will clear all conversations and remove {userName} from your
message list. This action cannot be undone.
</p>
<div className="flex justify-between">
<button
onClick={onClose}
className="bg-gray-300 hover:bg-gray-400 text-gray-800 py-2 px-4 rounded w-1/2 mr-2"
>
Cancel
</button>
<button
onClick={onConfirm} // Corrected to match the prop name in ViewProfileMenu
className="bg-red-500 hover:bg-red-600 text-white py-2 px-4 rounded w-1/2 ml-2"
>
Delete
</button>
</div>
</div>
</div>
);
};

export default MessageConfirmDelete;
35 changes: 35 additions & 0 deletions src/components/messageComponent/MessageList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from "react";

const MessageList = ({ messages, onUserClick }) => {
return (
<div className="space-y-2 mt-4 h-[80vh] max-h-[80vh] bg-white overflow-y-auto scrollbar-custom">
{messages.map((message, idx) => {
const initials = message.name[0];
return (
<div
key={idx}
className="flex space-x-2 hover:bg-gray-200 p-2 rounded-lg cursor-pointer border-b-2 border-[#EBECF0] justify-between"
onClick={() => onUserClick({ name: message.name, initials })}
>
<div className="flex flex-row gap-1">
<div className="initials w-10 h-10 bg-blue-500 text-white rounded-full flex items-center justify-center">
{initials}
</div>
<div>
<h3 className="font-semibold">{message.name}</h3>
<p className="text-gray-500 text-sm">
Parturient amet sociis tempor...
</p>
</div>
</div>
<span className={`text-xs ${message.isRead ? "text-gray-400" : "text-[#207DF7]"}`}>
2:23
</span>
</div>
);
})}
</div>
);
};

export default MessageList;
26 changes: 26 additions & 0 deletions src/components/messageComponent/SearchIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react'

const SearchIcon = ({ handleSearch }) => {
return (
<div>
<div className="border-[1.5px] bg-[#F9F9FC] flex px-4 py-2 mr-3 rounded-md">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 192.904 192.904"
width="16px"
className="fill-gray-600 mr-3 rotate-90"
>
<path d="M190.707 180.101L143.629 133.024c11.702-14.072 18.752-32.142 18.752-51.831C162.381 36.423 125.959 0 81.191 0 36.422 0 0 36.423 0 81.193c0 44.767 36.422 81.187 81.191 81.187 19.688 0 37.759-7.049 51.831-18.751l47.079 47.078a7.474 7.474 0 0 0 5.303 2.197 7.498 7.498 0 0 0 5.303-12.803zM15 81.193C15 44.694 44.693 15 81.191 15c36.497 0 66.189 29.694 66.189 66.193 0 36.496-29.692 66.187-66.189 66.187C44.693 147.38 15 117.689 15 81.193z" />
</svg>
<input
type="text"
placeholder="Search"
onChange={(e) => handleSearch(e.target.value)}
className="w-full outline-none bg-transparent text-gray-600 text-sm"
/>
</div>
</div>
)
}

export default SearchIcon
Loading

0 comments on commit 95ae409

Please sign in to comment.