chore: better Prettier config for easier reviews
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import useTranslation from "next-translate/useTranslation"
|
||||
import TextareaAutosize from "react-textarea-autosize"
|
||||
|
||||
import type { MessageProps } from '../Message'
|
||||
import type { MessageProps } from "../Message"
|
||||
|
||||
export interface EditMessageProps extends MessageProps {
|
||||
handleEdit: () => Promise<void>
|
||||
@ -15,7 +15,7 @@ export const EditMessage: React.FC<
|
||||
const { t } = useTranslation()
|
||||
|
||||
const handleEditSubmit: React.FormEventHandler<HTMLFormElement> = async (
|
||||
event
|
||||
event,
|
||||
) => {
|
||||
event.preventDefault()
|
||||
await handleEdit()
|
||||
@ -23,23 +23,23 @@ export const EditMessage: React.FC<
|
||||
|
||||
return (
|
||||
<form
|
||||
className='flex h-full w-full items-center'
|
||||
className="flex h-full w-full items-center"
|
||||
onSubmit={handleEditSubmit}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<TextareaAutosize
|
||||
className='scrollbar-firefox-support w-full resize-none bg-transparent p-2 tracking-wide outline-none'
|
||||
placeholder={t('application:write-a-message')}
|
||||
wrap='soft'
|
||||
className="scrollbar-firefox-support w-full resize-none bg-transparent p-2 tracking-wide outline-none"
|
||||
placeholder={t("application:write-a-message")}
|
||||
wrap="soft"
|
||||
maxRows={6}
|
||||
name='message'
|
||||
name="message"
|
||||
defaultValue={message.value}
|
||||
ref={textareaRef}
|
||||
autoFocus
|
||||
onFocus={(event) => {
|
||||
event.currentTarget.setSelectionRange(
|
||||
event.currentTarget.value.length,
|
||||
event.currentTarget.value.length
|
||||
event.currentTarget.value.length,
|
||||
)
|
||||
}}
|
||||
/>
|
||||
|
@ -1 +1 @@
|
||||
export * from './EditMessage'
|
||||
export * from "./EditMessage"
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { useState, useRef } from 'react'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import date from 'date-and-time'
|
||||
import { useState, useRef } from "react"
|
||||
import Image from "next/image"
|
||||
import Link from "next/link"
|
||||
import date from "date-and-time"
|
||||
|
||||
import type { MessageWithMember } from '../../../../models/Message'
|
||||
import { MessageText } from './MessageText'
|
||||
import { Loader } from '../../../design/Loader'
|
||||
import { MessageFile } from './MessageFile'
|
||||
import { useAuthentication } from '../../../../tools/authentication'
|
||||
import { MessageOptions } from './MessageOptions'
|
||||
import { EditMessage } from './EditMessage'
|
||||
import type { MessageWithMember } from "../../../../models/Message"
|
||||
import { MessageText } from "./MessageText"
|
||||
import { Loader } from "../../../design/Loader"
|
||||
import { MessageFile } from "./MessageFile"
|
||||
import { useAuthentication } from "../../../../tools/authentication"
|
||||
import { MessageOptions } from "./MessageOptions"
|
||||
import { EditMessage } from "./EditMessage"
|
||||
|
||||
export interface MessageProps {
|
||||
message: MessageWithMember
|
||||
@ -23,12 +23,12 @@ export const Message: React.FC<MessageProps> = (props) => {
|
||||
const { authentication, user } = useAuthentication()
|
||||
|
||||
const handleTextareaKeyDown: React.KeyboardEventHandler<HTMLFormElement> = (
|
||||
event
|
||||
event,
|
||||
) => {
|
||||
if (event.key === 'Enter' && !event.shiftKey) {
|
||||
if (event.key === "Enter" && !event.shiftKey) {
|
||||
event.preventDefault()
|
||||
event.currentTarget.dispatchEvent(
|
||||
new Event('submit', { cancelable: true, bubbles: true })
|
||||
new Event("submit", { cancelable: true, bubbles: true }),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -36,13 +36,13 @@ export const Message: React.FC<MessageProps> = (props) => {
|
||||
const handleEdit = async (): Promise<void> => {
|
||||
const newMessage = textareaReference.current?.value ?? message.value
|
||||
if (
|
||||
typeof newMessage === 'string' &&
|
||||
typeof newMessage === "string" &&
|
||||
newMessage.length > 0 &&
|
||||
newMessage !== message.value
|
||||
) {
|
||||
try {
|
||||
await authentication.api.put(`/messages/${message.id}`, {
|
||||
value: newMessage
|
||||
value: newMessage,
|
||||
})
|
||||
} catch {}
|
||||
}
|
||||
@ -58,17 +58,17 @@ export const Message: React.FC<MessageProps> = (props) => {
|
||||
return (
|
||||
<div
|
||||
data-cy={`message-${message.id}`}
|
||||
className='group flex w-full p-4 transition hover:bg-gray-200 dark:hover:bg-gray-900'
|
||||
className="group flex w-full p-4 transition hover:bg-gray-200 dark:hover:bg-gray-900"
|
||||
>
|
||||
<Link href={`/application/users/${message.member.user.id}`}>
|
||||
<div className='mr-4 flex h-12 w-12 flex-shrink-0 items-center justify-center'>
|
||||
<div className='h-10 w-10 drop-shadow-md'>
|
||||
<div className="mr-4 flex h-12 w-12 flex-shrink-0 items-center justify-center">
|
||||
<div className="h-10 w-10 drop-shadow-md">
|
||||
<Image
|
||||
quality={100}
|
||||
className='rounded-full'
|
||||
className="rounded-full"
|
||||
src={
|
||||
message.member.user.logo == null
|
||||
? '/images/data/user-default.png'
|
||||
? "/images/data/user-default.png"
|
||||
: message.member.user.logo
|
||||
}
|
||||
alt={"Users's profil picture"}
|
||||
@ -79,33 +79,33 @@ export const Message: React.FC<MessageProps> = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<div className='relative w-full whitespace-pre-wrap break-words break-all'>
|
||||
<div className='flex w-max items-center'>
|
||||
<div className="relative w-full whitespace-pre-wrap break-words break-all">
|
||||
<div className="flex w-max items-center">
|
||||
<Link href={`/application/users/${message.member.user.id}`}>
|
||||
<span
|
||||
data-cy='message-member-user-name'
|
||||
className='font-bold text-gray-900 dark:text-gray-200'
|
||||
data-cy="message-member-user-name"
|
||||
className="font-bold text-gray-900 dark:text-gray-200"
|
||||
>
|
||||
{message.member.user.name}
|
||||
</span>
|
||||
</Link>
|
||||
<span
|
||||
data-cy='message-date'
|
||||
className='ml-4 select-none text-xs text-gray-500 dark:text-gray-200'
|
||||
data-cy="message-date"
|
||||
className="ml-4 select-none text-xs text-gray-500 dark:text-gray-200"
|
||||
>
|
||||
{date.format(new Date(message.createdAt), 'DD/MM/YYYY - HH:mm:ss')}
|
||||
{date.format(new Date(message.createdAt), "DD/MM/YYYY - HH:mm:ss")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{message.member.userId === user.id && (
|
||||
<MessageOptions
|
||||
message={message}
|
||||
editMode={isEditing ? ':white_check_mark:' : ':pencil2:'}
|
||||
editMode={isEditing ? ":white_check_mark:" : ":pencil2:"}
|
||||
handleEdit={isEditing ? handleEdit : handleEditMode}
|
||||
/>
|
||||
)}
|
||||
|
||||
{message.type === 'text' ? (
|
||||
{message.type === "text" ? (
|
||||
<>
|
||||
{isEditing ? (
|
||||
<EditMessage
|
||||
@ -118,7 +118,7 @@ export const Message: React.FC<MessageProps> = (props) => {
|
||||
<MessageText message={message} />
|
||||
)}
|
||||
</>
|
||||
) : message.type === 'file' ? (
|
||||
) : message.type === "file" ? (
|
||||
<MessageFile message={message} />
|
||||
) : (
|
||||
<Loader />
|
||||
|
@ -1,14 +1,14 @@
|
||||
export const FileIcon: React.FC = () => {
|
||||
return (
|
||||
<svg
|
||||
className='fill-current text-black dark:text-white'
|
||||
width='21'
|
||||
height='26'
|
||||
viewBox='0 0 21 26'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
className="fill-current text-black dark:text-white"
|
||||
width="21"
|
||||
height="26"
|
||||
viewBox="0 0 21 26"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d='M2.625 0C1.92881 0 1.26113 0.273928 0.768845 0.761522C0.276562 1.24912 0 1.91044 0 2.6V23.4C0 24.0896 0.276562 24.7509 0.768845 25.2385C1.26113 25.7261 1.92881 26 2.625 26H18.375C19.0712 26 19.7389 25.7261 20.2312 25.2385C20.7234 24.7509 21 24.0896 21 23.4V7.8L13.125 0H2.625ZM13.125 9.1H11.8125V2.6L18.375 9.1H13.125Z' />
|
||||
<path d="M2.625 0C1.92881 0 1.26113 0.273928 0.768845 0.761522C0.276562 1.24912 0 1.91044 0 2.6V23.4C0 24.0896 0.276562 24.7509 0.768845 25.2385C1.26113 25.7261 1.92881 26 2.625 26H18.375C19.0712 26 19.7389 25.7261 20.2312 25.2385C20.7234 24.7509 21 24.0896 21 23.4V7.8L13.125 0H2.625ZM13.125 9.1H11.8125V2.6L18.375 9.1H13.125Z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import axios from 'axios'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { DownloadIcon } from '@heroicons/react/solid'
|
||||
import { useState, useEffect } from "react"
|
||||
import axios from "axios"
|
||||
import prettyBytes from "pretty-bytes"
|
||||
import { DownloadIcon } from "@heroicons/react/solid"
|
||||
|
||||
import type { MessageWithMember } from '../../../../../models/Message'
|
||||
import { Loader } from '../../../../design/Loader'
|
||||
import { FileIcon } from './FileIcon'
|
||||
import { api } from '../../../../../tools/api'
|
||||
import type { MessageWithMember } from "../../../../../models/Message"
|
||||
import { Loader } from "../../../../design/Loader"
|
||||
import { FileIcon } from "./FileIcon"
|
||||
import { api } from "../../../../../tools/api"
|
||||
|
||||
const supportedImageMimetype = [
|
||||
'image/png',
|
||||
'image/jpg',
|
||||
'image/jpeg',
|
||||
'image/gif'
|
||||
"image/png",
|
||||
"image/jpg",
|
||||
"image/jpeg",
|
||||
"image/gif",
|
||||
]
|
||||
|
||||
export interface FileData {
|
||||
@ -34,8 +34,8 @@ export const MessageFile: React.FC<MessageContentProps> = (props) => {
|
||||
|
||||
const fetchData = async (): Promise<void> => {
|
||||
const { data } = await api.get(message.value, {
|
||||
responseType: 'blob',
|
||||
cancelToken: ourRequest.token
|
||||
responseType: "blob",
|
||||
cancelToken: ourRequest.token,
|
||||
})
|
||||
const fileURL = URL.createObjectURL(data)
|
||||
setFile({ blob: data, url: fileURL })
|
||||
@ -52,27 +52,27 @@ export const MessageFile: React.FC<MessageContentProps> = (props) => {
|
||||
}
|
||||
if (supportedImageMimetype.includes(message.mimetype)) {
|
||||
return (
|
||||
<a href={file.url} target='_blank' rel='noreferrer'>
|
||||
<a href={file.url} target="_blank" rel="noreferrer">
|
||||
<img
|
||||
data-cy={`message-file-image-${message.id}`}
|
||||
className='max-h-80 sm:max-w-xs'
|
||||
className="max-h-80 sm:max-w-xs"
|
||||
src={file.url}
|
||||
alt={message.value}
|
||||
/>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
if (message.mimetype.startsWith('audio/')) {
|
||||
if (message.mimetype.startsWith("audio/")) {
|
||||
return (
|
||||
<audio controls data-cy={`message-file-audio-${message.id}`}>
|
||||
<source src={file.url} type={message.mimetype} />
|
||||
</audio>
|
||||
)
|
||||
}
|
||||
if (message.mimetype.startsWith('video/')) {
|
||||
if (message.mimetype.startsWith("video/")) {
|
||||
return (
|
||||
<video
|
||||
className='max-h-80 max-w-xs'
|
||||
className="max-h-80 max-w-xs"
|
||||
controls
|
||||
data-cy={`message-file-video-${message.id}`}
|
||||
>
|
||||
@ -82,17 +82,17 @@ export const MessageFile: React.FC<MessageContentProps> = (props) => {
|
||||
}
|
||||
return (
|
||||
<a href={file.url} download data-cy={`message-file-download-${message.id}`}>
|
||||
<div className='flex items-center'>
|
||||
<div className='flex items-center'>
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center">
|
||||
<div>
|
||||
<FileIcon />
|
||||
</div>
|
||||
<div className='ml-4'>
|
||||
<div className="ml-4">
|
||||
<p>{file.blob.type}</p>
|
||||
<p className='mt-1'>{prettyBytes(file.blob.size)}</p>
|
||||
<p className="mt-1">{prettyBytes(file.blob.size)}</p>
|
||||
</div>
|
||||
</div>
|
||||
<DownloadIcon className='ml-4 h-8 w-8' />
|
||||
<DownloadIcon className="ml-4 h-8 w-8" />
|
||||
</div>
|
||||
</a>
|
||||
)
|
||||
|
@ -1 +1 @@
|
||||
export * from './MessageFile'
|
||||
export * from "./MessageFile"
|
||||
|
@ -1,12 +1,12 @@
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
import useTranslation from "next-translate/useTranslation"
|
||||
|
||||
import { useAuthentication } from '../../../../../tools/authentication'
|
||||
import { Emoji } from '../../../../Emoji'
|
||||
import type { MessageProps } from '../Message'
|
||||
import { useAuthentication } from "../../../../../tools/authentication"
|
||||
import { Emoji } from "../../../../Emoji"
|
||||
import type { MessageProps } from "../Message"
|
||||
|
||||
interface MessageOptionsProps extends MessageProps {
|
||||
handleEdit: () => void
|
||||
editMode: ':white_check_mark:' | ':pencil2:'
|
||||
editMode: ":white_check_mark:" | ":pencil2:"
|
||||
}
|
||||
|
||||
export const MessageOptions: React.FC<
|
||||
@ -22,22 +22,22 @@ export const MessageOptions: React.FC<
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='absolute -top-8 right-6 flex opacity-0 transition-opacity group-hover:opacity-100'>
|
||||
{message.type === 'text' && (
|
||||
<div className="absolute -top-8 right-6 flex opacity-0 transition-opacity group-hover:opacity-100">
|
||||
{message.type === "text" && (
|
||||
<div
|
||||
className='message-options rounded-l-lg border-l-slate-600'
|
||||
title={t('application:edit')}
|
||||
className="message-options rounded-l-lg border-l-slate-600"
|
||||
title={t("application:edit")}
|
||||
onClick={handleEdit}
|
||||
>
|
||||
<Emoji value={editMode} size={18} />
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className='message-options rounded-r-lg border-r-slate-600'
|
||||
title={t('application:delete')}
|
||||
className="message-options rounded-r-lg border-r-slate-600"
|
||||
title={t("application:delete")}
|
||||
onClick={handleDeleteMessage}
|
||||
>
|
||||
<Emoji value=':wastebasket:' size={18} />
|
||||
<Emoji value=":wastebasket:" size={18} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -1 +1 @@
|
||||
export * from './MessageOptions'
|
||||
export * from "./MessageOptions"
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { useMemo } from 'react'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import gfm from 'remark-gfm'
|
||||
import remarkBreaks from 'remark-breaks'
|
||||
import remarkMath from 'remark-math'
|
||||
import rehypeKatex from 'rehype-katex'
|
||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
|
||||
import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'
|
||||
import { useMemo } from "react"
|
||||
import ReactMarkdown from "react-markdown"
|
||||
import gfm from "remark-gfm"
|
||||
import remarkBreaks from "remark-breaks"
|
||||
import remarkMath from "remark-math"
|
||||
import rehypeKatex from "rehype-katex"
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
|
||||
import { vscDarkPlus } from "react-syntax-highlighter/dist/cjs/styles/prism"
|
||||
|
||||
import 'katex/dist/katex.min.css'
|
||||
import "katex/dist/katex.min.css"
|
||||
|
||||
import { Emoji, emojiPlugin, isStringWithOnlyOneEmoji } from '../../../../Emoji'
|
||||
import type { MessageWithMember } from '../../../../../models/Message'
|
||||
import { Emoji, emojiPlugin, isStringWithOnlyOneEmoji } from "../../../../Emoji"
|
||||
import type { MessageWithMember } from "../../../../../models/Message"
|
||||
|
||||
export interface MessageContentProps {
|
||||
message: MessageWithMember
|
||||
@ -35,16 +35,16 @@ export const MessageText: React.FC<MessageContentProps> = (props) => {
|
||||
|
||||
return (
|
||||
<ReactMarkdown
|
||||
disallowedElements={['table']}
|
||||
disallowedElements={["table"]}
|
||||
unwrapDisallowed
|
||||
remarkPlugins={[[gfm], [remarkBreaks], [remarkMath]]}
|
||||
rehypePlugins={[[emojiPlugin], [rehypeKatex]]}
|
||||
linkTarget='_blank'
|
||||
linkTarget="_blank"
|
||||
components={{
|
||||
a: (props) => {
|
||||
return (
|
||||
<a
|
||||
className='text-green-800 hover:underline dark:text-green-400'
|
||||
className="text-green-800 hover:underline dark:text-green-400"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
@ -55,22 +55,22 @@ export const MessageText: React.FC<MessageContentProps> = (props) => {
|
||||
},
|
||||
code: (properties) => {
|
||||
const { inline, className, children, ...props } = properties
|
||||
const match = /language-(\w+)/.exec(className ?? '')
|
||||
const match = /language-(\w+)/.exec(className ?? "")
|
||||
return !(inline as boolean) && match != null ? (
|
||||
<SyntaxHighlighter
|
||||
style={vscDarkPlus as any}
|
||||
language={match[1]}
|
||||
PreTag='div'
|
||||
PreTag="div"
|
||||
{...props}
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
{String(children).replace(/\n$/, "")}
|
||||
</SyntaxHighlighter>
|
||||
) : (
|
||||
<code className={className} {...props}>
|
||||
{children}
|
||||
</code>
|
||||
)
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{message.value}
|
||||
|
@ -1 +1 @@
|
||||
export * from './MessageText'
|
||||
export * from "./MessageText"
|
||||
|
@ -1 +1 @@
|
||||
export * from './Message'
|
||||
export * from "./Message"
|
||||
|
Reference in New Issue
Block a user