From 43fd94827feeba915e62fe485e9d38eb9ae7d8b7 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:20:44 +0530 Subject: [PATCH] fixed mentions not showing in modals --- packages/editor/core/src/hooks/use-editor.tsx | 11 +- packages/editor/core/src/styles/table.css | 4 +- .../editor/core/src/ui/extensions/index.tsx | 148 +++++++++--------- .../editor/core/src/ui/mentions/custom.tsx | 2 +- .../editor/core/src/ui/mentions/index.tsx | 47 +++--- .../core/src/ui/mentions/mention-list.tsx | 1 + .../src/ui/mentions/mention-node-view.tsx | 18 ++- .../editor/document-editor/src/ui/index.tsx | 1 + .../src/extensions/slash-commands.tsx | 4 +- packages/types/src/users.d.ts | 1 - .../inbox/modals/create-issue-modal.tsx | 9 +- web/components/issues/description-form.tsx | 6 +- web/components/issues/draft-issue-form.tsx | 12 +- .../issue-activity/activity-comment-root.tsx | 4 +- .../issue-activity/comments/comment-card.tsx | 8 +- .../comments/comment-create.tsx | 8 +- .../issue-activity/comments/root.tsx | 4 +- .../issue-detail/issue-activity/root.tsx | 4 + web/components/issues/issue-modal/form.tsx | 6 +- web/hooks/store/use-mention.ts | 95 ++++++++--- .../projects/[projectId]/pages/[pageId].tsx | 26 +-- web/pages/_app.tsx | 1 + 22 files changed, 253 insertions(+), 167 deletions(-) diff --git a/packages/editor/core/src/hooks/use-editor.tsx b/packages/editor/core/src/hooks/use-editor.tsx index c2923c1e9..cae01569a 100644 --- a/packages/editor/core/src/hooks/use-editor.tsx +++ b/packages/editor/core/src/hooks/use-editor.tsx @@ -5,7 +5,7 @@ import { CoreEditorExtensions } from "src/ui/extensions"; import { EditorProps } from "@tiptap/pm/view"; import { getTrimmedHTML } from "src/lib/utils"; import { DeleteImage } from "src/types/delete-image"; -import { IMentionSuggestion } from "src/types/mention-suggestion"; +import { IMentionHighlight, IMentionSuggestion } from "src/types/mention-suggestion"; import { RestoreImage } from "src/types/restore-image"; import { UploadImage } from "src/types/upload-image"; @@ -27,8 +27,8 @@ interface CustomEditorProps { extensions?: any; editorProps?: EditorProps; forwardedRef?: any; - mentionHighlights?: string[]; - mentionSuggestions?: IMentionSuggestion[]; + mentionHighlights?: () => Promise; + mentionSuggestions?: () => Promise; } export const useEditor = ({ @@ -48,6 +48,7 @@ export const useEditor = ({ mentionHighlights, mentionSuggestions, }: CustomEditorProps) => { + console.log("the mentions", mentionHighlights); const editor = useCustomEditor( { editorProps: { @@ -57,8 +58,8 @@ export const useEditor = ({ extensions: [ ...CoreEditorExtensions( { - mentionSuggestions: mentionSuggestions ?? [], - mentionHighlights: mentionHighlights ?? [], + mentionSuggestions: mentionSuggestions, + mentionHighlights: mentionHighlights, }, deleteFile, restoreFile, diff --git a/packages/editor/core/src/styles/table.css b/packages/editor/core/src/styles/table.css index 8a47a8c59..597384f5b 100644 --- a/packages/editor/core/src/styles/table.css +++ b/packages/editor/core/src/styles/table.css @@ -68,7 +68,7 @@ top: 0; bottom: -2px; width: 4px; - z-index: 99; + z-index: 5; background-color: rgba(var(--color-primary-400)); pointer-events: none; } @@ -81,7 +81,7 @@ .tableWrapper .tableControls .rowsControl { transition: opacity ease-in 100ms; position: absolute; - z-index: 99; + z-index: 5; display: flex; justify-content: center; align-items: center; diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index e413aa9c1..ea5469b9a 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -22,94 +22,92 @@ import { CustomKeymap } from "src/ui/extensions/keymap"; import { CustomQuoteExtension } from "src/ui/extensions/quote"; import { DeleteImage } from "src/types/delete-image"; -import { IMentionSuggestion } from "src/types/mention-suggestion"; +import { IMentionHighlight, IMentionSuggestion } from "src/types/mention-suggestion"; import { RestoreImage } from "src/types/restore-image"; import { CustomLinkExtension } from "src/ui/extensions/custom-link"; import { CustomCodeInlineExtension } from "./code-inline"; export const CoreEditorExtensions = ( mentionConfig: { - mentionSuggestions: IMentionSuggestion[]; - mentionHighlights: string[]; + mentionSuggestions?: () => Promise; + mentionHighlights?: () => Promise; }, deleteFile: DeleteImage, restoreFile: RestoreImage, cancelUploadImage?: () => any -) => { - return [ - StarterKit.configure({ - bulletList: { - HTMLAttributes: { - class: "list-disc list-outside leading-3 -mt-2", - }, - }, - orderedList: { - HTMLAttributes: { - class: "list-decimal list-outside leading-3 -mt-2", - }, - }, - listItem: { - HTMLAttributes: { - class: "leading-normal -mb-2", - }, - }, - code: false, - codeBlock: false, - horizontalRule: { - HTMLAttributes: { class: "mt-4 mb-4" }, - }, - blockquote: false, - dropcursor: { - color: "rgba(var(--color-text-100))", - width: 2, - }, - }), - CustomQuoteExtension.configure({ - HTMLAttributes: { className: "border-l-4 border-custom-border-300" }, - }), - CustomKeymap, - ListKeymap, - CustomLinkExtension.configure({ - openOnClick: true, - autolink: true, - linkOnPaste: true, - protocols: ["http", "https"], - validate: (url: string) => isValidHttpUrl(url), +) => [ + StarterKit.configure({ + bulletList: { HTMLAttributes: { - class: - "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", + class: "list-disc list-outside leading-3 -mt-2", }, - }), - ImageExtension(deleteFile, restoreFile, cancelUploadImage).configure({ + }, + orderedList: { HTMLAttributes: { - class: "rounded-lg border border-custom-border-300", + class: "list-decimal list-outside leading-3 -mt-2", }, - }), - TiptapUnderline, - TextStyle, - Color, - TaskList.configure({ + }, + listItem: { HTMLAttributes: { - class: "not-prose pl-2", + class: "leading-normal -mb-2", }, - }), - TaskItem.configure({ - HTMLAttributes: { - class: "flex items-start my-4", - }, - nested: true, - }), - CustomCodeBlockExtension, - CustomCodeInlineExtension, - Markdown.configure({ - html: true, - transformCopiedText: true, - transformPastedText: true, - }), - Table, - TableHeader, - TableCell, - TableRow, - Mentions(mentionConfig.mentionSuggestions, mentionConfig.mentionHighlights, false), - ]; -}; + }, + code: false, + codeBlock: false, + horizontalRule: { + HTMLAttributes: { class: "mt-4 mb-4" }, + }, + blockquote: false, + dropcursor: { + color: "rgba(var(--color-text-100))", + width: 2, + }, + }), + CustomQuoteExtension.configure({ + HTMLAttributes: { className: "border-l-4 border-custom-border-300" }, + }), + CustomKeymap, + ListKeymap, + CustomLinkExtension.configure({ + openOnClick: true, + autolink: true, + linkOnPaste: true, + protocols: ["http", "https"], + validate: (url: string) => isValidHttpUrl(url), + HTMLAttributes: { + class: + "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", + }, + }), + ImageExtension(deleteFile, restoreFile, cancelUploadImage).configure({ + HTMLAttributes: { + class: "rounded-lg border border-custom-border-300", + }, + }), + TiptapUnderline, + TextStyle, + Color, + TaskList.configure({ + HTMLAttributes: { + class: "not-prose pl-2", + }, + }), + TaskItem.configure({ + HTMLAttributes: { + class: "flex items-start my-4", + }, + nested: true, + }), + CustomCodeBlockExtension, + CustomCodeInlineExtension, + Markdown.configure({ + html: true, + transformCopiedText: true, + transformPastedText: true, + }), + Table, + TableHeader, + TableCell, + TableRow, + Mentions(mentionConfig.mentionSuggestions, mentionConfig.mentionHighlights, false), +]; diff --git a/packages/editor/core/src/ui/mentions/custom.tsx b/packages/editor/core/src/ui/mentions/custom.tsx index d41b06420..8bab79666 100644 --- a/packages/editor/core/src/ui/mentions/custom.tsx +++ b/packages/editor/core/src/ui/mentions/custom.tsx @@ -5,7 +5,7 @@ import { MentionNodeView } from "src/ui/mentions/mention-node-view"; import { IMentionHighlight } from "src/types/mention-suggestion"; export interface CustomMentionOptions extends MentionOptions { - mentionHighlights: IMentionHighlight[]; + mentionHighlights: () => Promise; readonly?: boolean; } diff --git a/packages/editor/core/src/ui/mentions/index.tsx b/packages/editor/core/src/ui/mentions/index.tsx index 15637e516..1448131ab 100644 --- a/packages/editor/core/src/ui/mentions/index.tsx +++ b/packages/editor/core/src/ui/mentions/index.tsx @@ -7,29 +7,9 @@ import tippy from "tippy.js"; import { v4 as uuidv4 } from "uuid"; import { MentionList } from "src/ui/mentions/mention-list"; -export const getSuggestionItems = - (getSuggestions: () => Promise) => - async ({ query }: { query: string }) => { - console.log("yaa"); - const suggestions = await getSuggestions(); - const mappedSuggestions: IMentionSuggestion[] = suggestions.map((suggestion): IMentionSuggestion => { - const transactionId = uuidv4(); - return { - ...suggestion, - id: transactionId, - }; - }); - const filteredSuggestions = mappedSuggestions - .filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase())) - .slice(0, 5); - - console.log("yoo", filteredSuggestions); - return filteredSuggestions; - }; - export const Mentions = ( mentionSuggestions: () => Promise, - mentionHighlights: IMentionHighlight[], + mentionHighlights: () => Promise, readonly: boolean ) => CustomMention.configure({ @@ -39,8 +19,8 @@ export const Mentions = ( readonly: readonly, mentionHighlights: mentionHighlights, suggestion: { - items: ({ query }) => { - const suggestions = mentionSuggestions(); + items: async ({ query }) => { + const suggestions = await mentionSuggestions(); const mappedSuggestions: IMentionSuggestion[] = suggestions.map((suggestion): IMentionSuggestion => { const transactionId = uuidv4(); return { @@ -48,11 +28,11 @@ export const Mentions = ( id: transactionId, }; }); + const filteredSuggestions = mappedSuggestions .filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase())) .slice(0, 5); - console.log("yoo", filteredSuggestions); return filteredSuggestions; }, // @ts-ignore @@ -60,33 +40,44 @@ export const Mentions = ( let reactRenderer: ReactRenderer | null = null; let popup: any | null = null; + const hidePopup = () => { + popup?.[0].hide(); + }; return { onStart: (props: { editor: Editor; clientRect: DOMRect }) => { - props.editor.storage.mentionsOpen = true; + if (!props.clientRect) { + return; + } reactRenderer = new ReactRenderer(MentionList, { props, editor: props.editor, }); + props.editor.storage.mentionsOpen = true; // @ts-ignore popup = tippy("body", { getReferenceClientRect: props.clientRect, - appendTo: () => document.querySelector("#editor-container"), + appendTo: () => document.body, content: reactRenderer.element, showOnCreate: true, interactive: true, trigger: "manual", placement: "bottom-start", }); + // document.addEventListener("scroll", hidePopup, true); }, - onUpdate: (props: { editor: Editor; clientRect: DOMRect }) => { reactRenderer?.updateProps(props); + if (!props.clientRect) { + return; + } + popup && popup[0].setProps({ getReferenceClientRect: props.clientRect, }); }, + onKeyDown: (props: { event: KeyboardEvent }) => { if (props.event.key === "Escape") { popup?.[0].hide(); @@ -108,6 +99,8 @@ export const Mentions = ( props.editor.storage.mentionsOpen = false; popup?.[0].destroy(); reactRenderer?.destroy(); + + // document.removeEventListener("scroll", hidePopup, true); }, }; }, diff --git a/packages/editor/core/src/ui/mentions/mention-list.tsx b/packages/editor/core/src/ui/mentions/mention-list.tsx index b7ec14ecc..5f4c7ea66 100644 --- a/packages/editor/core/src/ui/mentions/mention-list.tsx +++ b/packages/editor/core/src/ui/mentions/mention-list.tsx @@ -12,6 +12,7 @@ interface MentionListProps { export const MentionList = forwardRef((props: MentionListProps, ref) => { const [selectedIndex, setSelectedIndex] = useState(0); + console.log("props", props); const selectItem = (index: number) => { const item = props.items[index]; diff --git a/packages/editor/core/src/ui/mentions/mention-node-view.tsx b/packages/editor/core/src/ui/mentions/mention-node-view.tsx index b58ad4eb2..ec97bbfeb 100644 --- a/packages/editor/core/src/ui/mentions/mention-node-view.tsx +++ b/packages/editor/core/src/ui/mentions/mention-node-view.tsx @@ -4,11 +4,22 @@ import { NodeViewWrapper } from "@tiptap/react"; import { cn } from "src/lib/utils"; import { useRouter } from "next/router"; import { IMentionHighlight } from "src/types/mention-suggestion"; +import { useEffect, useState } from "react"; // eslint-disable-next-line import/no-anonymous-default-export export const MentionNodeView = (props) => { const router = useRouter(); - const highlights = props.extension.options.mentionHighlights as IMentionHighlight[]; + // const highlights = props.extension.options.mentionHighlights as IMentionHighlight[]; + const [highlightsState, setHighlightsState] = useState(); + + useEffect(() => { + console.log("hightlights type", props.extension.options.mentionHighlights); + const hightlights = async () => { + const userId = await props.extension.options.mentionHighlights(); + setHighlightsState(userId); + }; + hightlights(); + }, []); const handleClick = () => { if (!props.extension.options.readonly) { @@ -16,12 +27,13 @@ export const MentionNodeView = (props) => { } }; + console.log("state of highlight", highlightsState); return ( { // @ts-ignore popup = tippy("body", { getReferenceClientRect: props.clientRect, - appendTo: () => document.querySelector("#editor-container"), + appendTo: () => document.body, content: component.element, showOnCreate: true, - interactive: true, + // interactive: true, trigger: "manual", placement: "bottom-start", }); diff --git a/packages/types/src/users.d.ts b/packages/types/src/users.d.ts index 81c8abcd5..50601b718 100644 --- a/packages/types/src/users.d.ts +++ b/packages/types/src/users.d.ts @@ -15,7 +15,6 @@ export interface IUser { is_email_verified: boolean; is_managed: boolean; is_onboarded: boolean; - is_password_autoset: boolean; is_tour_completed: boolean; is_password_autoset: boolean; mobile_number: string | null; diff --git a/web/components/inbox/modals/create-issue-modal.tsx b/web/components/inbox/modals/create-issue-modal.tsx index 84c4bef1e..88103db19 100644 --- a/web/components/inbox/modals/create-issue-modal.tsx +++ b/web/components/inbox/modals/create-issue-modal.tsx @@ -48,7 +48,7 @@ export const CreateInboxIssueModal: React.FC = observer((props) => { const editorRef = useRef(null); // toast alert const { setToastAlert } = useToast(); - const { mentionHighlights, mentionSuggestions } = useMention(); + // router const router = useRouter(); const { workspaceSlug, projectId, inboxId } = router.query as { @@ -59,6 +59,13 @@ export const CreateInboxIssueModal: React.FC = observer((props) => { const workspaceStore = useWorkspace(); const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string; + console.log("in create issue modal", workspaceSlug, projectId); + + const { mentionHighlights, mentionSuggestions } = useMention({ + workspaceSlug: workspaceSlug as string, + projectId: projectId as string, + }); + // store hooks const { issues: { createInboxIssue }, diff --git a/web/components/issues/description-form.tsx b/web/components/issues/description-form.tsx index b7601ef52..60fb3ec10 100644 --- a/web/components/issues/description-form.tsx +++ b/web/components/issues/description-form.tsx @@ -48,7 +48,11 @@ export const IssueDescriptionForm: FC = observer((props) => { const { setShowAlert } = useReloadConfirmations(); // store hooks - const { mentionHighlights, mentionSuggestions } = useMention(); + const { mentionHighlights, mentionSuggestions } = useMention({ + workspaceSlug: workspaceSlug as string, + projectId: projectId as string, + }); + // form info const { handleSubmit, diff --git a/web/components/issues/draft-issue-form.tsx b/web/components/issues/draft-issue-form.tsx index cfd6370fa..da5d013bc 100644 --- a/web/components/issues/draft-issue-form.tsx +++ b/web/components/issues/draft-issue-form.tsx @@ -106,10 +106,6 @@ export const DraftIssueForm: FC = observer((props) => { const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false); // store hooks const { areEstimatesEnabledForProject } = useEstimate(); - const { mentionHighlights, mentionSuggestions } = useMention(); - // hooks - const { setValue: setLocalStorageValue } = useLocalStorage("draftedIssue", {}); - const { setToastAlert } = useToast(); // refs const editorRef = useRef(null); // router @@ -118,6 +114,14 @@ export const DraftIssueForm: FC = observer((props) => { const workspaceStore = useWorkspace(); const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string; + // hooks + const { setValue: setLocalStorageValue } = useLocalStorage("draftedIssue", {}); + const { setToastAlert } = useToast(); + const { mentionHighlights, mentionSuggestions } = useMention({ + workspaceSlug: workspaceSlug as string, + projectId: projectId as string, + }); + // store const { config: { envConfig }, diff --git a/web/components/issues/issue-detail/issue-activity/activity-comment-root.tsx b/web/components/issues/issue-detail/issue-activity/activity-comment-root.tsx index 575e8d841..3d9cd2fff 100644 --- a/web/components/issues/issue-detail/issue-activity/activity-comment-root.tsx +++ b/web/components/issues/issue-detail/issue-activity/activity-comment-root.tsx @@ -10,13 +10,14 @@ import { TActivityOperations } from "./root"; type TIssueActivityCommentRoot = { workspaceSlug: string; + projectId: string; issueId: string; activityOperations: TActivityOperations; showAccessSpecifier?: boolean; }; export const IssueActivityCommentRoot: FC = observer((props) => { - const { workspaceSlug, issueId, activityOperations, showAccessSpecifier } = props; + const { workspaceSlug, issueId, activityOperations, showAccessSpecifier, projectId } = props; // hooks const { activity: { getActivityCommentByIssueId }, @@ -31,6 +32,7 @@ export const IssueActivityCommentRoot: FC = observer( {activityComments.map((activityComment, index) => activityComment.activity_type === "COMMENT" ? ( = (props) => { - const { workspaceSlug, commentId, activityOperations, ends, showAccessSpecifier = false } = props; + const { workspaceSlug, projectId, commentId, activityOperations, ends, showAccessSpecifier = false } = props; // hooks const { comment: { getCommentById }, } = useIssueDetail(); const { currentUser } = useUser(); - const { mentionHighlights, mentionSuggestions } = useMention(); + const { mentionHighlights, mentionSuggestions } = useMention({ + workspaceSlug: workspaceSlug as string, + projectId: projectId as string, + }); // refs const editorRef = useRef(null); const showEditorRef = useRef(null); diff --git a/web/components/issues/issue-detail/issue-activity/comments/comment-create.tsx b/web/components/issues/issue-detail/issue-activity/comments/comment-create.tsx index bf5b15266..fd2ca8fbb 100644 --- a/web/components/issues/issue-detail/issue-activity/comments/comment-create.tsx +++ b/web/components/issues/issue-detail/issue-activity/comments/comment-create.tsx @@ -15,6 +15,7 @@ import { useMention, useWorkspace } from "hooks/store"; const fileService = new FileService(); type TIssueCommentCreate = { + projectId: string; workspaceSlug: string; activityOperations: TActivityOperations; showAccessSpecifier?: boolean; @@ -39,11 +40,14 @@ const commentAccess: commentAccessType[] = [ ]; export const IssueCommentCreate: FC = (props) => { - const { workspaceSlug, activityOperations, showAccessSpecifier = false } = props; + const { workspaceSlug, projectId, activityOperations, showAccessSpecifier = false } = props; const workspaceStore = useWorkspace(); const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string; - const { mentionHighlights, mentionSuggestions } = useMention(); + const { mentionHighlights, mentionSuggestions } = useMention({ + workspaceSlug: workspaceSlug as string, + projectId: projectId as string, + }); // refs const editorRef = useRef(null); diff --git a/web/components/issues/issue-detail/issue-activity/comments/root.tsx b/web/components/issues/issue-detail/issue-activity/comments/root.tsx index 4e2775c4a..7c8f45cd0 100644 --- a/web/components/issues/issue-detail/issue-activity/comments/root.tsx +++ b/web/components/issues/issue-detail/issue-activity/comments/root.tsx @@ -8,6 +8,7 @@ import { IssueCommentCard } from "./comment-card"; import { TActivityOperations } from "../root"; type TIssueCommentRoot = { + projectId: string; workspaceSlug: string; issueId: string; activityOperations: TActivityOperations; @@ -15,7 +16,7 @@ type TIssueCommentRoot = { }; export const IssueCommentRoot: FC = observer((props) => { - const { workspaceSlug, issueId, activityOperations, showAccessSpecifier } = props; + const { workspaceSlug, projectId, issueId, activityOperations, showAccessSpecifier } = props; // hooks const { comment: { getCommentsByIssueId }, @@ -28,6 +29,7 @@ export const IssueCommentRoot: FC = observer((props) => {
{commentIds.map((commentId, index) => ( = observer((props) => { {activityTab === "all" ? (
= observer((props) => { ) : (
= observer((props) => { } = useApplication(); const { getProjectById } = useProject(); const { areEstimatesEnabledForProject } = useEstimate(); - const { mentionHighlights, mentionSuggestions } = useMention(); + const { mentionHighlights, mentionSuggestions } = useMention({ + workspaceSlug: workspaceSlug as string, + projectId: defaultProjectId, + }); + const { issue: { getIssueById }, } = useIssueDetail(); diff --git a/web/hooks/store/use-mention.ts b/web/hooks/store/use-mention.ts index 270a7764e..082fcd9a6 100644 --- a/web/hooks/store/use-mention.ts +++ b/web/hooks/store/use-mention.ts @@ -1,23 +1,27 @@ import useSWR from "swr"; - -import { ProjectMemberService } from "services/project"; -import { IProjectMember } from "@plane/types"; -import { UserService } from "services/user.service"; import { useRef, useEffect } from "react"; +import { ProjectMemberService } from "services/project"; +import { IProjectMember, IUser } from "@plane/types"; +import { UserService } from "services/user.service"; export const useMention = ({ workspaceSlug, projectId }: { workspaceSlug: string; projectId: string }) => { const userService = new UserService(); const projectMemberService = new ProjectMemberService(); - const { data: projectMembers } = useSWR(["projectMembers", workspaceSlug, projectId], async () => { - const members = await projectMemberService.fetchProjectMembers(workspaceSlug, projectId); - const detailedMembers = await Promise.all( - members.map(async (member) => projectMemberService.getProjectMember(workspaceSlug, projectId, member.id)) - ); - return detailedMembers; - }); + const { data: projectMembers, isLoading: projectMembersLoading } = useSWR( + ["projectMembers", workspaceSlug, projectId], + async () => { + const members = await projectMemberService.fetchProjectMembers(workspaceSlug, projectId); + const detailedMembers = await Promise.all( + members.map(async (member) => projectMemberService.getProjectMember(workspaceSlug, projectId, member.id)) + ); + return detailedMembers; + } + ); + const { data: user, isLoading: userDataLoading } = useSWR("currentUser", async () => userService.currentUser()); const projectMembersRef = useRef(); + const userRef = useRef(); useEffect(() => { if (projectMembers) { @@ -25,13 +29,51 @@ export const useMention = ({ workspaceSlug, projectId }: { workspaceSlug: string } }, [projectMembers]); - const { data: user } = useSWR("currentUser", async () => userService.currentUser()); + useEffect(() => { + if (userRef) { + userRef.current = user; + } + }, [user]); - const mentionHighlights = user ? [user.id] : []; + const waitForUserDate = async () => + new Promise((resolve) => { + const checkData = () => { + if (userRef.current) { + resolve(userRef.current); + } else { + setTimeout(checkData, 100); + } + }; + checkData(); + }); - const getMentionSuggestions = () => () => { - const mentionSuggestions = - projectMembersRef.current?.map((memberDetails) => ({ + const mentionHighlights = async () => { + console.log("isme aaya highlights"); + if (!userDataLoading && userRef.current) { + return [userRef.current.id]; + } else { + const user = await waitForUserDate(); + return [user.id]; + } + }; + + // Polling function to wait for projectMembersRef.current to be populated + const waitForData = async () => + new Promise((resolve) => { + const checkData = () => { + if (projectMembersRef.current && projectMembersRef.current.length > 0) { + resolve(projectMembersRef.current); + } else { + setTimeout(checkData, 100); // Check every 100ms + } + }; + checkData(); + }); + + const mentionSuggestions = async () => { + if (!projectMembersLoading && projectMembersRef.current && projectMembersRef.current.length > 0) { + // If data is already available, return it immediately + return projectMembersRef.current.map((memberDetails) => ({ entity_name: "user_mention", entity_identifier: `${memberDetails?.member?.id}`, type: "User", @@ -39,12 +81,25 @@ export const useMention = ({ workspaceSlug, projectId }: { workspaceSlug: string subtitle: memberDetails?.member?.email ?? "", avatar: `${memberDetails?.member?.avatar}`, redirect_uri: `/${workspaceSlug}/profile/${memberDetails?.member?.id}`, - })) || []; - - return mentionSuggestions; + })); + } else { + // Wait for data to be available + const members = await waitForData(); + console.log("isme aaya", members); + return members.map((memberDetails) => ({ + entity_name: "user_mention", + entity_identifier: `${memberDetails?.member?.id}`, + type: "User", + title: `${memberDetails?.member?.display_name}`, + subtitle: memberDetails?.member?.email ?? "", + avatar: `${memberDetails?.member?.avatar}`, + redirect_uri: `/${workspaceSlug}/profile/${memberDetails?.member?.id}`, + })); + } }; + return { - getMentionSuggestions, + mentionSuggestions, mentionHighlights, }; }; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx index 50a952d4b..674827b20 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx @@ -1,9 +1,9 @@ import { Sparkle } from "lucide-react"; import { observer } from "mobx-react-lite"; -import useSWR from "swr"; import { useRouter } from "next/router"; import { ReactElement, useEffect, useRef, useState } from "react"; import { Controller, useForm } from "react-hook-form"; +import useSWR from "swr"; // hooks import { useApplication, useMention, usePage, useUser, useWorkspace } from "hooks/store"; @@ -26,11 +26,9 @@ import { IPage } from "@plane/types"; import { NextPageWithLayout } from "lib/types"; // fetch-keys // constants +import { IssuePeekOverview } from "components/issues"; import { EUserProjectRoles } from "constants/project"; import { useProjectPages } from "hooks/store/use-project-specific-pages"; -import { IssuePeekOverview } from "components/issues"; -import { ProjectMemberService } from "services/project"; -import { UserService } from "services/user.service"; // services const fileService = new FileService(); @@ -78,6 +76,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { ? () => fetchProjectPages(workspaceSlug.toString(), projectId.toString()) : null ); + // fetching archived pages from API useSWR( workspaceSlug && projectId ? `ALL_ARCHIVED_PAGES_LIST_${projectId}` : null, @@ -86,21 +85,12 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { : null ); - const projectMemberService = new ProjectMemberService(); - - const { data: projectMembers } = useSWR(["projectMembers", workspaceSlug, projectId], async () => { - const members = await projectMemberService.fetchProjectMembers(workspaceSlug, projectId); - const detailedMembers = await Promise.all( - members.map(async (member) => projectMemberService.getProjectMember(workspaceSlug, projectId, member.id)) - ); - console.log("ye toh chal", detailedMembers); - return detailedMembers; - }); - const pageStore = usePage(pageId as string); - // store hooks - const { getMentionSuggestions, mentionHighlights, mentionSuggestions } = useMention({ workspaceSlug, projectId }); + const { mentionHighlights, mentionSuggestions } = useMention({ + workspaceSlug: workspaceSlug as string, + projectId: projectId as string, + }); const { setShowAlert } = useReloadConfirmations(pageStore?.isSubmitting === "submitting"); @@ -317,7 +307,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { last_updated_at: updated_at, last_updated_by: updated_by, }} - mentionSuggestions={getMentionSuggestions(projectMembers)} + mentionSuggestions={mentionSuggestions} mentionHighlights={mentionHighlights} uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)} deleteFile={fileService.getDeleteImageFunction(workspaceId)} diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index a53ae80ab..d9073f4b6 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -6,6 +6,7 @@ import "styles/globals.css"; import "styles/command-pallette.css"; import "styles/nprogress.css"; import "styles/react-datepicker.css"; + // constants import { SITE_TITLE } from "constants/seo-variables"; // mobx store provider