added shift + enter for new line in MessageForm.tsx, and display message length

This commit is contained in:
slawk0
2024-11-16 23:39:50 +01:00
parent 7663f5da8f
commit a118ad38f4
2 changed files with 85 additions and 98 deletions

View File

@@ -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;

View File

@@ -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