Skip to content

Commit a2baebd

Browse files
committed
Refactor support dropdown to fix errors on build
This refactor is necessary because the error `[cause]: TypeError: Layout_styles_module_default is not a function` occurred. After trying to fix this issue by changing the import for **styles.module.css** to the global **custom.css** file instead, the error `[cause]: ReferenceError: Cannot access 'SupportDropdownMenu' before initialization` occurred. This refactor resolves those issues by ensuring that the support dropdown menu component is initialized first before the Layout component is built.
1 parent b49c1e6 commit a2baebd

File tree

2 files changed

+75
-70
lines changed

2 files changed

+75
-70
lines changed

src/components/Support/SupportDropdownMenu.tsx

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,44 @@
1-
import React, { useState, useEffect, useRef } from 'react';
2-
import AssistantModal from './AssistantModal'; // Import the AssistantModal component for the chatbot.
3-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; // Import the FontAwesomeIcon component.
4-
import { faChevronDown } from '@fortawesome/free-solid-svg-icons'; // Import the icon.
1+
import React, { useState, useEffect, useRef, lazy, Suspense, MouseEvent } from 'react';
2+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3+
import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
54
import { useDoc } from '@docusaurus/plugin-content-docs/client';
6-
import { useLocation } from "@docusaurus/router"; // Import for location detection.
5+
import { useLocation } from "@docusaurus/router";
6+
7+
// Lazy-load AssistantModal
8+
const AssistantModal = lazy(() => import('./AssistantModal'));
79

