From fd68459236eb09f32057f1d81ac736a4760df92e Mon Sep 17 00:00:00 2001 From: Claire Peng Date: Mon, 25 Aug 2025 16:03:27 +0100 Subject: [PATCH 01/27] useAsModal: delete --unused --- client/components/useAsModal.jsx | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 client/components/useAsModal.jsx diff --git a/client/components/useAsModal.jsx b/client/components/useAsModal.jsx deleted file mode 100644 index 1ea8d71aa7..0000000000 --- a/client/components/useAsModal.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { useModalBehavior } from '../modules/IDE/hooks/custom-hooks'; - -const BackgroundOverlay = styled.div` - position: fixed; - z-index: 2; - width: 100% !important; - height: 100% !important; - - background: black; - opacity: 0.3; -`; - -export default (Element, hasOverlay = false) => { - const [visible, toggle, setRef] = useModalBehavior(); - - const wrapper = () => - visible && ( -
- {hasOverlay && } -
- {typeof Element === 'function' ? Element(toggle) : Element} -
-
- ); - - return [toggle, wrapper]; -}; From 554a2f0c9a15c8d1e7b5108a33dd3845a0766ee7 Mon Sep 17 00:00:00 2001 From: Claire Peng Date: Mon, 25 Aug 2025 16:04:25 +0100 Subject: [PATCH 02/27] RootPage: update to tsx --no-verify --- client/components/{RootPage.jsx => RootPage.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/components/{RootPage.jsx => RootPage.tsx} (100%) diff --git a/client/components/RootPage.jsx b/client/components/RootPage.tsx similarity index 100% rename from client/components/RootPage.jsx rename to client/components/RootPage.tsx From 3120c79bbaac30dfb80afcca0937701594b5911e Mon Sep 17 00:00:00 2001 From: Claire Peng Date: Mon, 25 Aug 2025 16:05:59 +0100 Subject: [PATCH 03/27] RootPage: add interface and update to named export --- client/components/RootPage.tsx | 8 +++++--- client/modules/About/pages/About.jsx | 2 +- client/modules/IDE/pages/FullView.jsx | 2 +- client/modules/IDE/pages/IDEView.jsx | 2 +- client/modules/Legal/pages/Legal.jsx | 2 +- client/modules/User/pages/CollectionView.jsx | 2 +- client/modules/User/pages/DashboardView.jsx | 2 +- client/modules/User/pages/EmailVerificationView.jsx | 2 +- client/modules/User/pages/LoginView.jsx | 2 +- client/modules/User/pages/NewPasswordView.jsx | 2 +- client/modules/User/pages/ResetPasswordView.jsx | 2 +- client/modules/User/pages/SignupView.jsx | 2 +- 12 files changed, 16 insertions(+), 14 deletions(-) diff --git a/client/components/RootPage.tsx b/client/components/RootPage.tsx index 7cb3b35cc4..24e35b0dc2 100644 --- a/client/components/RootPage.tsx +++ b/client/components/RootPage.tsx @@ -1,7 +1,11 @@ import styled from 'styled-components'; import { prop } from '../theme'; -const RootPage = styled.div` +interface RootPageProps { + fixedHeight?: string; +} + +export const RootPage = styled.div` min-height: 100vh; height: ${({ fixedHeight }) => fixedHeight || '100vh'}; display: flex; @@ -21,5 +25,3 @@ const RootPage = styled.div` } } `; - -export default RootPage; diff --git a/client/modules/About/pages/About.jsx b/client/modules/About/pages/About.jsx index 5690aba0a0..ab069f5812 100644 --- a/client/modules/About/pages/About.jsx +++ b/client/modules/About/pages/About.jsx @@ -21,7 +21,7 @@ import { import { ContactSectionLinks, AboutSectionInfo } from '../statics/aboutData'; import Nav from '../../IDE/components/Header/Nav'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; import packageData from '../../../../package.json'; import HeartIcon from '../../../images/heart.svg'; diff --git a/client/modules/IDE/pages/FullView.jsx b/client/modules/IDE/pages/FullView.jsx index 31f58a7df3..ba2f50c573 100644 --- a/client/modules/IDE/pages/FullView.jsx +++ b/client/modules/IDE/pages/FullView.jsx @@ -12,7 +12,7 @@ import { MessageTypes } from '../../../utils/dispatcher'; import useInterval from '../hooks/useInterval'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; function FullView() { const dispatch = useDispatch(); diff --git a/client/modules/IDE/pages/IDEView.jsx b/client/modules/IDE/pages/IDEView.jsx index 8f253c67d7..f3d869937b 100644 --- a/client/modules/IDE/pages/IDEView.jsx +++ b/client/modules/IDE/pages/IDEView.jsx @@ -16,7 +16,7 @@ import { getProject } from '../actions/project'; import { getIsUserOwner } from '../selectors/users'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; import Header from '../components/Header'; import FloatingActionButton from '../components/FloatingActionButton'; import Editor from '../components/Editor'; diff --git a/client/modules/Legal/pages/Legal.jsx b/client/modules/Legal/pages/Legal.jsx index 24f8920fe3..4ba5cb5bbc 100644 --- a/client/modules/Legal/pages/Legal.jsx +++ b/client/modules/Legal/pages/Legal.jsx @@ -5,7 +5,7 @@ import Helmet from 'react-helmet'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import { RouterTab } from '../../../common/RouterTab'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; import { remSize } from '../../../theme'; import Loader from '../../App/components/loader'; import Nav from '../../IDE/components/Header/Nav'; diff --git a/client/modules/User/pages/CollectionView.jsx b/client/modules/User/pages/CollectionView.jsx index e52eb2c279..8207388086 100644 --- a/client/modules/User/pages/CollectionView.jsx +++ b/client/modules/User/pages/CollectionView.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { useParams } from 'react-router-dom'; import Nav from '../../IDE/components/Header/Nav'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; import Collection from '../components/Collection'; const CollectionView = () => { diff --git a/client/modules/User/pages/DashboardView.jsx b/client/modules/User/pages/DashboardView.jsx index 611fef9f5a..1626d0d369 100644 --- a/client/modules/User/pages/DashboardView.jsx +++ b/client/modules/User/pages/DashboardView.jsx @@ -10,7 +10,7 @@ import AssetList from '../../IDE/components/AssetList'; import AssetSize from '../../IDE/components/AssetSize'; import CollectionList from '../../IDE/components/CollectionList'; import SketchList from '../../IDE/components/SketchList'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; import { newProject } from '../../IDE/actions/project'; import { CollectionSearchbar, diff --git a/client/modules/User/pages/EmailVerificationView.jsx b/client/modules/User/pages/EmailVerificationView.jsx index 7ad9d2fa79..d21d2446b9 100644 --- a/client/modules/User/pages/EmailVerificationView.jsx +++ b/client/modules/User/pages/EmailVerificationView.jsx @@ -4,7 +4,7 @@ import { useLocation, useHistory } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { verifyEmailConfirmation } from '../actions'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; import Nav from '../../IDE/components/Header/Nav'; const EmailVerificationView = () => { diff --git a/client/modules/User/pages/LoginView.jsx b/client/modules/User/pages/LoginView.jsx index 1847c84b50..b931c50ea8 100644 --- a/client/modules/User/pages/LoginView.jsx +++ b/client/modules/User/pages/LoginView.jsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'; import LoginForm from '../components/LoginForm'; import SocialAuthButton from '../components/SocialAuthButton'; import Nav from '../../IDE/components/Header/Nav'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; function LoginView() { const { t } = useTranslation(); diff --git a/client/modules/User/pages/NewPasswordView.jsx b/client/modules/User/pages/NewPasswordView.jsx index cb9d7cbe1d..2bc310e6a3 100644 --- a/client/modules/User/pages/NewPasswordView.jsx +++ b/client/modules/User/pages/NewPasswordView.jsx @@ -7,7 +7,7 @@ import { useParams } from 'react-router-dom'; import NewPasswordForm from '../components/NewPasswordForm'; import { validateResetPasswordToken } from '../actions'; import Nav from '../../IDE/components/Header/Nav'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; function NewPasswordView() { const { t } = useTranslation(); diff --git a/client/modules/User/pages/ResetPasswordView.jsx b/client/modules/User/pages/ResetPasswordView.jsx index 9188a5e2c8..e744311b7c 100644 --- a/client/modules/User/pages/ResetPasswordView.jsx +++ b/client/modules/User/pages/ResetPasswordView.jsx @@ -5,7 +5,7 @@ import { useSelector } from 'react-redux'; import { Helmet } from 'react-helmet'; import { useTranslation } from 'react-i18next'; import ResetPasswordForm from '../components/ResetPasswordForm'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; import Nav from '../../IDE/components/Header/Nav'; function ResetPasswordView() { diff --git a/client/modules/User/pages/SignupView.jsx b/client/modules/User/pages/SignupView.jsx index 6b1e1fff51..16e038c6e0 100644 --- a/client/modules/User/pages/SignupView.jsx +++ b/client/modules/User/pages/SignupView.jsx @@ -5,7 +5,7 @@ import { useTranslation, Trans } from 'react-i18next'; import SignupForm from '../components/SignupForm'; import SocialAuthButton from '../components/SocialAuthButton'; import Nav from '../../IDE/components/Header/Nav'; -import RootPage from '../../../components/RootPage'; +import { RootPage } from '../../../components/RootPage'; function SignupView() { const { t } = useTranslation(); From 06ca7b2c1a5fc8d7c5c253b3dd8f2e14b572832a Mon Sep 17 00:00:00 2001 From: Claire Peng Date: Mon, 25 Aug 2025 16:09:32 +0100 Subject: [PATCH 04/27] PreviewNav: update to tsx --no-verify --- client/components/{PreviewNav.jsx => PreviewNav.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/components/{PreviewNav.jsx => PreviewNav.tsx} (100%) diff --git a/client/components/PreviewNav.jsx b/client/components/PreviewNav.tsx similarity index 100% rename from client/components/PreviewNav.jsx rename to client/components/PreviewNav.tsx From 2e23c923b9a282a8fde611ce882f43782a30d339 Mon Sep 17 00:00:00 2001 From: Claire Peng Date: Mon, 25 Aug 2025 16:14:44 +0100 Subject: [PATCH 05/27] PreviewNav: add test, add interface and update to named export. Add d.ts for svg files --- client/components/PreviewNav.test.tsx | 54 +++++++++++++++++++++++++++ client/components/PreviewNav.tsx | 43 +++++++++++---------- client/custom.d.ts | 8 ++++ client/modules/IDE/pages/FullView.jsx | 2 +- 4 files changed, 86 insertions(+), 21 deletions(-) create mode 100644 client/components/PreviewNav.test.tsx create mode 100644 client/custom.d.ts diff --git a/client/components/PreviewNav.test.tsx b/client/components/PreviewNav.test.tsx new file mode 100644 index 0000000000..f5566cfa8c --- /dev/null +++ b/client/components/PreviewNav.test.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { render, screen } from '../test-utils'; +import { PreviewNav } from './PreviewNav'; + +describe('PreviewNav', () => { + const owner = { username: 'alice' }; + const project = { id: '123', name: 'My Project' }; + + test('renders with correct links and icons using provided data-testid attributes', () => { + render(); + + // Logo link to /alice/sketches + const iconLinkUserSketches = screen.getByTestId('icon-link_user-sketches'); + expect(iconLinkUserSketches).toHaveAttribute( + 'href', + `/${owner.username}/sketches` + ); + + // p5js logo icon presence + const iconP5Logo = screen.getByTestId('icon_p5-logo'); + expect(iconP5Logo).toBeInTheDocument(); + + // Current project link to /alice/sketches/123 + const linkCurrentProject = screen.getByTestId('link_current-project'); + expect(linkCurrentProject).toHaveAttribute( + 'href', + `/${owner.username}/sketches/${project.id}` + ); + expect(linkCurrentProject).toHaveTextContent(project.name); + + // Owner username link to /alice/sketches + const linkUserSketches = screen.getByTestId('link_user-sketches'); + expect(linkUserSketches).toHaveAttribute( + 'href', + `/${owner.username}/sketches` + ); + expect(linkUserSketches).toHaveTextContent(owner.username); + + // Edit project code link to /alice/sketches/123 + const linkProjectCode = screen.getByTestId('link_project-code'); + expect(linkProjectCode).toHaveAttribute( + 'href', + `/${owner.username}/sketches/${project.id}` + ); + + // Code icon presence + const iconCode = screen.getByTestId('icon_code'); + expect(iconCode).toBeInTheDocument(); + + // Check nav container presence + const nav = screen.getByTestId('preview-nav'); + expect(nav).toBeInTheDocument(); + }); +}); diff --git a/client/components/PreviewNav.tsx b/client/components/PreviewNav.tsx index f66476d92b..65f429db49 100644 --- a/client/components/PreviewNav.tsx +++ b/client/components/PreviewNav.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React from 'react'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; @@ -6,56 +5,60 @@ import { useTranslation } from 'react-i18next'; import LogoIcon from '../images/p5js-logo-small.svg'; import CodeIcon from '../images/code.svg'; -const PreviewNav = ({ owner, project }) => { +interface PreviewNavProps { + owner: { username: string }; + project: { name: string; id: string }; +} + +export const PreviewNav = ({ owner, project }: PreviewNavProps) => { const { t } = useTranslation(); return ( -