From 390edb38bdc55f84a93076eabcdf67692591d568 Mon Sep 17 00:00:00 2001 From: valentinkolb Date: Tue, 11 Jun 2024 23:38:40 +0200 Subject: [PATCH] feat(chat): added new chat feature you can now enable chat rooms for eventLists --- config.ts | 2 +- src/components/layout/index.tsx | 2 - .../modals/ShowMessagesModal/Message.tsx | 26 ---- .../modals/ShowMessagesModal/index.module.css | 5 - .../users/modals/ShowMessagesModal/index.tsx | 109 -------------- src/models/EventTypes.ts | 1 + src/models/MessageTypes.ts | 23 +-- src/models/index.ts | 4 +- src/pages/chat/ChatRouter.tsx | 10 +- ...e.css => EventListMessagesList.module.css} | 6 +- src/pages/chat/EventListMessagesList.tsx | 107 +++++++++++++ ...module.css => ListMessagesView.module.css} | 0 src/pages/chat/ListMessagesView.tsx | 92 ++++++++++++ src/pages/chat/MessageThreadView.tsx | 134 ----------------- src/pages/chat/MessageThreadsList.tsx | 140 ------------------ src/pages/chat/components/Announcement.tsx | 1 - src/pages/chat/components/Announcements.tsx | 3 +- src/pages/chat/components/ChatNavIcon.tsx | 32 ++-- src/pages/chat/components/Messages.tsx | 17 +-- .../chat/components/UpsertThreadForm.tsx | 76 ---------- src/pages/events/EventOverview/index.page.tsx | 2 +- src/pages/events/StatusEditor/EntrySearch.tsx | 10 +- .../events/StatusEditor/StatusEditor.tsx | 2 +- .../events/e/:eventId/EditEventRouter.tsx | 2 +- .../EventLists/:listId/EventListRouter.tsx | 13 +- .../:listId/ListSettings/ListSettings.tsx | 15 +- .../EventLists/EventListsOverview.tsx | 74 ++++----- src/pages/events/entries/UserEntries.tsx | 2 +- src/pages/events/s/EventListView.tsx | 2 +- src/pages/events/s/EventView.tsx | 2 +- src/style/global.css | 4 +- 31 files changed, 320 insertions(+), 598 deletions(-) delete mode 100644 src/components/users/modals/ShowMessagesModal/Message.tsx delete mode 100644 src/components/users/modals/ShowMessagesModal/index.module.css delete mode 100644 src/components/users/modals/ShowMessagesModal/index.tsx rename src/pages/chat/{MessageThreadsList.module.css => EventListMessagesList.module.css} (95%) create mode 100644 src/pages/chat/EventListMessagesList.tsx rename src/pages/chat/{MessageThreadView.module.css => ListMessagesView.module.css} (100%) create mode 100644 src/pages/chat/ListMessagesView.tsx delete mode 100644 src/pages/chat/MessageThreadView.tsx delete mode 100644 src/pages/chat/MessageThreadsList.tsx delete mode 100644 src/pages/chat/components/UpsertThreadForm.tsx diff --git a/config.ts b/config.ts index 7048e55..9388bf8 100644 --- a/config.ts +++ b/config.ts @@ -9,5 +9,5 @@ export const PB_STORAGE_KEY = "stuve-it-login-record" // general export const APP_NAME = "StuVe IT" -export const APP_VERSION = "0.8.11 (beta)" +export const APP_VERSION = "0.9.0 (beta)" export const APP_URL = "https://it.stuve.uni-ulm.de" \ No newline at end of file diff --git a/src/components/layout/index.tsx b/src/components/layout/index.tsx index 97cdc7f..cbb1ada 100644 --- a/src/components/layout/index.tsx +++ b/src/components/layout/index.tsx @@ -9,7 +9,6 @@ import RegisterModal from "@/components/users/modals/RegisterModal.tsx"; import EmailTokenVerification from "@/components/users/modals/EmailTokenVerification.tsx"; import ForgotPasswordModal from "@/components/users/modals/ForgotPasswordModal.tsx"; import ChangeEmailModal from "@/components/users/modals/ChangeEmailModal.tsx"; -import ShowMessagesModal from "@/components/users/modals/ShowMessagesModal"; export default function Layout({hideNav}: { hideNav?: boolean }) { return
@@ -21,7 +20,6 @@ export default function Layout({hideNav}: { hideNav?: boolean }) { -
diff --git a/src/components/users/modals/ShowMessagesModal/Message.tsx b/src/components/users/modals/ShowMessagesModal/Message.tsx deleted file mode 100644 index 0e5aadd..0000000 --- a/src/components/users/modals/ShowMessagesModal/Message.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import {MessagesModel} from "@/models/MessageTypes.ts"; -import {Notification} from '@mantine/core'; -import InnerHtml from "@/components/InnerHtml"; -import {getUserName} from "@/components/users/modals/util.tsx"; - -export default function Message({message}: { message: MessagesModel }) { - - - const senderName = getUserName(message.expand?.sender) - - let title - - if (message.subject) { - title = `${senderName} - ${message.subject}` - } else { - title = senderName - } - - return <> - - - - -} \ No newline at end of file diff --git a/src/components/users/modals/ShowMessagesModal/index.module.css b/src/components/users/modals/ShowMessagesModal/index.module.css deleted file mode 100644 index fc54cc4..0000000 --- a/src/components/users/modals/ShowMessagesModal/index.module.css +++ /dev/null @@ -1,5 +0,0 @@ -.messagesContainer { - display: flex; - flex-direction: column-reverse; - gap: var(--gap); -} \ No newline at end of file diff --git a/src/components/users/modals/ShowMessagesModal/index.tsx b/src/components/users/modals/ShowMessagesModal/index.tsx deleted file mode 100644 index 8455bce..0000000 --- a/src/components/users/modals/ShowMessagesModal/index.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import {PocketBaseErrorAlert, usePB} from "@/lib/pocketbase.tsx"; -import {Button, Modal, Stack, Text, ThemeIcon} from "@mantine/core"; -import {useShowMessages} from "@/components/users/modals/hooks.ts"; -import PromptLoginModal from "@/components/users/modals/PromptLoginModal.tsx"; -import {useInfiniteQuery} from "@tanstack/react-query"; -import {IconMessageCircleOff, IconMessageCircleUp} from "@tabler/icons-react"; -import Message from "@/components/users/modals/ShowMessagesModal/Message.tsx"; -import InfiniteScroll from "react-infinite-scroll-component"; - - -export default function ShowMessagesModal() { - - const {value, handler} = useShowMessages() - const {user, pb} = usePB() - - const PER_PAGE = 1 // todo - - const { - fetchNextPage, - hasNextPage, - isFetchingNextPage, - ...query - } = useInfiniteQuery({ - queryKey: ["messages", user?.id, "infinite"], - queryFn: async ({pageParam}) => ( - await pb.collection("messages").getList(pageParam, PER_PAGE, { - filter: `recipients?~'${user?.id}'&&thread=null`, - sort: "-created", - expand: "sender" - }) - ), - initialPageParam: 1, - getNextPageParam: (lastPage) => - lastPage.page >= lastPage.totalPages ? undefined : lastPage.page + 1, - enabled: !!user - }) - - if (value && !user) { - return - } - - return <> - -
- - - { - query.data?.pages[0].totalItems === 0 && - - - - - Keine Nachrichten - - - } - - Loading...} - endMessage={ -

- Yay! You have seen it all -

- } - refreshFunction={query.refetch} - pullDownToRefresh - pullDownToRefreshThreshold={50} - pullDownToRefreshContent={ -

↓ Pull down to refresh

- } - releaseToRefreshContent={ -

↑ Release to refresh

- } - > -
- { - query.data?.pages.map(page => page?.items.map((message) => ( - - ))) - } - - -
-
-
-
- -} \ No newline at end of file diff --git a/src/models/EventTypes.ts b/src/models/EventTypes.ts index bd92884..d5ee09b 100644 --- a/src/models/EventTypes.ts +++ b/src/models/EventTypes.ts @@ -36,6 +36,7 @@ export type EventListModel = { favourite: boolean | null; allowOverlappingEntries: boolean | null; onlyStuVeAccounts: boolean | null; + enableChat: boolean | null; event: string entryQuestionSchema: FormSchema | null entryStatusSchema: FormSchema | null; diff --git a/src/models/MessageTypes.ts b/src/models/MessageTypes.ts index d28af7a..907182f 100644 --- a/src/models/MessageTypes.ts +++ b/src/models/MessageTypes.ts @@ -1,13 +1,15 @@ import {RecordModel} from "pocketbase"; import {UserModal} from "@/models/AuthTypes.ts"; +import {EventListModel} from "@/models/EventTypes.ts"; export type MessagesModel = { sender: string - recipients: string[] - thread: string | null + recipient: string | null + eventList: string | null subject: string | null content: string + comment: string | null repliedTo: string | null @@ -15,19 +17,8 @@ export type MessagesModel = { expand: { sender: UserModal - recipients: UserModal[] - thread: MessageThreadsModel | null + recipient: UserModal + eventList: EventListModel | null repliedTo: MessagesModel | null } -} & RecordModel - -export type MessageThreadsModel = { - name: string - participants: string[] - img: string | null - systemThread: boolean | null - - expand: { - participants: UserModal[] - } -} & RecordModel +} & RecordModel \ No newline at end of file diff --git a/src/models/index.ts b/src/models/index.ts index f6342e4..cf3a2e9 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -8,7 +8,7 @@ import { EventListSlotsWithEntriesCountModel, EventModel } from "./EventTypes.ts"; -import {MessagesModel, MessageThreadsModel} from "@/models/MessageTypes.ts"; +import {MessagesModel} from "@/models/MessageTypes.ts"; export type SettingsModel = { key: ['privacyPolicy', 'agb', 'stexGroup', 'stuveEventQuestions'] @@ -29,8 +29,6 @@ export interface TypedPocketBase extends PocketBase { collection(idOrName: 'messages'): RecordService - collection(idOrName: 'messageThreads'): RecordService - collection(idOrName: 'settings'): RecordService collection(idOrName: 'legalSettings'): RecordService diff --git a/src/pages/chat/ChatRouter.tsx b/src/pages/chat/ChatRouter.tsx index d9a2ba4..c2d130e 100644 --- a/src/pages/chat/ChatRouter.tsx +++ b/src/pages/chat/ChatRouter.tsx @@ -4,8 +4,8 @@ import classes from "./ChatRouter.module.css"; import ConversationSvg from "@/illustrations/conversation.svg?react"; import {useMediaQuery} from "@mantine/hooks"; -import MessageThreadsList from "@/pages/chat/MessageThreadsList.tsx"; -import MessageThreadView from "@/pages/chat/MessageThreadView.tsx"; +import EventListMessagesList from "@/pages/chat/EventListMessagesList.tsx"; +import ListMessagesView from "@/pages/chat/ListMessagesView.tsx"; import {usePB} from "@/lib/pocketbase.tsx"; import {useLogin} from "@/components/users/modals/hooks.ts"; import Announcements from "@/pages/chat/components/Announcements.tsx"; @@ -34,7 +34,7 @@ export default function ChatRouter() { {title: "Home", to: "/"}, {title: "Nachrichten", to: "/chat"}, ].map(({title, to}) => ( - + {title} ))} @@ -44,12 +44,12 @@ export default function ChatRouter() { - }/> + }/> {!isMobile && }/>} - }/> + }/> }/>
diff --git a/src/pages/chat/MessageThreadsList.module.css b/src/pages/chat/EventListMessagesList.module.css similarity index 95% rename from src/pages/chat/MessageThreadsList.module.css rename to src/pages/chat/EventListMessagesList.module.css index 8731db3..52f9ef1 100644 --- a/src/pages/chat/MessageThreadsList.module.css +++ b/src/pages/chat/EventListMessagesList.module.css @@ -14,7 +14,7 @@ background-color: var(--mantine-color-body); } -.threadText { +.listText { color: var(--mantine-color-dimmed); width: calc(100% - 40px); @@ -28,7 +28,7 @@ } } -.threadLink { +.listLink { display: flex; flex-direction: row; align-items: center; @@ -36,7 +36,7 @@ gap: var(--gap); } -.threadsContainer { +.listsContainer { //flex-grow: 1; overflow: auto; border: var(--border); diff --git a/src/pages/chat/EventListMessagesList.tsx b/src/pages/chat/EventListMessagesList.tsx new file mode 100644 index 0000000..2129b66 --- /dev/null +++ b/src/pages/chat/EventListMessagesList.tsx @@ -0,0 +1,107 @@ +import {Button, Center, Divider, Loader, Stack, Text, TextInput, ThemeIcon, UnstyledButton} from "@mantine/core"; +import {NavLink} from "react-router-dom"; +import classes from "@/pages/chat/EventListMessagesList.module.css"; +import PBAvatar from "@/components/PBAvatar.tsx"; +import {IconArrowDown, IconListSearch, IconMoodPuzzled, IconSpeakerphone} from "@tabler/icons-react"; +import {usePB} from "@/lib/pocketbase.tsx"; +import {useDebouncedState} from "@mantine/hooks"; +import {useInfiniteQuery} from "@tanstack/react-query"; +import {EventListModel} from "@/models/EventTypes.ts"; + +const ListMessagesLink = ({eventList}: { eventList: EventListModel }) => { + return + { + ({isActive}) => <> + +
+ {eventList.name} ({eventList.expand?.event.name}) +
+ + } +
+} + +const AnnouncementsLink = () => { + return <> + + { + ({isActive}) => <> + + + + + +
+ Ankündigungen +
+ + } +
+ +} + +export default function EventListMessagesList() { + const {user, pb} = usePB() + + const [eventListNameQuery, setEventListNameQuery] = useDebouncedState("", 200) + + const query = useInfiniteQuery({ + queryKey: ["eventLists", eventListNameQuery], + queryFn: async ({pageParam}) => ( + await pb.collection("eventLists").getList(pageParam, 100, { + filter: `enableChat=true&&name~'${eventListNameQuery}'`, + sort: "-messages_via_eventList.created,name", + expand: "event" + }) + ), + getNextPageParam: (lastPage) => + lastPage.page >= lastPage.totalPages ? undefined : lastPage.page + 1, + initialPageParam: 1, + enabled: !!user, + }) + + const eventLists = query.data?.pages.flatMap(t => t.items) || [] + + return
+ + + + + } + rightSection={query.isPending ? : undefined} + defaultValue={eventListNameQuery} + onChange={(e) => setEventListNameQuery(e.currentTarget.value)} + placeholder={"Nach Listen suchen..."} + /> + + {eventLists.length === 0 ? + + + + + + {eventListNameQuery ? "Keine Listen gefunden" : "Keine Listen"} + + : ( +
+ {eventLists.map(list => )} + + {query.hasNextPage && ( +
+ +
+ )} +
+ )} +
+} \ No newline at end of file diff --git a/src/pages/chat/MessageThreadView.module.css b/src/pages/chat/ListMessagesView.module.css similarity index 100% rename from src/pages/chat/MessageThreadView.module.css rename to src/pages/chat/ListMessagesView.module.css diff --git a/src/pages/chat/ListMessagesView.tsx b/src/pages/chat/ListMessagesView.tsx new file mode 100644 index 0000000..f9bf298 --- /dev/null +++ b/src/pages/chat/ListMessagesView.tsx @@ -0,0 +1,92 @@ +import {Link, useParams} from "react-router-dom"; +import {useQuery} from "@tanstack/react-query"; +import {PocketBaseErrorAlert, usePB} from "@/lib/pocketbase.tsx"; +import {ActionIcon, Button, Center, Collapse, Group, Loader, Text} from "@mantine/core"; +import PBAvatar from "@/components/PBAvatar.tsx"; +import {IconArrowRight, IconChevronLeft, IconInfoCircle, IconInfoCircleFilled} from "@tabler/icons-react"; +import {useDisclosure} from "@mantine/hooks"; +import Messages from "@/pages/chat/components/Messages.tsx"; +import classes from './ListMessagesView.module.css'; +import InnerHtml from "@/components/InnerHtml"; +import {useEventRights} from "@/pages/events/util.ts"; + +export default function ListMessagesView() { + const {listId} = useParams() as { listId: string } + + const {pb} = usePB() + + const [showListInfo, showListInfoHandler] = useDisclosure(false) + + const query = useQuery({ + queryKey: ["eventListMessageView", listId], + queryFn: async () => ( + await pb.collection("eventLists").getOne(listId, {expand: "event"}) + ) + }) + + const {canEditEvent} = useEventRights(query.data?.expand?.event) + + if (query.isError) return ( + + ) + + if (query.isLoading || !query.data) return ( +
+ +
+ ) + + const eventList = query.data + + return
+ + + + + + +
+ {eventList.name} + {eventList.expand?.event.name} +
+ + {showListInfo ? : } + +
+ + +
+ + { + (canEditEvent || eventList.expand?.event.privilegedLists.includes(eventList.id)) + && + + + + } +
+
+ + +
+} \ No newline at end of file diff --git a/src/pages/chat/MessageThreadView.tsx b/src/pages/chat/MessageThreadView.tsx deleted file mode 100644 index b1ddb76..0000000 --- a/src/pages/chat/MessageThreadView.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import {Link, useNavigate, useParams} from "react-router-dom"; -import {useMutation, useQuery} from "@tanstack/react-query"; -import {PocketBaseErrorAlert, usePB} from "@/lib/pocketbase.tsx"; -import {ActionIcon, Alert, Button, Center, Collapse, Group, Loader, Text} from "@mantine/core"; -import PBAvatar from "@/components/PBAvatar.tsx"; -import {IconChevronLeft, IconEdit, IconInfoCircle, IconTrash} from "@tabler/icons-react"; -import {useDisclosure} from "@mantine/hooks"; -import UsersDisplay from "@/components/users/UsersDisplay.tsx"; -import UpsertThreadForm from "@/pages/chat/components/UpsertThreadForm.tsx"; -import Messages from "@/pages/chat/components/Messages.tsx"; -import {useConfirmModal} from "@/components/ConfirmModal.tsx"; -import classes from './MessageThreadView.module.css'; - -export default function MessageThreadView() { - const {threadId} = useParams() as { threadId: string } - - const {pb} = usePB() - - const [showEditThread, showEditThreadHandler] = useDisclosure(false) - - const [showThreadInfo, showThreadInfoHandler] = useDisclosure(false) - - const query = useQuery({ - queryKey: ["messageThreads", threadId], - queryFn: async () => ( - await pb.collection("messageThreads").getOne(threadId, { - expand: "participants" - }) - ) - }) - - const navigate = useNavigate() - - const deleteThreadMutation = useMutation({ - mutationFn: async () => { - await pb.collection("messageThreads").delete(threadId) - }, - onSuccess: () => { - navigate("/chat") - } - }) - - const {toggleConfirmModal, ConfirmModal} = useConfirmModal({ - title: "Thread löschen", - description: "Bist du sicher, dass du diesen Thread löschen möchtest?", - onConfirm: () => deleteThreadMutation.mutate() - - }) - - if (query.isError) return ( - - ) - - if (query.isLoading || !query.data) return ( -
- -
- ) - - const thread = query.data - - return
- - - - - - - - - - {thread.name} - - - - - - - -
- { - thread.expand.participants && ( - - ) - } - {!showEditThread && - - - - - - - - } - - { - showEditThreadHandler.toggle() - query.refetch() - }} onCancel={showEditThreadHandler.toggle}/> - -
-
-
- - -
-} \ No newline at end of file diff --git a/src/pages/chat/MessageThreadsList.tsx b/src/pages/chat/MessageThreadsList.tsx deleted file mode 100644 index 25e18fe..0000000 --- a/src/pages/chat/MessageThreadsList.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import {MessageThreadsModel} from "@/models/MessageTypes.ts"; -import { - ActionIcon, - Alert, - Button, - Center, - Collapse, - Divider, - Loader, - Stack, - Text, - TextInput, - ThemeIcon, - UnstyledButton -} from "@mantine/core"; -import {NavLink} from "react-router-dom"; -import classes from "@/pages/chat/MessageThreadsList.module.css"; -import PBAvatar from "@/components/PBAvatar.tsx"; -import {IconArrowDown, IconMinus, IconNeedleThread, IconPlus, IconSpeakerphone} from "@tabler/icons-react"; -import {usePB} from "@/lib/pocketbase.tsx"; -import {useDebouncedState, useDisclosure} from "@mantine/hooks"; -import {useInfiniteQuery} from "@tanstack/react-query"; -import UpsertThreadForm from "@/pages/chat/components/UpsertThreadForm.tsx"; - -const MessageThreadLink = ({thread}: { thread: MessageThreadsModel }) => { - return - { - ({isActive}) => <> - - - -
- {thread.name} -
- - } -
-} - -const AnnouncementsLink = () => { - return <> - - { - ({isActive}) => <> - - - - - -
- Ankündigungen -
- - } -
- -} - -export default function MessageThreadsList() { - const {user, pb} = usePB() - - const [showCreateThread, showCreateThreadHandler] = useDisclosure(false) - - const [threadSearchQuery, setThreadSearchQuery] = useDebouncedState("", 200) - - const query = useInfiniteQuery({ - queryKey: ["threads", threadSearchQuery], - queryFn: async ({pageParam}) => ( - await pb.collection("messageThreads").getList(pageParam, 100, { - filter: `participants ?~ '${user?.id}' && name ~ '${threadSearchQuery}' && systemThread != true`, - }) - ), - getNextPageParam: (lastPage) => - lastPage.page >= lastPage.totalPages ? undefined : lastPage.page + 1, - initialPageParam: 1, - enabled: !!user, - }) - - const threads = query.data?.pages.flatMap(t => t.items) || [] - - return
- - - - - } - rightSection={query.isPending ? : ( - showCreateThreadHandler.toggle()} - color={"green"} - variant={"transparent"} - > - {showCreateThread ? : } - - )} - defaultValue={threadSearchQuery} - onChange={(e) => setThreadSearchQuery(e.currentTarget.value)} - placeholder={"Nach Threads suchen..."} - /> - - - - { - query.refetch() - showCreateThreadHandler.close() - }} onCancel={showCreateThreadHandler.close}/> - - - - {threads.length === 0 ? - - - - - - {threadSearchQuery ? "Keine Threads gefunden" : "Keine Threads"} - - : ( -
- {threads.map(thread => )} - - {query.hasNextPage && ( -
- -
- )} -
- )} -
-} \ No newline at end of file diff --git a/src/pages/chat/components/Announcement.tsx b/src/pages/chat/components/Announcement.tsx index cfb7f5f..4d32197 100644 --- a/src/pages/chat/components/Announcement.tsx +++ b/src/pages/chat/components/Announcement.tsx @@ -8,7 +8,6 @@ export default function Announcement({subject, content}: { content: string, }) { return
- {subject &&
{subject} diff --git a/src/pages/chat/components/Announcements.tsx b/src/pages/chat/components/Announcements.tsx index da5bb03..d5722ec 100644 --- a/src/pages/chat/components/Announcements.tsx +++ b/src/pages/chat/components/Announcements.tsx @@ -1,7 +1,6 @@ import {useInfiniteQuery} from "@tanstack/react-query"; import {PocketBaseErrorAlert, usePB} from "@/lib/pocketbase.tsx"; import {Button, Center, Loader, Text} from "@mantine/core"; - import classes from './Announcements.module.css' import {IconMessageCircleUp} from "@tabler/icons-react"; import Announcement from "@/pages/chat/components/Announcement.tsx"; @@ -13,7 +12,7 @@ export default function Announcements() { queryKey: ["announcements"], queryFn: async ({pageParam}) => ( await pb.collection("messages").getList(pageParam, 100, { - filter: `isAnnouncement=true`, + filter: `isAnnouncement=true&&sender!='${user?.id}'`, sort: "-created" }) ), diff --git a/src/pages/chat/components/ChatNavIcon.tsx b/src/pages/chat/components/ChatNavIcon.tsx index 8a93bed..51357a9 100644 --- a/src/pages/chat/components/ChatNavIcon.tsx +++ b/src/pages/chat/components/ChatNavIcon.tsx @@ -11,28 +11,28 @@ export default function ChatNavIcon() { const [newMessage, setNewMessage] = useState(null); const {start} = useTimeout(() => setNewMessage(null), 5000); - const {user, pb, useSubscription} = usePB() + const {user, useSubscription} = usePB() - const match = useMatch("/chat/:threadId") + const match = useMatch("/chat/:listId") useSubscription({ idOrName: "messages", topic: "*", callback: (event) => { - if (event.action == "create" && event.record.thread) { - pb.collection("messageThreads").getOne(event.record.thread).then(thread => { - if (thread.systemThread) { - start() - setNewMessage("announcements") - } else if ( - match?.params.threadId !== event.record.thread // check if thread is not already open - && - event.record.sender !== user?.id // check if sender is not the user - ) { - start() - setNewMessage(event.record.thread) - } - }) + if (event.action == "create") { + if (event.record.isAnnouncement) { + start() + setNewMessage("announcements") + } else if ( + event.record.eventList + && + match?.params.listId !== event.record.eventList // check if chat page is not already open + && + event.record.sender !== user?.id // check if sender is not the user + ) { + start() + setNewMessage(event.record.eventList) + } } } }) diff --git a/src/pages/chat/components/Messages.tsx b/src/pages/chat/components/Messages.tsx index fb4a2af..239da97 100644 --- a/src/pages/chat/components/Messages.tsx +++ b/src/pages/chat/components/Messages.tsx @@ -1,26 +1,26 @@ -import {MessagesModel, MessageThreadsModel} from "@/models/MessageTypes.ts"; +import {MessagesModel} from "@/models/MessageTypes.ts"; import TextEditor from "@/components/input/Editor"; import {useForm} from "@mantine/form"; import {ActionIcon, Button, Center, Group, Text} from "@mantine/core"; import {IconMessageCircleUp, IconSend} from "@tabler/icons-react"; - import classes from './Messages.module.css' import {useInfiniteQuery, useMutation} from "@tanstack/react-query"; import {PocketBaseErrorAlert, usePB} from "@/lib/pocketbase.tsx"; import InnerHtml from "@/components/InnerHtml"; import {getUserName} from "@/components/users/modals/util.tsx"; import {pprintDateTime} from "@/lib/datetime.ts"; +import {EventListModel} from "@/models/EventTypes.ts"; -export default function Messages({thread}: { - thread: MessageThreadsModel +export default function Messages({eventList}: { + eventList: EventListModel }) { const {user, pb, useSubscription} = usePB() const query = useInfiniteQuery({ - queryKey: ["messages", thread], + queryKey: ["messages", eventList], queryFn: async ({pageParam}) => ( await pb.collection("messages").getList(pageParam, 100, { - filter: `thread='${thread?.id}'`, + filter: `eventList='${eventList?.id}'`, sort: "-created", expand: "sender" }) @@ -35,9 +35,8 @@ export default function Messages({thread}: { idOrName: "messages", topic: "*", callback: (event) => { - if (event.action == "create" && event.record.thread == thread.id) { + if (event.action == "create" && event.record.eventList == eventList.id) { query.refetch() - console.log("test") } } }) @@ -47,7 +46,7 @@ export default function Messages({thread}: { await pb.collection("messages").create({ ...formValues.values, sender: user!.id, - thread: thread.id, + eventList: eventList.id, }) }, onSuccess: () => { diff --git a/src/pages/chat/components/UpsertThreadForm.tsx b/src/pages/chat/components/UpsertThreadForm.tsx deleted file mode 100644 index beb77b3..0000000 --- a/src/pages/chat/components/UpsertThreadForm.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import {MessageThreadsModel} from "@/models/MessageTypes.ts"; -import {usePB} from "@/lib/pocketbase.tsx"; -import {useForm} from "@mantine/form"; -import {useMutation} from "@tanstack/react-query"; -import {ActionIcon, Box, Button, Group, TextInput} from "@mantine/core"; -import UserInput from "@/components/users/UserInput.tsx"; -import {IconX} from "@tabler/icons-react"; - -export default function UpsertThreadForm({thread, onSuccess, onCancel}: { - thread?: MessageThreadsModel, - onSuccess: () => void, - onCancel: () => void -}) { - const {user, pb} = usePB() - const formValues = useForm({ - initialValues: { - name: thread?.name || "", - description: thread?.description || "", - participants: thread?.expand.participants || [user!], - }, - validate: { - name: (value) => { - if (value.length < 1) { - return "Bitte gib einen Namen ein" - } - }, - } - }) - const mutation = useMutation({ - mutationFn: async () => { - const values = { - name: formValues.values.name, - description: formValues.values.description, - participants: formValues.values.participants.map(p => p.id), - } - - if (thread) { - await pb.collection("messageThreads").update(thread.id, values) - } else { - await pb.collection("messageThreads").create(values) - } - }, - onSuccess: () => { - onSuccess() - } - }) - return
mutation.mutate())}> - - - - formValues.setFieldValue("participants", value)} - /> - - - - - - - - - -} \ No newline at end of file diff --git a/src/pages/events/EventOverview/index.page.tsx b/src/pages/events/EventOverview/index.page.tsx index b2044ce..e05722c 100644 --- a/src/pages/events/EventOverview/index.page.tsx +++ b/src/pages/events/EventOverview/index.page.tsx @@ -19,7 +19,7 @@ export default function EventOverview() { { [{title: "Home", to: "/"}, {title: "Events", to: "/events"}, ].map(({title, to}) => ( - {title} + {title} )) }
diff --git a/src/pages/events/StatusEditor/EntrySearch.tsx b/src/pages/events/StatusEditor/EntrySearch.tsx index 96ca023..5d79845 100644 --- a/src/pages/events/StatusEditor/EntrySearch.tsx +++ b/src/pages/events/StatusEditor/EntrySearch.tsx @@ -1,6 +1,6 @@ import QRCodeModal from "@/pages/events/StatusEditor/QrCodeModal.tsx"; import EntrySearchModal from "@/pages/events/StatusEditor/EntrySearchModal.tsx"; -import {ActionIcon, Center, Group, Text} from "@mantine/core"; +import {ActionIcon, Group, Text, Title} from "@mantine/core"; import {IconQrcode, IconUserSearch} from "@tabler/icons-react"; import {useDisclosure} from "@mantine/hooks"; import SearchSVG from "@/illustrations/search.svg?react" @@ -14,11 +14,13 @@ export default function EntrySearch() { -
+
-
-
+ + Status Editor + + ( - + {title} ))} diff --git a/src/pages/events/e/:eventId/EditEventRouter.tsx b/src/pages/events/e/:eventId/EditEventRouter.tsx index c553eff..59a18bc 100644 --- a/src/pages/events/e/:eventId/EditEventRouter.tsx +++ b/src/pages/events/e/:eventId/EditEventRouter.tsx @@ -118,7 +118,7 @@ export default function EditEventRouter() { {title: "Events", to: "/events"}, {title: event.name, to: `/events/${event.id}`}, ].map(({title, to}) => ( - + {title} ))} diff --git a/src/pages/events/e/:eventId/EventLists/:listId/EventListRouter.tsx b/src/pages/events/e/:eventId/EventLists/:listId/EventListRouter.tsx index 51f4390..939f359 100644 --- a/src/pages/events/e/:eventId/EventLists/:listId/EventListRouter.tsx +++ b/src/pages/events/e/:eventId/EventLists/:listId/EventListRouter.tsx @@ -6,6 +6,7 @@ import { IconForms, IconLock, IconLockOpen, + IconMessageCircle, IconSettings, IconUserCog } from "@tabler/icons-react"; @@ -57,6 +58,14 @@ export default function EventListRouter({event}: { event: EventModel }) { } ] + if (list.enableChat) { + nav.push({ + icon: , + to: `/chat/${list.id}`, + title: "Chat" + }) + } + if (canEditEvent) { nav.push(...[ { @@ -81,10 +90,10 @@ export default function EventListRouter({event}: { event: EventModel }) { - Event Listen + Listen - + {list.name} diff --git a/src/pages/events/e/:eventId/EventLists/:listId/ListSettings/ListSettings.tsx b/src/pages/events/e/:eventId/EventLists/:listId/ListSettings/ListSettings.tsx index 5bd6fe4..277f904 100644 --- a/src/pages/events/e/:eventId/EventLists/:listId/ListSettings/ListSettings.tsx +++ b/src/pages/events/e/:eventId/EventLists/:listId/ListSettings/ListSettings.tsx @@ -21,6 +21,7 @@ export default function ListSettings({list, event}: { list: EventListModel, even open: list.open, allowOverlappingEntries: list.allowOverlappingEntries, onlyStuVeAccounts: list.onlyStuVeAccounts, + enableChat: list.enableChat, favorite: list.favorite, description: list.description || "", } @@ -105,6 +106,19 @@ export default function ListSettings({list, event}: { list: EventListModel, even {...formValues.getInputProps("allowOverlappingEntries", {type: "checkbox"})} /> + " + + "Der Chat wird automatisch gelöscht, wenn diese Liste gelöscht wird. Wenn du den Chat deaktivierst, " + + "werden die Nachrichten nicht gelöscht und kann der Chat kann später wieder aktiviert werden." + } + {...formValues.getInputProps("enableChat", {type: "checkbox"})} + /> + - + - - - + + + } } - rightSection={listsQuery.isLoading ? : undefined} + rightSection={listsQuery.isLoading ? : ( + canEditEvent && + + + {createNewList ? : } + + + )} data={ listsQuery .data diff --git a/src/pages/events/entries/UserEntries.tsx b/src/pages/events/entries/UserEntries.tsx index 17007aa..3ecb9a5 100644 --- a/src/pages/events/entries/UserEntries.tsx +++ b/src/pages/events/entries/UserEntries.tsx @@ -67,7 +67,7 @@ export default function UserEntries() { {title: "Events", to: "/events"}, {title: "Anmeldungen", to: `/events/entries`}, ].map(({title, to}) => ( - + {title} ))} diff --git a/src/pages/events/s/EventListView.tsx b/src/pages/events/s/EventListView.tsx index ae2cc35..653a90c 100644 --- a/src/pages/events/s/EventListView.tsx +++ b/src/pages/events/s/EventListView.tsx @@ -23,7 +23,7 @@ export default function EventListView({event, listId}: { event: EventModel, list const listSlotsQuery = useQuery({ queryKey: ["event", event.id, "list", listId, "slots", activePage], - queryFn: async () => (await pb.collection("eventListSlotsWithEntriesCount").getList(activePage, 10, { + queryFn: async () => (await pb.collection("eventListSlotsWithEntriesCount").getList(activePage, 20, { filter: `eventList='${listId}'`, sort: "startDate", enabled: !!listId, diff --git a/src/pages/events/s/EventView.tsx b/src/pages/events/s/EventView.tsx index 8428ba2..3bce921 100644 --- a/src/pages/events/s/EventView.tsx +++ b/src/pages/events/s/EventView.tsx @@ -66,7 +66,7 @@ export default function SharedEvent() { {title: "Events", to: "/events"}, {title: event.name, to: `/events/${event.id}`}, ].map(({title, to}) => ( - + {title} ))} diff --git a/src/style/global.css b/src/style/global.css index f69210d..aea27a0 100644 --- a/src/style/global.css +++ b/src/style/global.css @@ -67,12 +67,10 @@ a { text-decoration: unset; /* Removes default underline */ - color: revert; } a:hover, a:active, a:visited { text-decoration: unset; /* Removes default underline */ - color: unset; } .section-icon { @@ -156,5 +154,5 @@ a:hover, a:active, a:visited { } .monospace { - font-family: var(--mantine-font-family-monospace); + font-family: var(--mantine-font-family-monospace), monospace; } \ No newline at end of file