added file preview

This commit is contained in:
slawk0
2024-12-01 20:03:39 +01:00
parent 47f145216d
commit e3aaf4675e
3 changed files with 123 additions and 62 deletions

18
client/assets/group.svg Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" ?>
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<defs>
<style>.cls-1{fill:#101820;}</style>
</defs>
<title/>
<g data-name="Layer 20" id="Layer_20">
<path class="cls-1" d="M16,22a6,6,0,1,1,6-6A6,6,0,0,1,16,22Zm0-10a4,4,0,1,0,4,4A4,4,0,0,0,16,12Z"/>
<path class="cls-1"
d="M21,31H11a4,4,0,0,1-4-4V24.45a1,1,0,0,1,.63-.92l3.64-1.46A1,1,0,1,1,12,23.93l-3,1.2V27a2,2,0,0,0,2,2H21a2,2,0,0,0,2-2V25.13l-3-1.2a1,1,0,0,1,.74-1.86l3.64,1.46a1,1,0,0,1,.63.92V27A4,4,0,0,1,21,31Z"/>
<path class="cls-1" d="M9,11a5,5,0,1,1,5-5A5,5,0,0,1,9,11ZM9,3a3,3,0,1,0,3,3A3,3,0,0,0,9,3Z"/>
<path class="cls-1"
d="M8,19.39H5a4,4,0,0,1-4-4V13.64a1,1,0,0,1,.63-.93l3.19-1.25A1,1,0,0,1,6.11,12a1,1,0,0,1-.56,1.3L3,14.32v1.07a2,2,0,0,0,2,2H8a1,1,0,0,1,0,2Z"/>
<path class="cls-1" d="M23,11a5,5,0,1,1,5-5A5,5,0,0,1,23,11Zm0-8a3,3,0,1,0,3,3A3,3,0,0,0,23,3Z"/>
<path class="cls-1"
d="M27,19.39H24a1,1,0,0,1,0-2h3a2,2,0,0,0,2-2V14.32l-2.55-1a1,1,0,0,1-.56-1.3,1,1,0,0,1,1.29-.57l3.19,1.25a1,1,0,0,1,.63.93v1.75A4,4,0,0,1,27,19.39Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

15
client/assets/group2.svg Normal file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0" ?>
<svg fill="none" height="27" viewBox="0 0 35 27" width="35" xmlns="http://www.w3.org/2000/svg">
<path d="M5.60001 12.6C7.1464 12.6 8.39999 11.3464 8.39999 9.8C8.39999 8.25361 7.1464 7 5.60001 7C4.05361 7 2.8 8.25361 2.8 9.8C2.8 11.3464 4.05361 12.6 5.60001 12.6Z"
stroke="#4F4F4F" stroke-miterlimit="10" stroke-width="2"/>
<path d="M8.3 23.6H2.60001C1.70001 23.6 1.10001 22.9 1.10001 22V19.2C1.10001 17 2.8 15.3 5 15.3H8.5"
stroke="#4F4F4F" stroke-miterlimit="10" stroke-width="2"/>
<path d="M17.6 10C20.0301 10 22 8.03007 22 5.60001C22 3.16996 20.0301 1.20001 17.6 1.20001C15.17 1.20001 13.2 3.16996 13.2 5.60001C13.2 8.03007 15.17 10 17.6 10Z"
stroke="#4F4F4F" stroke-miterlimit="10" stroke-width="2"/>
<path d="M24.1 25.2H10.7C9.3 25.2 8.2 24.1 8.2 22.7V18.4C8.2 15 11.1 12.2 14.6 12.2H20.3C23.8 12.2 26.7 15 26.7 18.4V22.7C26.6 24.1 25.5 25.2 24.1 25.2Z"
stroke="#4F4F4F" stroke-miterlimit="10" stroke-width="2"/>
<path d="M29 12.6C30.5464 12.6 31.8 11.3464 31.8 9.8C31.8 8.25361 30.5464 7 29 7C27.4536 7 26.2 8.25361 26.2 9.8C26.2 11.3464 27.4536 12.6 29 12.6Z"
stroke="#4F4F4F" stroke-miterlimit="10" stroke-width="2"/>
<path d="M26.3 23.6H32C32.9 23.6 33.5 22.9 33.5 22V19.2C33.5 17 31.8 15.3 29.6 15.3H26.1" stroke="#4F4F4F"
stroke-miterlimit="10" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -6,7 +6,7 @@ import { customAlphabet } from 'nanoid';
import { useOutletContext } from 'react-router-dom';
import { ChatMessages, ContactsProps } from '../../pages/Chat.tsx';
import { axiosClient } from '../../App.tsx';
import { File, Paperclip } from 'lucide-react';
import { File, Paperclip, X } from 'lucide-react';
const nanoid = customAlphabet('1234567890', 5);
@@ -48,6 +48,14 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
adjustHeight();
}, [message, adjustHeight]);
const handleClearFile = () => {
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
setFile(null);
setValue('attachment', null);
};
if (!socket) {
console.error('Socket not initialized');
return;
@@ -96,13 +104,13 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
}
}
const tempId: string = nanoid(); // Temporary ID for unsent messages
const tempId: string = nanoid();
const tempMessage: ChatMessages = {
sender: username,
message: data.message.trim(),
recipient: contact.conversation_id,
message_id: 0, // Set to 0 because of key={msg.message_id || msg.tempId} in messages list
message_id: 0,
pending: true,
tempId: tempId,
attachment_url: attachmentUrl || null,
@@ -110,7 +118,7 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
conversation_id: 0,
};
setMessages((prevMessages) => [...prevMessages, tempMessage]); // Display as gray
setMessages((prevMessages) => [...prevMessages, tempMessage]);
socket.emit(
'chat message',
@@ -141,8 +149,7 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
);
reset({ message: '' });
setValue('attachment', null);
setFile(null);
handleClearFile();
}
console.log(
`status: ${response.status}, tempId: ${response.tempId}, message: ${response.message}`,
@@ -158,7 +165,6 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
});
};
// Handle Enter and Ctrl+Enter in textarea
const handleKeyPress: KeyboardEventHandler<HTMLTextAreaElement> = (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
@@ -187,63 +193,85 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
return (
<form onSubmit={handleSubmit(submitMessage)} className="w-full">
<div className="flex items-end gap-2 w-full text-center">
<div className="flex-1 inline-block">
<div className="relative flex justify-center">
<textarea
{...messageRegister}
ref={(e) => {
ref(e);
textareaRef.current = e;
}}
className={`w-full overflow-y-hidden resize-none bg-green-50 text-black rounded-md p-2 min-h-[40px] max-h-96
${isOverLimit ? 'border-2 border-red-500' : isNearLimit ? 'border-2 border-yellow-500' : ''} mx-auto`}
autoFocus={!!contact}
disabled={!contact}
placeholder="Enter message"
onKeyDown={handleKeyPress}
rows={1}
/>
<span
className={`absolute right-2 bottom-1 text-sm ${
isOverLimit
? 'text-red-500 font-bold'
: isNearLimit
? 'text-yellow-600'
: 'text-gray-500'
}`}
<div className="flex flex-col gap-2 w-full">
{file && (
<div className="flex items-center justify-between p-2 bg-green-50 rounded-md mx-2">
<div className="flex items-center">
<File className="w-4 h-4 mr-2" />
<span className="text-black text-sm truncate">{file.name}</span>
<span className="text-xs text-gray-500 ml-2">
({Math.round(file.size / 1024)} KB)
</span>
</div>
<button
type="button"
onClick={handleClearFile}
className="p-1 hover:bg-green-100 rounded-full"
aria-label="Clear file"
>
{charCount}/2000
</span>
<X className="w-4 h-4 text-gray-500" />
</button>
</div>
)}
<div className="flex items-end gap-2 w-full text-center">
<div className="flex-1 inline-block">
<div className="relative flex justify-center">
<textarea
{...messageRegister}
ref={(e) => {
ref(e);
textareaRef.current = e;
}}
className={`w-full overflow-y-hidden resize-none bg-green-50 text-black rounded-md p-2 min-h-[40px] max-h-96
${isOverLimit ? 'border-2 border-red-500' : isNearLimit ? 'border-2 border-yellow-500' : ''} mx-auto`}
autoFocus={!!contact}
disabled={!contact}
placeholder="Enter message"
onKeyDown={handleKeyPress}
rows={1}
/>
<span
className={`absolute right-2 bottom-1 text-sm ${
isOverLimit
? 'text-red-500 font-bold'
: isNearLimit
? 'text-yellow-600'
: 'text-gray-500'
}`}
>
{charCount}/2000
</span>
</div>
</div>
<div className="flex gap-2">
<label
htmlFor="attachment"
className="flex items-center justify-center hover:cursor-pointer p-1 rounded-full hover:bg-gray-800"
>
<Paperclip />
</label>
<input
name="attachment"
id="attachment"
type="file"
accept="*/*"
onChange={handleFileChange}
disabled={isUploading}
ref={fileInputRef}
className="hidden"
/>
{isUploading && (
<span className="text-gray-500 text-sm">Uploading...</span>
)}
<button
className="text-black bg-green-500 hover:bg-green-400 font-bold py-2 px-4 rounded w-24 shrink-0 disabled:opacity-50 disabled:cursor-not-allowed"
type="submit"
disabled={isOverLimit || isUploading}
>
Send
</button>
</div>
</div>
<div className="flex gap-2">
<label
htmlFor="attachment"
className="flex items-center justify-center hover:cursor-pointer p-1 rounded-full hover:bg-gray-800"
>
<Paperclip size={24} />
</label>
<input
name="attachment"
id="attachment"
type="file"
accept="*/*"
onChange={handleFileChange}
disabled={isUploading}
ref={fileInputRef}
className="hidden"
/>
{isUploading && (
<span className="text-gray-500 text-sm">Uploading...</span>
)}
<button
className="text-black bg-green-500 hover:bg-green-400 font-bold py-2 px-4 rounded w-24 shrink-0 disabled:opacity-50 disabled:cursor-not-allowed"
type="submit"
disabled={isOverLimit || isUploading}
>
Send
</button>
</div>
</div>
</form>