({
toolId,
toolTitle,
discussionPostId,
}: ToolDiscussionProps)
| 65 | ); |
| 66 | |
| 67 | export const ToolDiscussion = ({ |
| 68 | toolId, |
| 69 | toolTitle, |
| 70 | discussionPostId, |
| 71 | }: ToolDiscussionProps): ReactElement => { |
| 72 | const { isLoggedIn, showLogin } = useAuthContext(); |
| 73 | const { isVerified, isLoading: isCompaniesLoading } = useUserCompaniesQuery(); |
| 74 | const { displayToast } = useToastNotification(); |
| 75 | const commentRef = useRef<NewCommentRef>(null); |
| 76 | // Set once the mutation below creates the post, so the composer can be |
| 77 | // opened as soon as it finishes loading. |
| 78 | const shouldOpenOnLoad = useRef(false); |
| 79 | const [postId, setPostId] = useState<string | null>(discussionPostId); |
| 80 | |
| 81 | // The SSG prop can still deliver the id after the client already resolved |
| 82 | // one from `initToolDiscussion` (ISR revalidation); never downgrade it. |
| 83 | useEffect(() => { |
| 84 | setPostId((current) => current ?? discussionPostId); |
| 85 | }, [discussionPostId]); |
| 86 | |
| 87 | const { post, isLoading } = usePostById({ id: postId ?? '' }); |
| 88 | |
| 89 | useEffect(() => { |
| 90 | if (shouldOpenOnLoad.current && post) { |
| 91 | shouldOpenOnLoad.current = false; |
| 92 | commentRef.current?.onShowInput(Origin.ToolPage); |
| 93 | } |
| 94 | }, [post]); |
| 95 | |
| 96 | const { mutate: startDiscussion, isPending: isStarting } = useMutation({ |
| 97 | mutationFn: () => initToolDiscussion(toolId), |
| 98 | onSuccess: (id) => { |
| 99 | shouldOpenOnLoad.current = true; |
| 100 | setPostId(id); |
| 101 | }, |
| 102 | onError: (error: unknown) => { |
| 103 | const message = (error as GraphQLError)?.response?.errors?.[0]?.message; |
| 104 | displayToast(message ?? 'Failed to start the discussion'); |
| 105 | }, |
| 106 | }); |
| 107 | |
| 108 | // Logged in but no verified work email: the server rejects the mutation |
| 109 | // anyway, so the composer is replaced before the user ever gets there. |
| 110 | // While the companies query is still resolving, treat replies as blocked |
| 111 | // too rather than briefly allowing a composer that then gets pulled away. |
| 112 | const isCheckingVerification = isLoggedIn && isCompaniesLoading; |
| 113 | const isGated = isLoggedIn && !isCompaniesLoading && !isVerified; |
| 114 | const canReply = !isLoggedIn || (!isCompaniesLoading && isVerified); |
| 115 | |
| 116 | const handleReplyBlocked = useCallback(() => { |
| 117 | displayToast(VERIFIED_GATE_MESSAGE); |
| 118 | }, [displayToast]); |
| 119 | |
| 120 | const handleStart = (): void => { |
| 121 | if (isStarting) { |
| 122 | return; |
| 123 | } |
| 124 |
nothing calls this directly
no test coverage detected