From 6c158a9e2fc998d1e647e16ee07266dbdc903ca6 Mon Sep 17 00:00:00 2001 From: Maksym <109230509+TheMaksym@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:12:40 -0500 Subject: [PATCH] Whitespace in Memo References Whitespace works with Memo References with this code. --- CreateMemoRelationDialog.tsx | 172 +++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 CreateMemoRelationDialog.tsx diff --git a/CreateMemoRelationDialog.tsx b/CreateMemoRelationDialog.tsx new file mode 100644 index 000000000..ff35910bf --- /dev/null +++ b/CreateMemoRelationDialog.tsx @@ -0,0 +1,172 @@ +import { Autocomplete, AutocompleteOption, Button, Checkbox, Chip, IconButton } from "@mui/joy"; +import React, { useState, useEffect } from "react"; +import { toast } from "react-hot-toast"; +import { memoServiceClient } from "@/grpcweb"; +import { DEFAULT_MEMO_LIMIT } from "@/helpers/consts"; +import { getDateTimeString } from "@/helpers/datetime"; +import useCurrentUser from "@/hooks/useCurrentUser"; +import { Memo } from "@/types/proto/api/v2/memo_service"; +import { useTranslate } from "@/utils/i18n"; +import { generateDialog } from "./Dialog"; +import Icon from "./Icon"; + +interface Props extends DialogProps { + onConfirm: (memoIdList: number[], embedded?: boolean) => void; +} + +const CreateMemoRelationDialog: React.FC = (props: Props) => { + const { destroy, onConfirm } = props; + const t = useTranslate(); + const user = useCurrentUser(); + const [searchText, setSearchText] = useState(""); + const [debouncedSearchText, setDebouncedSearchText] = useState(""); + const [isFetching, setIsFetching] = useState(true); + const [fetchedMemos, setFetchedMemos] = useState([]); + const [selectedMemos, setSelectedMemos] = useState([]); + const [embedded, setEmbedded] = useState(false); + const filteredMemos = fetchedMemos.filter((memo) => !selectedMemos.includes(memo)); + + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedSearchText(searchText.trim()); + }, 300); + + return () => { + clearTimeout(handler); + }; + }, [searchText]); + + useEffect(() => { + const fetchMemos = async () => { + setIsFetching(true); + try { + const filters = [`creator == "${user.name}"`, `row_status == "NORMAL"`]; + if (debouncedSearchText) { + filters.push(`content_search == [${JSON.stringify(debouncedSearchText)}]`); + } + const { memos } = await memoServiceClient.listMemos({ + pageSize: DEFAULT_MEMO_LIMIT, + filter: filters.length > 0 ? filters.join(" && ") : undefined, + }); + setFetchedMemos(memos); + } catch (error: any) { + console.error(error); + toast.error(error.response.data.message); + } + setIsFetching(false); + }; + + if (debouncedSearchText) fetchMemos(); + }, [debouncedSearchText]); + + const getHighlightedContent = (content: string) => { + const index = content.toLowerCase().indexOf(searchText.toLowerCase()); + if (index === -1) { + return content; + } + let before = content.slice(0, index); + if (before.length > 20) { + before = "..." + before.slice(before.length - 20); + } + const highlighted = content.slice(index, index + searchText.length); + let after = content.slice(index + searchText.length); + if (after.length > 20) { + after = after.slice(0, 20) + "..."; + } + + return ( + <> + {before} + {highlighted} + {after} + + ); + }; + + const handleCloseDialog = () => { + destroy(); + }; + + const handleConfirmBtnClick = async () => { + onConfirm( + selectedMemos.map((memo) => memo.id), + embedded, + ); + destroy(); + }; + + return ( + <> +
+

{"Add references"}

+ destroy()}> + + +
+
+ setSearchText(value)} + getOptionKey={(option) => option.name} + getOptionLabel={(option) => option.content} + isOptionEqualToValue={(option, value) => option.id === value.id} + renderOption={(props, option) => ( + +
+

{getDateTimeString(option.displayTime)}

+

+ {searchText ? getHighlightedContent(option.content) : option.content} +

+
+
+ )} + renderTags={(memos) => + memos.map((memo) => ( + +
+

{getDateTimeString(memo.displayTime)}

+ {memo.content} +
+
+ )) + } + onChange={(_, value) => setSelectedMemos(value)} + /> +
+ setEmbedded(e.target.checked)} /> +
+
+ + +
+
+ + ); +}; + +function showCreateMemoRelationDialog(props: Omit) { + generateDialog( + { + className: "create-memo-relation-dialog", + dialogName: "create-memo-relation-dialog", + }, + CreateMemoRelationDialog, + props, + ); +} + +export default showCreateMemoRelationDialog; \ No newline at end of file