mirror of
https://github.com/usatiuk/y.git
synced 2025-10-28 10:37:47 +01:00
editing messages
This commit is contained in:
@@ -6,6 +6,7 @@ import "./Chat.scss";
|
||||
import "./PostForm.scss";
|
||||
import { Message } from "./Message";
|
||||
import { useEffect } from "react";
|
||||
import { getTokenUserUuid } from "./api/utils";
|
||||
|
||||
export function Chat() {
|
||||
const loaderData = useLoaderData() as LoaderToType<typeof chatLoader>;
|
||||
@@ -51,7 +52,12 @@ export function Chat() {
|
||||
</fetcher.Form>
|
||||
<div className={"messages"}>
|
||||
{sortedMessages.map((m) => (
|
||||
<Message key={m.id} message={m} chat={chat} />
|
||||
<Message
|
||||
key={m.id}
|
||||
message={m}
|
||||
chat={chat}
|
||||
actions={m.authorUuid == getTokenUserUuid()}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
&.messageEditing {
|
||||
padding: 0;
|
||||
min-height: 6rem;
|
||||
min-height: 3rem;
|
||||
border: 1px solid #D0D0D0;
|
||||
|
||||
@include post-editor;
|
||||
|
||||
@@ -1,14 +1,53 @@
|
||||
import "./Message.scss";
|
||||
import { TChatTo, TMessageTo } from "./api/dto";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Form, Link, useNavigation, useSubmit } from "react-router-dom";
|
||||
import { useState } from "react";
|
||||
|
||||
export function Message({
|
||||
message,
|
||||
chat,
|
||||
actions,
|
||||
}: {
|
||||
message: TMessageTo;
|
||||
chat: TChatTo;
|
||||
actions: boolean;
|
||||
}) {
|
||||
const [editing, setEditing] = useState(false);
|
||||
const submit = useSubmit();
|
||||
const navigation = useNavigation();
|
||||
const busy = navigation.state === "submitting";
|
||||
|
||||
if (editing) {
|
||||
return (
|
||||
<div className={"message messageEditing"}>
|
||||
<Form className={"postForm"} method="patch">
|
||||
<input
|
||||
hidden={true}
|
||||
name={"messageId"}
|
||||
value={message.id}
|
||||
/>
|
||||
<textarea
|
||||
placeholder={"Write something!"}
|
||||
name="text"
|
||||
defaultValue={message.contents}
|
||||
/>
|
||||
<button
|
||||
name="intent"
|
||||
value="updateMessage"
|
||||
type="submit"
|
||||
onClick={(e) => {
|
||||
setEditing(false);
|
||||
submit(e.currentTarget);
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"message"}>
|
||||
<span className={"text"}>{message.contents}</span>
|
||||
@@ -24,26 +63,26 @@ export function Message({
|
||||
by {message.authorUsername}
|
||||
</Link>
|
||||
</div>
|
||||
{/*{actions && (*/}
|
||||
{/* <div className={"actions"}>*/}
|
||||
{/* {<button onClick={() => setEditing(true)}>edit</button>}*/}
|
||||
{/* <Form method={"delete"}>*/}
|
||||
{/* <input*/}
|
||||
{/* hidden={true}*/}
|
||||
{/* name={"postToDeleteId"}*/}
|
||||
{/* value={id}*/}
|
||||
{/* />*/}
|
||||
{/* <button*/}
|
||||
{/* name="intent"*/}
|
||||
{/* value="deletePost"*/}
|
||||
{/* type={"submit"}*/}
|
||||
{/* disabled={busy}*/}
|
||||
{/* >*/}
|
||||
{/* delete*/}
|
||||
{/* </button>*/}
|
||||
{/* </Form>*/}
|
||||
{/* </div>*/}
|
||||
{/*)}*/}
|
||||
{actions && (
|
||||
<div className={"actions"}>
|
||||
{<button onClick={() => setEditing(true)}>edit</button>}
|
||||
<Form method={"delete"}>
|
||||
<input
|
||||
hidden={true}
|
||||
name={"messageToDeleteId"}
|
||||
value={message.id}
|
||||
/>
|
||||
<button
|
||||
name="intent"
|
||||
value="deleteMessage"
|
||||
type={"submit"}
|
||||
disabled={busy}
|
||||
>
|
||||
delete
|
||||
</button>
|
||||
</Form>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -11,7 +11,7 @@ import { isError } from "./api/dto";
|
||||
import { deleteToken, getTokenUserUuid, setToken } from "./api/utils";
|
||||
import { createPost, deletePost, updatePost } from "./api/Post";
|
||||
import { createChat } from "./api/Chat";
|
||||
import { addMessagesToChat } from "./api/Message";
|
||||
import { addMessagesToChat, deleteMessage, editMessage } from "./api/Message";
|
||||
|
||||
export type ActionToType<T extends (...args: any) => any> =
|
||||
| Exclude<Awaited<ReturnType<T>>, Response>
|
||||
@@ -117,8 +117,20 @@ export async function newChatAction({ request }: ActionFunctionArgs) {
|
||||
|
||||
export async function chatAction({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
return await addMessagesToChat(
|
||||
Number(formData.get("chatId")!.toString()),
|
||||
formData.get("text")!.toString(),
|
||||
);
|
||||
const intent = formData.get("intent")!.toString();
|
||||
if (intent == "addMessage") {
|
||||
return await addMessagesToChat(
|
||||
Number(formData.get("chatId")!.toString()),
|
||||
formData.get("text")!.toString(),
|
||||
);
|
||||
} else if (intent == "deleteMessage") {
|
||||
return await deleteMessage(
|
||||
Number(formData.get("messageToDeleteId")!.toString()),
|
||||
);
|
||||
} else if (intent == "updateMessage") {
|
||||
return await editMessage(
|
||||
Number(formData.get("messageId")!.toString()),
|
||||
formData.get("text")!.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import {
|
||||
MessagesToResp,
|
||||
MessageToResp,
|
||||
NoContentToResp,
|
||||
TMessagesToResp,
|
||||
TMessageToResp,
|
||||
TNoContentToResp,
|
||||
} from "./dto";
|
||||
import { fetchJSONAuth } from "./utils";
|
||||
|
||||
@@ -20,3 +22,27 @@ export async function addMessagesToChat(
|
||||
contents: messageContents,
|
||||
});
|
||||
}
|
||||
|
||||
export async function editMessage(
|
||||
messageId: number,
|
||||
messageContents: string,
|
||||
): Promise<TMessageToResp> {
|
||||
return fetchJSONAuth(
|
||||
"/message/by-id/" + messageId,
|
||||
"PATCH",
|
||||
MessageToResp,
|
||||
{
|
||||
contents: messageContents,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteMessage(
|
||||
messageId: number,
|
||||
): Promise<TNoContentToResp> {
|
||||
return fetchJSONAuth(
|
||||
"/message/by-id/" + messageId,
|
||||
"DELETE",
|
||||
NoContentToResp,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@RestController
|
||||
@@ -52,4 +53,26 @@ public class MessageController {
|
||||
messageService.create(message);
|
||||
return messageMapper.makeDto(message);
|
||||
}
|
||||
|
||||
@PatchMapping(path = "/by-id/{id}")
|
||||
public MessageTo update(Principal principal, @PathVariable long id, @RequestBody MessageCreateTo messageCreateTo) {
|
||||
var message = messageService.readById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
|
||||
if (!Objects.equals(message.getAuthor().getUuid(), principal.getName()))
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
||||
message.setContents(messageCreateTo.contents());
|
||||
messageService.update(message);
|
||||
return messageMapper.makeDto(message);
|
||||
}
|
||||
|
||||
@DeleteMapping(path = "/by-id/{id}")
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
public void delete(Principal principal, @PathVariable long id) {
|
||||
var read = messageService.readById(id);
|
||||
if (read.isEmpty()) return;
|
||||
if (!Objects.equals(read.get().getAuthor().getId(), principal.getName())) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
messageService.deleteById(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user