From 77799a587022ebf672aac6795733e08ca70b4f50 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Tue, 28 Sep 2021 20:15:45 +1000 Subject: [PATCH] Refactor IdeHeader to take middle buttons as children --- .../src/components/IdeHeader/IdeHeader.tsx | 324 ++++++++---------- .../src/components/IdeWrapper/IdeWrapper.tsx | 14 +- .../components/ProjectCell/ProjectCell.tsx | 68 ++-- .../ProjectProfile/ProjectProfile.tsx | 14 +- app/web/src/components/TopNav/TopNav.tsx | 31 ++ .../components/UserProfile/UserProfile.tsx | 17 +- app/web/src/pages/DevIdePage/DevIdePage.tsx | 5 +- app/web/src/pages/ProjectPage/ProjectPage.tsx | 15 +- 8 files changed, 231 insertions(+), 257 deletions(-) create mode 100644 app/web/src/components/TopNav/TopNav.tsx diff --git a/app/web/src/components/IdeHeader/IdeHeader.tsx b/app/web/src/components/IdeHeader/IdeHeader.tsx index b85c868..ecc4863 100644 --- a/app/web/src/components/IdeHeader/IdeHeader.tsx +++ b/app/web/src/components/IdeHeader/IdeHeader.tsx @@ -1,21 +1,17 @@ import { useAuth } from '@redwoodjs/auth' -import { useLocation } from '@redwoodjs/router' +import { useMutation } from '@redwoodjs/web' import { Popover } from '@headlessui/react' import { Link, navigate, routes } from '@redwoodjs/router' -import { useIdeContext } from 'src/helpers/hooks/useIdeContext' import { Tab, Tabs, TabList, TabPanel } from 'react-tabs' + import FullScriptEncoding from 'src/components/EncodedUrl/FullScriptEncoding' import ExternalScript from 'src/components/EncodedUrl/ExternalScript' import Svg from 'src/components/Svg/Svg' -import NavPlusButton from 'src/components/NavPlusButton' -import ProfileSlashLogin from 'src/components/ProfileSlashLogin' -import { useMutation } from '@redwoodjs/web' +import { toast } from '@redwoodjs/web/toast' +import CaptureButton from 'src/components/CaptureButton/CaptureButton' +import { useIdeContext } from 'src/helpers/hooks/useIdeContext' import Gravatar from 'src/components/Gravatar/Gravatar' import EditableProjectTitle from 'src/components/EditableProjecTitle/EditableProjecTitle' -import CaptureButton from 'src/components/CaptureButton/CaptureButton' -import { toast } from '@redwoodjs/web/toast' - -import { ReactNode } from 'react' const FORK_PROJECT_MUTATION = gql` mutation ForkProjectMutation($input: ForkProjectInput!) { @@ -55,101 +51,21 @@ const TopButton = ({ ) } -interface IdeHeaderProps { - handleRender: () => void - projectTitle?: string - projectOwner?: string - projectOwnerId?: string - projectOwnerImage?: string - projectId?: string - children?: ReactNode -} - -const IdeHeader = ({ +export default function IdeHeader({ handleRender, - projectOwner, - projectTitle, - projectOwnerImage, - projectId, - projectOwnerId, - children, -}: IdeHeaderProps) => { - const { currentUser } = useAuth() - const { project } = useIdeContext() - const canEdit = - (currentUser && - currentUser?.sub === (project?.user?.id || projectOwnerId)) || - currentUser?.roles.includes('admin') - const _projectId = projectId || project?.id - const _projectOwner = project?.user?.userName || projectOwner - - return ( -
-
-
- - - -
- {_projectId && ( - <> - - - - {_projectOwner} - - - - - )} -
-
- {!children ? ( - - ) : ( - children - )} -
- -
- -
-
- ) -} - -export default IdeHeader - -function DefaultTopButtons({ - project, - projectTitle, - projectId, - _projectOwner, - handleRender, - canEdit, + context, +}: { + handleRender?: () => void + context: 'ide' | 'profile' }) { const { currentUser } = useAuth() - const { pathname } = useLocation() + const { project } = useIdeContext() + + const isProfile = context === 'profile' + const canEdit = + (currentUser && currentUser?.sub === project?.user?.id) || + currentUser?.roles?.includes('admin') + const projectOwner = project?.user?.userName const [createFork] = useMutation(FORK_PROJECT_MUTATION, { onCompleted: ({ forkProject }) => { @@ -157,9 +73,7 @@ function DefaultTopButtons({ userName: forkProject?.user?.userName, projectTitle: forkProject?.title, } - navigate( - pathname.includes('/ide') ? routes.ide(params) : routes.project(params) - ) + navigate(!isProfile ? routes.ide(params) : routes.project(params)) }, }) const handleFork = () => { @@ -167,7 +81,7 @@ function DefaultTopButtons({ variables: { input: { userId: currentUser.sub, - forkedFromId: project?.id || projectId, + forkedFromId: project?.id, }, }, }) @@ -180,95 +94,127 @@ function DefaultTopButtons({ return ( <> - {canEdit && !projectTitle && ( - ( +
+
+ {project?.id && ( + <> + + + + {projectOwner} + + + + + )} +
+
+ {canEdit && !isProfile && ( + ( + + + + )} + /> + )} + {!isProfile && ( - + )} - /> - )} - {!projectTitle && ( - - - - )} - {projectTitle && ( - - navigate(routes.ide({ userName: _projectOwner, projectTitle })) - } - name="Editor" - > - - - )} - - {({ open }) => { - return ( - <> - - - - - - {open && ( - - - - - - - - + {isProfile && ( + + navigate( + routes.ide({ + userName: projectOwner, + projectTitle: project.title, + }) + ) + } + name="Editor" + > + + + )} + + {({ open }) => { + return ( + <> + + + + + + {open && ( + + + + + + + + - - encoded script - external script - - - - )} - - ) - }} - - {currentUser?.sub && ( - - - - )} + + encoded script + external script + + + + )} + + ) + }} + + {currentUser?.sub && ( + + + + )} +
+
) } diff --git a/app/web/src/components/IdeWrapper/IdeWrapper.tsx b/app/web/src/components/IdeWrapper/IdeWrapper.tsx index 7b52242..2e7f529 100644 --- a/app/web/src/components/IdeWrapper/IdeWrapper.tsx +++ b/app/web/src/components/IdeWrapper/IdeWrapper.tsx @@ -1,17 +1,17 @@ -import { useEffect, useState } from 'react' +import { useState } from 'react' import IdeContainer from 'src/components/IdeContainer/IdeContainer' import { useRender } from './useRender' -import OutBound from 'src/components/OutBound/OutBound' import IdeSideBar from 'src/components/IdeSideBar/IdeSideBar' -import IdeHeader from 'src/components/IdeHeader/IdeHeader' -import Svg from 'src/components/Svg/Svg' +import TopNav from 'src/components/TopNav/TopNav' import { useIdeInit } from 'src/components/EncodedUrl/helpers' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' import { useSaveCode } from 'src/components/IdeWrapper/useSaveCode' import { ShortcutsModalContext } from 'src/components/EditorMenu/AllShortcutsModal' +import IdeHeader from 'src/components/IdeHeader/IdeHeader' +import type { CadPackageType } from 'src/components/CadPackage/CadPackage' interface Props { - cadPackage: string + cadPackage: CadPackageType } const IdeWrapper = ({ cadPackage }: Props) => { @@ -33,7 +33,9 @@ const IdeWrapper = ({ cadPackage }: Props) => {
diff --git a/app/web/src/components/ProjectCell/ProjectCell.tsx b/app/web/src/components/ProjectCell/ProjectCell.tsx index 30a2b36..75fc19b 100644 --- a/app/web/src/components/ProjectCell/ProjectCell.tsx +++ b/app/web/src/components/ProjectCell/ProjectCell.tsx @@ -2,6 +2,8 @@ import { useMutation } from '@redwoodjs/web' import { toast } from '@redwoodjs/web/toast' import { navigate, routes } from '@redwoodjs/router' import { useAuth } from '@redwoodjs/auth' +import { useIdeState } from 'src/helpers/hooks/useIdeState' +import { IdeContext } from 'src/helpers/hooks/useIdeContext' import ProjectProfile from 'src/components/ProjectProfile/ProjectProfile' import { QUERY as PROJECT_REACTION_QUERY } from 'src/components/ProjectReactionsCell' @@ -120,26 +122,20 @@ export const Empty = () =>
Empty
export const Failure = ({ error }) =>
Error: {error.message}
-export const Success = ({ - userProject, - variables: { isEditable }, - refetch, -}) => { +export const Success = ({ userProject, refetch }) => { const { currentUser } = useAuth() - const [updateProject, { loading, error }] = useMutation( - UPDATE_PROJECT_MUTATION, - { - onCompleted: ({ updateProject }) => { - navigate( - routes.project({ - userName: updateProject.user.userName, - projectTitle: updateProject.title, - }) - ) - toast.success('Project updated.') - }, - } - ) + const [state, thunkDispatch] = useIdeState() + const [updateProject] = useMutation(UPDATE_PROJECT_MUTATION, { + onCompleted: ({ updateProject }) => { + navigate( + routes.project({ + userName: updateProject.user.userName, + projectTitle: updateProject.title, + }) + ) + toast.success('Project updated.') + }, + }) const [createProject] = useMutation(CREATE_PROJECT_MUTATION, { onCompleted: ({ createProject }) => { navigate( @@ -160,7 +156,7 @@ export const Success = ({ refetch() } const [deleteProject] = useMutation(DELETE_PROJECT_MUTATION, { - onCompleted: ({ deleteProject }) => { + onCompleted: () => { navigate(routes.home()) toast.success('Project deleted.') }, @@ -206,15 +202,27 @@ export const Success = ({ }) return ( - + + + ) } diff --git a/app/web/src/components/ProjectProfile/ProjectProfile.tsx b/app/web/src/components/ProjectProfile/ProjectProfile.tsx index b5bf735..9fe52dd 100644 --- a/app/web/src/components/ProjectProfile/ProjectProfile.tsx +++ b/app/web/src/components/ProjectProfile/ProjectProfile.tsx @@ -10,6 +10,7 @@ import Button from 'src/components/Button/Button' import ProjectReactionsCell from '../ProjectReactionsCell' import { countEmotes } from 'src/helpers/emote' import { getActiveClasses } from 'get-active-classes' +import TopNav from 'src/components/TopNav/TopNav' import IdeHeader from 'src/components/IdeHeader/IdeHeader' import CadPackage from 'src/components/CadPackage/CadPackage' import Gravatar from 'src/components/Gravatar/Gravatar' @@ -50,7 +51,7 @@ const ProjectProfile = ({ projectTitle: project?.title, }) ) - }, [currentUser]) + }, [currentUser, project?.title, userProject.userName]) useIdeInit(project?.cadPackage, project?.code, 'viewer') const [newDescription, setNewDescription] = useState(project?.description) const onDescriptionChange = (description) => setNewDescription(description()) @@ -70,14 +71,9 @@ const ProjectProfile = ({ <>
- {}} - projectOwner={userProject?.userName} - projectOwnerImage={userProject?.image} - projectOwnerId={userProject?.id} - projectTitle={project?.title} - projectId={project?.id} - /> + + +
diff --git a/app/web/src/components/TopNav/TopNav.tsx b/app/web/src/components/TopNav/TopNav.tsx new file mode 100644 index 0000000..0f015eb --- /dev/null +++ b/app/web/src/components/TopNav/TopNav.tsx @@ -0,0 +1,31 @@ +import { Link, routes } from '@redwoodjs/router' +import Svg from 'src/components/Svg/Svg' +import NavPlusButton from 'src/components/NavPlusButton' +import ProfileSlashLogin from 'src/components/ProfileSlashLogin' +import { ReactNode } from 'react' +interface IdeHeaderProps { + children: ReactNode +} + +const TopNav = ({ children }: IdeHeaderProps) => { + return ( +
+
+
+ + + +
+
+ {children} +
+
+ +
+ +
+
+ ) +} + +export default TopNav diff --git a/app/web/src/components/UserProfile/UserProfile.tsx b/app/web/src/components/UserProfile/UserProfile.tsx index ae6cfb2..0ffe9b5 100644 --- a/app/web/src/components/UserProfile/UserProfile.tsx +++ b/app/web/src/components/UserProfile/UserProfile.tsx @@ -1,9 +1,8 @@ import { useEffect, useReducer } from 'react' import { useAuth } from '@redwoodjs/auth' -import { Link, navigate, routes } from '@redwoodjs/router' +import { navigate, routes } from '@redwoodjs/router' import ProjectsOfUser from 'src/components/ProjectsOfUserCell' -import IdeHeader from 'src/components/IdeHeader/IdeHeader' -import Svg from 'src/components/Svg/Svg' +import TopNav from 'src/components/TopNav/TopNav' import { fieldComponents, fieldReducer, @@ -27,13 +26,7 @@ function buildFieldsConfig(fieldsConfig, user, hasPermissionToEdit) { ) } -const UserProfile = ({ - user, - isEditing, - loading, - onSave, - error, -}: UserProfileType) => { +const UserProfile = ({ user, isEditing, onSave }: UserProfileType) => { const { currentUser } = useAuth() const hasPermissionToEdit = currentUser?.sub === user.id useEffect(() => { @@ -60,14 +53,14 @@ const UserProfile = ({ <>
- {}} projectOwner={user?.userName} projectOwnerImage={user?.image} projectOwnerId={user?.id} > - +
diff --git a/app/web/src/pages/DevIdePage/DevIdePage.tsx b/app/web/src/pages/DevIdePage/DevIdePage.tsx index 0c98170..a39195f 100644 --- a/app/web/src/pages/DevIdePage/DevIdePage.tsx +++ b/app/web/src/pages/DevIdePage/DevIdePage.tsx @@ -4,6 +4,7 @@ import { Toaster } from '@redwoodjs/web/toast' import { useIdeState } from 'src/helpers/hooks/useIdeState' import type { Project } from 'src/components/IdeProjectCell/IdeProjectCell' import { IdeContext } from 'src/helpers/hooks/useIdeContext' +import type { CadPackageType } from 'src/components/CadPackage/CadPackage' interface Props { cadPackage: string @@ -21,7 +22,9 @@ const DevIdePage = ({ cadPackage, project }: Props) => { /> - +
) diff --git a/app/web/src/pages/ProjectPage/ProjectPage.tsx b/app/web/src/pages/ProjectPage/ProjectPage.tsx index 4bd6c23..3110a8f 100644 --- a/app/web/src/pages/ProjectPage/ProjectPage.tsx +++ b/app/web/src/pages/ProjectPage/ProjectPage.tsx @@ -2,14 +2,11 @@ import { useAuth } from '@redwoodjs/auth' import ProjectCell from 'src/components/ProjectCell' import Seo from 'src/components/Seo/Seo' -import { useIdeState } from 'src/helpers/hooks/useIdeState' -import { IdeContext } from 'src/helpers/hooks/useIdeContext' import { Toaster } from '@redwoodjs/web/toast' import { makeSocialPublicId } from 'src/helpers/hooks/useUpdateProjectImages' const ProjectPage = ({ userName, projectTitle }) => { const { currentUser } = useAuth() - const [state, thunkDispatch] = useIdeState() const socialImageUrl = `http://res.cloudinary.com/irevdev/image/upload/c_scale,w_1200/v1/CadHub/${makeSocialPublicId( userName, projectTitle @@ -23,13 +20,11 @@ const ProjectPage = ({ userName, projectTitle }) => { lang="en-US" /> - - - + ) }