diff --git a/frontend/src/components/ChangeWarning/index.jsx b/frontend/src/components/ChangeWarning/index.jsx index a0fe14c1..42b211ba 100644 --- a/frontend/src/components/ChangeWarning/index.jsx +++ b/frontend/src/components/ChangeWarning/index.jsx @@ -6,44 +6,42 @@ export default function ChangeWarningModal({ onConfirm, }) { return ( - -
-
-
-
- -

Warning

-
-
-
-

- {warningText} -
-
- Are you sure you want to proceed? -

-
- -
- - +
+
+
+
+ +

Warning

+
+

+ {warningText} +
+
+ Are you sure you want to proceed? +

+
+ +
+ + +
-
+ ); } diff --git a/frontend/src/components/ModalWrapper/index.jsx b/frontend/src/components/ModalWrapper/index.jsx new file mode 100644 index 00000000..37041f63 --- /dev/null +++ b/frontend/src/components/ModalWrapper/index.jsx @@ -0,0 +1,9 @@ +export default function ModalWrapper({ children, isOpen }) { + if (!isOpen) return null; + + return ( +
+ {children} +
+ ); +} diff --git a/frontend/src/components/UserMenu/index.jsx b/frontend/src/components/UserMenu/index.jsx index 61e111da..e6f3c7cf 100644 --- a/frontend/src/components/UserMenu/index.jsx +++ b/frontend/src/components/UserMenu/index.jsx @@ -193,7 +193,7 @@ function AccountModal({ user, hideModal }) { return (
diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/Citation/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/Citation/index.jsx index 9af36fc5..697c5521 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/Citation/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/Citation/index.jsx @@ -1,9 +1,10 @@ -import { memo, useState, useEffect, useRef } from "react"; +import { memo, useState } from "react"; import { X } from "@phosphor-icons/react"; import { v4 } from "uuid"; import { decode as HTMLDecode } from "he"; import { CaretRight, FileText } from "@phosphor-icons/react"; import truncate from "truncate"; +import ModalWrapper from "@/components/ModalWrapper"; function combineLikeSources(sources) { const combined = {}; @@ -98,27 +99,10 @@ function SkeletonLine() { function CitationDetailModal({ source, onClose }) { const { references, title, text } = source; - const dialogRef = useRef(null); - - useEffect(() => { - if (source && dialogRef.current) { - dialogRef.current.showModal(); - } - }, [source]); - - const handleModalClose = () => { - if (dialogRef.current) { - dialogRef.current.close(); - } - onClose(); - }; return ( - -
+ +

{truncate(title, 45)} @@ -129,7 +113,7 @@ function CitationDetailModal({ source, onClose }) {

)}

-
+ ); } diff --git a/frontend/src/components/WorkspaceChat/index.jsx b/frontend/src/components/WorkspaceChat/index.jsx index 30bd494f..cbe7dbdd 100644 --- a/frontend/src/components/WorkspaceChat/index.jsx +++ b/frontend/src/components/WorkspaceChat/index.jsx @@ -3,6 +3,7 @@ import Workspace from "@/models/workspace"; import LoadingChat from "./LoadingChat"; import ChatContainer from "./ChatContainer"; import paths from "@/utils/paths"; +import ModalWrapper from "../ModalWrapper"; export default function WorkspaceChat({ loading, workspace }) { const [history, setHistory] = useState([]); @@ -28,11 +29,7 @@ export default function WorkspaceChat({ loading, workspace }) { return ( <> {loading === false && !workspace && ( - +

@@ -52,7 +49,7 @@ export default function WorkspaceChat({ loading, workspace }) {

- + )} diff --git a/frontend/src/hooks/useModal.js b/frontend/src/hooks/useModal.js new file mode 100644 index 00000000..854b5d4a --- /dev/null +++ b/frontend/src/hooks/useModal.js @@ -0,0 +1,10 @@ +import { useState } from "react"; + +export function useModal() { + const [isOpen, setIsOpen] = useState(false); + + const openModal = () => setIsOpen(true); + const closeModal = () => setIsOpen(false); + + return { isOpen, openModal, closeModal }; +} diff --git a/frontend/src/pages/Admin/Invitations/NewInviteModal/index.jsx b/frontend/src/pages/Admin/Invitations/NewInviteModal/index.jsx index 54ae7e07..3aef87a6 100644 --- a/frontend/src/pages/Admin/Invitations/NewInviteModal/index.jsx +++ b/frontend/src/pages/Admin/Invitations/NewInviteModal/index.jsx @@ -2,14 +2,7 @@ import React, { useEffect, useState } from "react"; import { X } from "@phosphor-icons/react"; import Admin from "@/models/admin"; -const DIALOG_ID = `new-invite-modal`; - -function hideModal() { - document.getElementById(DIALOG_ID)?.close(); -} - -export const NewInviteModalId = DIALOG_ID; -export default function NewInviteModal() { +export default function NewInviteModal({ closeModal }) { const [invite, setInvite] = useState(null); const [error, setError] = useState(null); const [copied, setCopied] = useState(false); @@ -39,74 +32,70 @@ export default function NewInviteModal() { }, [copied]); return ( - -
-
-
-

- Create new invite -

- -
-
-
-
- {error && ( -

Error: {error}

- )} - {invite && ( - - )} -

- After creation you will be able to copy the invite and send it - to a new user where they can create an account as a default - user. -

-
-
-
- {!invite ? ( - <> - - - - ) : ( - - )} -
-
+
+
+
+

+ Create new invite +

+
+
+
+
+ {error &&

Error: {error}

} + {invite && ( + + )} +

+ After creation you will be able to copy the invite and send it + to a new user where they can create an account as a default + user. +

+
+
+
+ {!invite ? ( + <> + + + + ) : ( + + )} +
+
-
+
); } diff --git a/frontend/src/pages/Admin/Invitations/index.jsx b/frontend/src/pages/Admin/Invitations/index.jsx index cf5b38d3..94b07f33 100644 --- a/frontend/src/pages/Admin/Invitations/index.jsx +++ b/frontend/src/pages/Admin/Invitations/index.jsx @@ -7,9 +7,12 @@ import { EnvelopeSimple } from "@phosphor-icons/react"; import usePrefersDarkMode from "@/hooks/usePrefersDarkMode"; import Admin from "@/models/admin"; import InviteRow from "./InviteRow"; -import NewInviteModal, { NewInviteModalId } from "./NewInviteModal"; +import NewInviteModal from "./NewInviteModal"; +import { useModal } from "@/hooks/useModal"; +import ModalWrapper from "@/components/ModalWrapper"; export default function AdminInvites() { + const { isOpen, openModal, closeModal } = useModal(); return (
{!isMobile && } @@ -23,9 +26,7 @@ export default function AdminInvites() {

Invitations

- + + +
); diff --git a/frontend/src/pages/Admin/Users/NewUserModal/index.jsx b/frontend/src/pages/Admin/Users/NewUserModal/index.jsx index d8c26d1e..9a7e2a6d 100644 --- a/frontend/src/pages/Admin/Users/NewUserModal/index.jsx +++ b/frontend/src/pages/Admin/Users/NewUserModal/index.jsx @@ -4,14 +4,7 @@ import Admin from "@/models/admin"; import { userFromStorage } from "@/utils/request"; import { RoleHintDisplay } from ".."; -const DIALOG_ID = `new-user-modal`; - -function hideModal() { - document.getElementById(DIALOG_ID)?.close(); -} - -export const NewUserModalId = DIALOG_ID; -export default function NewUserModal() { +export default function NewUserModal({ closeModal }) { const [error, setError] = useState(null); const [role, setRole] = useState("default"); const handleCreate = async (e) => { @@ -28,107 +21,103 @@ export default function NewUserModal() { const user = userFromStorage(); return ( - -
-
-
-

- Add user to instance -

+
+
+
+

+ Add user to instance +

+ +
+
+
+
+
+ + +
+
+ + +
+
+ + + +
+ {error &&

Error: {error}

} +

+ After creating a user they will need to login with their initial + login to get access. +

+
+
+
+
- -
-
-
- - -
-
- - -
-
- - - -
- {error && ( -

Error: {error}

- )} -

- After creating a user they will need to login with their - initial login to get access. -

-
-
-
- - -
-
-
+
-
+ ); } diff --git a/frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx b/frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx index 4c3c2686..959b04b4 100644 --- a/frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx +++ b/frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx @@ -3,16 +3,10 @@ import { X } from "@phosphor-icons/react"; import Admin from "@/models/admin"; import { RoleHintDisplay } from "../.."; -export const EditUserModalId = (user) => `edit-user-${user.id}-modal`; - -export default function EditUserModal({ currentUser, user }) { +export default function EditUserModal({ currentUser, user, closeModal }) { const [role, setRole] = useState(user.role); const [error, setError] = useState(null); - const hideModal = () => { - document.getElementById(EditUserModalId(user)).close(); - }; - const handleUpdate = async (e) => { setError(null); e.preventDefault(); @@ -28,103 +22,99 @@ export default function EditUserModal({ currentUser, user }) { }; return ( - -
-
-
-

- Edit {user.username} -

+
+
+
+

+ Edit {user.username} +

+ +
+
+
+
+
+ + +
+
+ + +
+
+ + + +
+ {error &&

Error: {error}

} +
+
+
+
- -
-
-
- - -
-
- - -
-
- - - -
- {error && ( -

Error: {error}

- )} -
-
-
- - -
-
-
+
-
+ ); } diff --git a/frontend/src/pages/Admin/Users/UserRow/index.jsx b/frontend/src/pages/Admin/Users/UserRow/index.jsx index cd1c4773..c58b8124 100644 --- a/frontend/src/pages/Admin/Users/UserRow/index.jsx +++ b/frontend/src/pages/Admin/Users/UserRow/index.jsx @@ -1,9 +1,11 @@ import { useRef, useState } from "react"; import { titleCase } from "text-case"; import Admin from "@/models/admin"; -import EditUserModal, { EditUserModalId } from "./EditUserModal"; +import EditUserModal from "./EditUserModal"; import { DotsThreeOutline } from "@phosphor-icons/react"; import showToast from "@/utils/toast"; +import { useModal } from "@/hooks/useModal"; +import ModalWrapper from "@/components/ModalWrapper"; const ModMap = { admin: ["admin", "manager", "default"], @@ -15,6 +17,7 @@ export default function UserRow({ currUser, user }) { const rowRef = useRef(null); const canModify = ModMap[currUser?.role || "default"].includes(user.role); const [suspended, setSuspended] = useState(user.suspended === 1); + const { isOpen, openModal, closeModal } = useModal(); const handleSuspend = async () => { if ( !window.confirm( @@ -65,9 +68,7 @@ export default function UserRow({ currUser, user }) { {canModify && ( + +
+
+
+
+ + +
+ {error &&

Error: {error}

} +

+ After creating this workspace only admins will be able to see + it. You can add users after it has been created. +

+
+
+
+
- -
-
-
- - -
- {error && ( -

Error: {error}

- )} -

- After creating this workspace only admins will be able to see - it. You can add users after it has been created. -

-
-
-
- - -
-
- + - + ); } diff --git a/frontend/src/pages/Admin/Workspaces/WorkspaceRow/EditWorkspaceUsersModal/index.jsx b/frontend/src/pages/Admin/Workspaces/WorkspaceRow/EditWorkspaceUsersModal/index.jsx index 052f845b..cd8d5f01 100644 --- a/frontend/src/pages/Admin/Workspaces/WorkspaceRow/EditWorkspaceUsersModal/index.jsx +++ b/frontend/src/pages/Admin/Workspaces/WorkspaceRow/EditWorkspaceUsersModal/index.jsx @@ -6,13 +6,13 @@ import { titleCase } from "text-case"; export const EditWorkspaceUsersModalId = (workspace) => `edit-workspace-${workspace.id}-modal`; -export default function EditWorkspaceUsersModal({ workspace, users }) { +export default function EditWorkspaceUsersModal({ + workspace, + users, + closeModal, +}) { const [error, setError] = useState(null); - const hideModal = () => { - document.getElementById(EditWorkspaceUsersModalId(workspace)).close(); - }; - const handleUpdate = async (e) => { setError(null); e.preventDefault(); @@ -35,122 +35,115 @@ export default function EditWorkspaceUsersModal({ workspace, users }) { }; return ( - -
-
-
-

- Edit {workspace.name} -

+
+
+
+

+ Edit {workspace.name} +

+ +
+
+
+
+ {users + .filter((user) => user.role !== "admin") + .map((user) => { + return ( +
{ + document + .getElementById( + `workspace-${workspace.id}-user-${user.id}` + ) + ?.click(); + }} + > + + +
+ ); + })} +
+ + +
+ {error &&

Error: {error}

} +
+
+
+
- -
-
- {users - .filter((user) => user.role !== "admin") - .map((user) => { - return ( -
{ - document - .getElementById( - `workspace-${workspace.id}-user-${user.id}` - ) - ?.click(); - }} - > - - -
- ); - })} -
- - -
- {error && ( -

Error: {error}

- )} -
-
-
- - -
-
-
+
-
+ ); } diff --git a/frontend/src/pages/Admin/Workspaces/WorkspaceRow/index.jsx b/frontend/src/pages/Admin/Workspaces/WorkspaceRow/index.jsx index 8c896962..e755e185 100644 --- a/frontend/src/pages/Admin/Workspaces/WorkspaceRow/index.jsx +++ b/frontend/src/pages/Admin/Workspaces/WorkspaceRow/index.jsx @@ -1,13 +1,14 @@ import { useRef } from "react"; import Admin from "@/models/admin"; import paths from "@/utils/paths"; -import EditWorkspaceUsersModal, { - EditWorkspaceUsersModalId, -} from "./EditWorkspaceUsersModal"; +import EditWorkspaceUsersModal from "./EditWorkspaceUsersModal"; import { DotsThreeOutline, LinkSimple, Trash } from "@phosphor-icons/react"; +import { useModal } from "@/hooks/useModal"; +import ModalWrapper from "@/components/ModalWrapper"; export default function WorkspaceRow({ workspace, users }) { const rowRef = useRef(null); + const { isOpen, openModal, closeModal } = useModal(); const handleDelete = async () => { if ( !window.confirm( @@ -32,6 +33,7 @@ export default function WorkspaceRow({ workspace, users }) { {workspace.slug} @@ -41,11 +43,7 @@ export default function WorkspaceRow({ workspace, users }) { {workspace.createdAt} - + + + ); } diff --git a/frontend/src/pages/Admin/Workspaces/index.jsx b/frontend/src/pages/Admin/Workspaces/index.jsx index c29c92ac..8ca7410b 100644 --- a/frontend/src/pages/Admin/Workspaces/index.jsx +++ b/frontend/src/pages/Admin/Workspaces/index.jsx @@ -7,9 +7,12 @@ import { BookOpen } from "@phosphor-icons/react"; import usePrefersDarkMode from "@/hooks/usePrefersDarkMode"; import Admin from "@/models/admin"; import WorkspaceRow from "./WorkspaceRow"; -import NewWorkspaceModal, { NewWorkspaceModalId } from "./NewWorkspaceModal"; +import NewWorkspaceModal from "./NewWorkspaceModal"; +import { useModal } from "@/hooks/useModal"; +import ModalWrapper from "@/components/ModalWrapper"; export default function AdminWorkspaces() { + const { isOpen, openModal, closeModal } = useModal(); return (
{!isMobile && } @@ -25,9 +28,7 @@ export default function AdminWorkspaces() { Instance workspaces

- + + + ); diff --git a/frontend/src/pages/GeneralSettings/ApiKeys/NewApiKeyModal/index.jsx b/frontend/src/pages/GeneralSettings/ApiKeys/NewApiKeyModal/index.jsx index a4095ae9..cde8bdbe 100644 --- a/frontend/src/pages/GeneralSettings/ApiKeys/NewApiKeyModal/index.jsx +++ b/frontend/src/pages/GeneralSettings/ApiKeys/NewApiKeyModal/index.jsx @@ -5,14 +5,7 @@ import paths from "@/utils/paths"; import { userFromStorage } from "@/utils/request"; import System from "@/models/system"; -const DIALOG_ID = `new-api-key-modal`; - -function hideModal() { - document.getElementById(DIALOG_ID)?.close(); -} - -export const NewApiKeyModalId = DIALOG_ID; -export default function NewApiKeyModal() { +export default function NewApiKeyModal({ closeModal }) { const [apiKey, setApiKey] = useState(null); const [error, setError] = useState(null); const [copied, setCopied] = useState(false); @@ -43,80 +36,77 @@ export default function NewApiKeyModal() { }, [copied]); return ( - -
-
-
-

- Create new API key -

- -
-
-
-
- {error && ( -

Error: {error}

- )} - {apiKey && ( - - )} -

- Once created the API key can be used to programmatically - access and configure this AnythingLLM instance. -

-
- Read the API documentation → - -
-
-
- {!apiKey ? ( - <> - - - - ) : ( - - )} -
-
+
+
+
+

+ Create new API key +

+
+
+
+
+ {error &&

Error: {error}

} + {apiKey && ( + + )} +

+ Once created the API key can be used to programmatically access + and configure this AnythingLLM instance. +

+ + Read the API documentation → + +
+
+
+ {!apiKey ? ( + <> + + + + ) : ( + + )} +
+
- +
); } diff --git a/frontend/src/pages/GeneralSettings/ApiKeys/index.jsx b/frontend/src/pages/GeneralSettings/ApiKeys/index.jsx index 5ee5fd0a..bf4ac51e 100644 --- a/frontend/src/pages/GeneralSettings/ApiKeys/index.jsx +++ b/frontend/src/pages/GeneralSettings/ApiKeys/index.jsx @@ -6,12 +6,15 @@ import "react-loading-skeleton/dist/skeleton.css"; import { PlusCircle } from "@phosphor-icons/react"; import Admin from "@/models/admin"; import ApiKeyRow from "./ApiKeyRow"; -import NewApiKeyModal, { NewApiKeyModalId } from "./NewApiKeyModal"; +import NewApiKeyModal from "./NewApiKeyModal"; import paths from "@/utils/paths"; import { userFromStorage } from "@/utils/request"; import System from "@/models/system"; +import ModalWrapper from "@/components/ModalWrapper"; +import { useModal } from "@/hooks/useModal"; export default function AdminApiKeys() { + const { isOpen, openModal, closeModal } = useModal(); return (
{!isMobile && } @@ -25,9 +28,7 @@ export default function AdminApiKeys() {

API Keys

- + + +
); diff --git a/frontend/src/pages/GeneralSettings/Chats/ChatRow/index.jsx b/frontend/src/pages/GeneralSettings/Chats/ChatRow/index.jsx index 23fc39d9..3056e765 100644 --- a/frontend/src/pages/GeneralSettings/Chats/ChatRow/index.jsx +++ b/frontend/src/pages/GeneralSettings/Chats/ChatRow/index.jsx @@ -2,9 +2,22 @@ import { useRef } from "react"; import truncate from "truncate"; import { X, Trash } from "@phosphor-icons/react"; import System from "@/models/system"; +import ModalWrapper from "@/components/ModalWrapper"; +import { useModal } from "@/hooks/useModal"; export default function ChatRow({ chat }) { const rowRef = useRef(null); + const { + isOpen: isPromptOpen, + openModal: openPromptModal, + closeModal: closePromptModal, + } = useModal(); + const { + isOpen: isResponseOpen, + openModal: openResponseModal, + closeModal: closeResponseModal, + } = useModal(); + const handleDelete = async () => { if ( !window.confirm( @@ -30,17 +43,13 @@ export default function ChatRow({ chat }) { {chat.workspace?.name} { - document.getElementById(`chat-${chat.id}-prompt`)?.showModal(); - }} + onClick={openPromptModal} className="px-6 py-4 border-transparent cursor-pointer transform transition-transform duration-200 hover:scale-105 hover:shadow-lg" > {truncate(chat.prompt, 40)} { - document.getElementById(`chat-${chat.id}-response`)?.showModal(); - }} + onClick={openResponseModal} className="px-6 py-4 cursor-pointer transform transition-transform duration-200 hover:scale-105 hover:shadow-lg" > {truncate(JSON.parse(chat.response)?.text, 40)} @@ -55,42 +64,38 @@ export default function ChatRow({ chat }) { - - + + + + + + ); } - -function hideModal(modalName) { - document.getElementById(modalName)?.close(); -} - -const TextPreview = ({ text, modalName }) => { +const TextPreview = ({ text, closeModal }) => { return ( - -
-
-
-

Viewing Text

- -
-
-
-              {text}
-            
-
+
+
+
+

Viewing Text

+ +
+
+
+            {text}
+          
-
+ ); }; diff --git a/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx b/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx index ddcb8131..c6c62fef 100644 --- a/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx +++ b/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx @@ -15,6 +15,8 @@ import LocalAiOptions from "@/components/EmbeddingSelection/LocalAiOptions"; import NativeEmbeddingOptions from "@/components/EmbeddingSelection/NativeEmbeddingOptions"; import EmbedderItem from "@/components/EmbeddingSelection/EmbedderItem"; import { MagnifyingGlass } from "@phosphor-icons/react"; +import { useModal } from "@/hooks/useModal"; +import ModalWrapper from "@/components/ModalWrapper"; export default function GeneralEmbeddingPreference() { const [saving, setSaving] = useState(false); @@ -25,6 +27,7 @@ export default function GeneralEmbeddingPreference() { const [searchQuery, setSearchQuery] = useState(""); const [filteredEmbedders, setFilteredEmbedders] = useState([]); const [selectedEmbedder, setSelectedEmbedder] = useState(null); + const { isOpen, openModal, closeModal } = useModal(); const handleSubmit = async (e) => { e.preventDefault(); @@ -33,7 +36,7 @@ export default function GeneralEmbeddingPreference() { hasChanges && hasEmbeddings ) { - document.getElementById("confirmation-modal")?.showModal(); + openModal(); } else { await handleSaveSettings(); } @@ -56,7 +59,7 @@ export default function GeneralEmbeddingPreference() { setHasChanges(false); } setSaving(false); - document.getElementById("confirmation-modal")?.close(); + closeModal(); }; const updateChoice = (selection) => { @@ -116,11 +119,13 @@ export default function GeneralEmbeddingPreference() { return (
- document.getElementById("confirmation-modal")?.close()} - onConfirm={handleSaveSettings} - /> + + + {!isMobile && } {loading ? (
{ async function fetchKeys() { @@ -107,7 +110,7 @@ export default function GeneralVectorDatabase() { const handleSubmit = async (e) => { e.preventDefault(); if (selectedVDB !== settings?.VectorDB && hasChanges && hasEmbeddings) { - document.getElementById("confirmation-modal")?.showModal(); + openModal(); } else { await handleSaveSettings(); } @@ -130,7 +133,7 @@ export default function GeneralVectorDatabase() { setHasChanges(false); } setSaving(false); - document.getElementById("confirmation-modal")?.close(); + closeModal(); }; useEffect(() => { @@ -142,11 +145,13 @@ export default function GeneralVectorDatabase() { return (
- document.getElementById("confirmation-modal")?.close()} - onConfirm={handleSaveSettings} - /> + + + {!isMobile && } {loading ? (
-
-
-
-

- Create a new account -

-
-
-
-
-
- - -
-
- - -
- {error && ( -

Error: {error}

- )} -

- After creating your account you will be able to login with - these credentials and start using workspaces. -

-
-
-
- -
-
+
+
+
+

+ Create a new account +

+
+
+
+
+ + +
+
+ + +
+ {error &&

Error: {error}

} +

+ After creating your account you will be able to login with these + credentials and start using workspaces. +

+
+
+
+ +
+
- +
); } diff --git a/frontend/src/pages/Invite/index.jsx b/frontend/src/pages/Invite/index.jsx index e44ff235..a7522a54 100644 --- a/frontend/src/pages/Invite/index.jsx +++ b/frontend/src/pages/Invite/index.jsx @@ -3,6 +3,7 @@ import { useParams } from "react-router-dom"; import { FullScreenLoader } from "@/components/Preloader"; import Invite from "@/models/invite"; import NewUserModal from "./NewUserModal"; +import ModalWrapper from "@/components/ModalWrapper"; export default function InvitePage() { const { code } = useParams(); @@ -47,7 +48,9 @@ export default function InvitePage() { return (
- + + +
); }