810
const SupportDropdownMenu: React.FC = () => {
9-
const [isOpen, setIsOpen] = useState(false); // For dropdown visibility
10-
const [isModalOpen, setIsModalOpen] = useState(false); // For modal visibility
11-
const [storedUrl, setStoredUrl] = useState<string | null>(null); // For storing the URL
12-
const dropdownRef = useRef<HTMLDivElement>(null);
11+
const [isOpen, setIsOpen] = useState<boolean>(false);
12+
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
13+
const [storedUrl, setStoredUrl] = useState<string | null>(null);
14+
const dropdownRef = useRef<HTMLDivElement | null>(null);
1315
const location = useLocation();
1416

1517
// Get document metadata from Docusaurus.
1618
const { metadata } = useDoc();
17-
const docTitle = metadata?.title || "Issue with documentation page"; // Use document title or fallback.
19+
const docTitle: string = metadata?.title || "Issue with documentation page";
1820

1921
// Detect the language based on the URL path.
20-
const isJapanese = location.pathname.startsWith("/ja-jp");
22+
const isJapanese: boolean = location.pathname.startsWith("/ja-jp");
2123

2224
useEffect(() => {
23-
// Store the current URL in localStorage when the component first mounts.
24-
const currentUrl = `https://scalardb.scalar-labs.com${location.pathname}`;
25-
localStorage.setItem("currentUrl", currentUrl);
26-
27-
// Retrieve stored URL (if available).
28-
const savedUrl = localStorage.getItem("currentUrl");
29-
if (savedUrl) {
30-
setStoredUrl(savedUrl);
25+
if (typeof window !== "undefined") {
26+
const currentUrl = `https://scalardb.scalar-labs.com${location.pathname}`;
27+
localStorage.setItem("currentUrl", currentUrl);
28+
29+
const savedUrl = localStorage.getItem("currentUrl");
30+
if (savedUrl) {
31+
setStoredUrl(savedUrl);
32+
}
3133
}
3234
}, [location]);
3335

3436
const toggleDropdown = () => {
3537
setIsOpen((prev) => !prev);
3638
};
3739

38-
const openModal = (event: React.MouseEvent) => {
39-
event.preventDefault(); // Prevent default anchor behavior.
40+
const openModal = (event: MouseEvent<HTMLAnchorElement>) => {
41+
event.preventDefault();
4042
setIsModalOpen(true);
4143
setIsOpen(false);
4244
};
@@ -46,23 +48,23 @@ const SupportDropdownMenu: React.FC = () => {
4648
};
4749

4850
const handleSupportClick = () => {
49-
// Get the stored URL or fall back to the current URL.
50-
const finalUrl = storedUrl || `https://scalardb.scalar-labs.com${location.pathname}`;
51-
const reportUrl = `https://support.scalar-labs.com/hc/ja/requests/new?ticket_form_id=8641483507983&tf_11847415366927=${encodeURIComponent(finalUrl)}`;
51+
if (typeof window !== "undefined") {
52+
const finalUrl = storedUrl || `https://scalardb.scalar-labs.com${location.pathname}`;
53+
const reportUrl = `https://support.scalar-labs.com/hc/ja/requests/new?ticket_form_id=8641483507983&tf_11847415366927=${encodeURIComponent(finalUrl)}`;
5254

53-
// Open the support link in a new tab.
54-
window.open(reportUrl, "_blank");
55+
window.open(reportUrl, "_blank");
56+
}
5557
};
5658

57-
// Generate GitHub issue URL dynamically.
58-
const repoUrl = "https://github.com/scalar-labs/docs-scalardb/issues/new";
59-
const issueTitle = encodeURIComponent(
60-
isJapanese ? `フィードバック: \`${docTitle}\` ページ` : `Feedback: \`${docTitle}\` page`
61-
);
59+
const githubIssueUrl: string = typeof window !== "undefined" ? (() => {
60+
const repoUrl = "https://github.com/scalar-labs/docs-scalardb/issues/new";
61+
const issueTitle = encodeURIComponent(
62+
isJapanese ? `フィードバック: \`${docTitle}\` ページ` : `Feedback: \`${docTitle}\` page`
63+
);
6264

63-
const issueBody = encodeURIComponent(
64-
isJapanese
65-
? `**ドキュメントページの URL:** ${window.location.href.replace(/#.*$/, '')}
65+
const issueBody = encodeURIComponent(
66+
isJapanese
67+
? `**ドキュメントページの URL:** ${window.location.href.replace(/#.*$/, '')}
6668
6769
## 期待される動作
6870
@@ -80,7 +82,7 @@ const SupportDropdownMenu: React.FC = () => {
8082
8183
該当する場合は、スクリーンショットを添付してください。
8284
`
83-
: `**Documentation page URL:** ${window.location.href.replace(/#.*$/, '')}
85+
: `**Documentation page URL:** ${window.location.href.replace(/#.*$/, '')}
8486
8587
## Expected behavior
8688
@@ -98,13 +100,13 @@ If the issue is reproducible, please list the steps to reproduce it.
98100
99101
If applicable, add screenshots to help explain your problem.
100102
`
101-
);
103+
);
102104

103-
const githubIssueUrl = `${repoUrl}?title=${issueTitle}&body=${issueBody}&labels=documentation`;
105+
return `${repoUrl}?title=${issueTitle}&body=${issueBody}&labels=documentation`;
106+
})() : "#";
104107

105-
// Close dropdown when clicking outside of it.
106108
useEffect(() => {
107-
function handleClickOutside(event: MouseEvent) {
109+
function handleClickOutside(event: MouseEvent | Event) {
108110
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
109111
setIsOpen(false);
110112
}
@@ -151,7 +153,11 @@ If applicable, add screenshots to help explain your problem.
151153
</div>
152154
)}
153155

154-
{isModalOpen && <AssistantModal isOpen={isModalOpen} onClose={closeModal} />}
156+
{isModalOpen && (
157+
<Suspense fallback={<div>Loading...</div>}>
158+
<AssistantModal isOpen={isModalOpen} onClose={closeModal} />
159+
</Suspense>
160+
)}
155161
</div>
156162
);
157163
};

src/theme/DocItem/Layout/index.tsx

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import React, {type ReactNode} from 'react';
1+
import SupportDropdownMenu from '../../../components/Support/SupportDropdownMenu';
2+
import React from 'react';
23
import clsx from 'clsx';
3-
import {useWindowSize} from '@docusaurus/theme-common';
4-
import {useDoc} from '@docusaurus/plugin-content-docs/client';
4+
import { useWindowSize } from '@docusaurus/theme-common';
5+
import { useDoc } from '@docusaurus/plugin-content-docs/client';
56
import DocItemPaginator from '@theme/DocItem/Paginator';
67
import DocVersionBanner from '@theme/DocVersionBanner';
78
import DocVersionBadge from '@theme/DocVersionBadge';
@@ -11,40 +12,41 @@ import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop';
1112
import DocItemContent from '@theme/DocItem/Content';
1213
import DocBreadcrumbs from '@theme/DocBreadcrumbs';
1314
import ContentVisibility from '@theme/ContentVisibility';
14-
import type {Props} from '@theme/DocItem/Layout';
15-
import SupportDropdownMenu from '../../../components/Support/SupportDropdownMenu'; // Import the support dropdown component.
1615

1716
import styles from './styles.module.css';
1817

19-
/**
20-
* Decide if the ToC should be rendered, on mobile or desktop viewports.
21-
*/
22-
function useDocTOC() {
23-
const {frontMatter, toc} = useDoc();
24-
const windowSize = useWindowSize();
18+
// Define the type for the useDocTOC return value.
19+
interface DocTOC {
20+
hidden: boolean;
21+
mobile?: JSX.Element;
22+
desktop?: JSX.Element;
23+
}
2524

25+
// Type for the DocItemLayout props
26+
interface DocItemLayoutProps {
27+
children: React.ReactNode;
28+
}
29+
30+
// Hook to handle the Table of Contents visibility and rendering
31+
function useDocTOC(): DocTOC {
32+
const { frontMatter, toc } = useDoc();
33+
const windowSize = useWindowSize();
2634
const hidden = frontMatter.hide_table_of_contents;
2735
const canRender = !hidden && toc.length > 0;
2836

29-
const mobile = canRender ? <DocItemTOCMobile /> : undefined;
30-
31-
const desktop =
32-
canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? (
33-
<DocItemTOCDesktop />
34-
) : undefined;
35-
3637
return {
3738
hidden,
38-
mobile,
39-
desktop,
39+
mobile: canRender ? <DocItemTOCMobile /> : undefined,
40+
desktop: canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? <DocItemTOCDesktop /> : undefined,
4041
};
4142
}
4243

43-
export default function DocItemLayout({children}: Props): ReactNode {
44+
// DocItemLayout component
45+
const DocItemLayout: React.FC<DocItemLayoutProps> = ({ children }) => {
4446
const docTOC = useDocTOC();
45-
const {metadata, frontMatter} = useDoc(); // Get the front-matter metadata to check for the `hide_table_of_contents` configuration.
46-
const hideTOC = frontMatter.hide_table_of_contents; // Check if the ToC is hidden.
47-
const windowSize = useWindowSize(); // Get the current window size.
47+
const { metadata, frontMatter } = useDoc();
48+
const hideTOC = frontMatter.hide_table_of_contents;
49+
const windowSize = useWindowSize();
4850

4951
return (
5052
<div className="row">
@@ -55,7 +57,6 @@ export default function DocItemLayout({children}: Props): ReactNode {
5557
<article>
5658
<DocBreadcrumbs />
5759
<DocVersionBadge />
58-
{/* Show the Support button on mobile. */}
5960
{windowSize === 'mobile' && (
6061
<div style={{ display: 'flex', justifyContent: 'left', marginBottom: '1rem' }}>
6162
<SupportDropdownMenu />
@@ -69,20 +70,18 @@ export default function DocItemLayout({children}: Props): ReactNode {
6970
</div>
7071
</div>
7172

72-
{/* Ensure the right column always exists, even if there is no ToC. */}
7373
{!hideTOC && windowSize !== 'mobile' && (
7474
<div className="col col--3" style={{ position: "relative" }}>
75-
{/* Add a wrapper div to make the support dropdown and ToC sticky. */}
7675
<div style={{ position: "sticky", top: "80px", zIndex: 1 }}>
77-
{/* Add the support dropdown above the ToC on desktop. */}
7876
<div style={{ display: 'flex', justifyContent: 'flex-start', padding: '0px 17px', right: '0' }}>
7977
<SupportDropdownMenu />
8078
</div>
81-
{/* Render the ToC if one is available. */}
8279
{docTOC.desktop}
8380
</div>
8481
</div>
8582
)}
8683
</div>
8784
);
88-
}
85+
};
86+
87+
export default DocItemLayout;

0 commit comments

Comments
 (0)