added shift + enter for new line in MessageForm.tsx, and display message length
This commit is contained in:
@@ -1,78 +1,116 @@
|
||||
import { sendMessage } from '../../socket/socket.tsx';
|
||||
import { useRef, useEffect, useCallback } from 'react';
|
||||
import { useForm, SubmitHandler } from 'react-hook-form';
|
||||
import type { KeyboardEventHandler } from 'react';
|
||||
import { sendMessage } from '../../socket/socket.tsx';
|
||||
|
||||
type Input = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
type MessaFormProps = {
|
||||
type MessageFormProps = {
|
||||
contact: string;
|
||||
};
|
||||
|
||||
function MessageForm({ contact }: MessaFormProps) {
|
||||
const MessageForm = ({ contact }: MessageFormProps) => {
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { errors },
|
||||
} = useForm<Input>();
|
||||
watch,
|
||||
formState: {},
|
||||
} = useForm<Input>({ mode: 'onChange' });
|
||||
|
||||
const message = watch('message', '');
|
||||
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
|
||||
// Function to adjust textarea height
|
||||
const adjustHeight = useCallback(() => {
|
||||
const textarea = textareaRef.current;
|
||||
if (textarea) {
|
||||
textarea.style.height = 'auto';
|
||||
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Adjust height on content change
|
||||
useEffect(() => {
|
||||
adjustHeight();
|
||||
}, [message, adjustHeight]);
|
||||
|
||||
// Sending message
|
||||
const submitMessage: SubmitHandler<Input> = (data) => {
|
||||
console.log(contact);
|
||||
|
||||
// Block sending empty message
|
||||
if (!data.message) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendMessage(data.message, contact);
|
||||
// Assuming sendMessage is imported
|
||||
sendMessage(data.message.trim(), contact);
|
||||
reset({ message: '' });
|
||||
};
|
||||
|
||||
const adjustSize = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const textarea = event.target;
|
||||
|
||||
// Adjust height
|
||||
textarea.style.height = 'auto';
|
||||
const maxHeight = 500;
|
||||
|
||||
if (textarea.scrollHeight > maxHeight) {
|
||||
textarea.style.height = `${maxHeight}px`;
|
||||
textarea.style.overflowY = 'auto';
|
||||
} else {
|
||||
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||
textarea.style.overflowY = 'hidden';
|
||||
// Handle Enter and Ctrl+Enter
|
||||
const handleKeyPress: KeyboardEventHandler<HTMLTextAreaElement> = (e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
handleSubmit(submitMessage)();
|
||||
}
|
||||
};
|
||||
|
||||
const { ref, ...messageRegister } = register('message', {
|
||||
maxLength: {
|
||||
value: 2000,
|
||||
message: 'Maximum length exceeded',
|
||||
},
|
||||
minLength: 1,
|
||||
});
|
||||
|
||||
const charCount = message.length;
|
||||
const isNearLimit = charCount > 1900;
|
||||
const isOverLimit = charCount > 2000;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(submitMessage)}>
|
||||
<div className="flex items-end">
|
||||
<textarea
|
||||
className="resize-none overflow-y-hidden bg-green-50 text-black rounded-md w-full ml-1 mr-1 size-10"
|
||||
autoFocus={!!contact}
|
||||
disabled={!contact}
|
||||
placeholder="Enter message"
|
||||
onInput={adjustSize}
|
||||
rows={1}
|
||||
{...register('message', {
|
||||
maxLength: 2000,
|
||||
minLength: 1,
|
||||
})}
|
||||
/>
|
||||
{errors?.message?.type === 'maxLength' && (
|
||||
<p>Maximum length of the message is 2000</p>
|
||||
)}
|
||||
<button
|
||||
className="text-black bg-green-500 hover:bg-green-400 font-bold py-2 px-4 rounded mr-1 w-24"
|
||||
type="submit"
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
<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'
|
||||
}`}
|
||||
>
|
||||
{charCount}/2000
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<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}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default MessageForm;
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# Comments are provided throughout this file to help you get started.
|
||||
# If you need more help, visit the Docker Compose reference guide at
|
||||
# https://docs.docker.com/go/compose-spec-reference/
|
||||
|
||||
# Here the instructions define your application as a service called "server".
|
||||
# This service is built from the Dockerfile in the current directory.
|
||||
# You can add other services your application may depend on here, such as a
|
||||
# database or a cache. For examples, see the Awesome Compose repository:
|
||||
# https://github.com/docker/awesome-compose
|
||||
services:
|
||||
server:
|
||||
build:
|
||||
context: .
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
ports:
|
||||
- 3000:3000
|
||||
|
||||
# The commented out section below is an example of how to define a PostgreSQL
|
||||
# database that your application can use. `depends_on` tells Docker Compose to
|
||||
# start the database before your application. The `db-data` volume persists the
|
||||
# database data between container restarts. The `db-password` secret is used
|
||||
# to set the database password. You must create `db/password.txt` and add
|
||||
# a password of your choosing to it before running `docker-compose up`.
|
||||
# depends_on:
|
||||
# db:
|
||||
# condition: service_healthy
|
||||
# db:
|
||||
# image: postgres
|
||||
# restart: always
|
||||
# user: postgres
|
||||
# secrets:
|
||||
# - db-password
|
||||
# volumes:
|
||||
# - db-data:/var/lib/postgresql/data
|
||||
# environment:
|
||||
# - POSTGRES_DB=example
|
||||
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
|
||||
# expose:
|
||||
# - 5432
|
||||
# healthcheck:
|
||||
# test: [ "CMD", "pg_isready" ]
|
||||
# interval: 10s
|
||||
# timeout: 5s
|
||||
# retries: 5
|
||||
# volumes:
|
||||
# db-data:
|
||||
# secrets:
|
||||
# db-password:
|
||||
# file: db/password.txt
|
||||
|
||||
Reference in New Issue
Block a user