Merge pull request #190 from Irev-Dev/kurt/189

fixed most of issue 189
This commit was merged in pull request #190.
This commit is contained in:
Kurt Hutten
2020-12-30 12:48:38 +11:00
committed by GitHub
10 changed files with 145 additions and 68 deletions

View File

@@ -26,9 +26,9 @@ const UPDATE_USER_MUTATION = gql`
} }
` `
export const Loading = () => <div>Loading...</div> export const Loading = () => <div className="h-screen">Loading...</div>
export const Empty = () => <div>Empty</div> export const Empty = () => <div className="h-full">Empty</div>
export const Failure = ({ error }) => <div>Error: {error.message}</div> export const Failure = ({ error }) => <div>Error: {error.message}</div>

View File

@@ -1,6 +1,8 @@
import { useMutation, useFlash } from '@redwoodjs/web' import { useMutation, useFlash } from '@redwoodjs/web'
import { navigate, routes } from '@redwoodjs/router' import { navigate, routes } from '@redwoodjs/router'
import IdeCascadeStudio from 'src/components/IdeCascadeStudio' import IdeCascadeStudio from 'src/components/IdeCascadeStudio'
import { QUERY as UsersPartsQuery } from 'src/components/PartsOfUserCell'
import useUser from 'src/helpers/hooks/useUser'
export const QUERY = gql` export const QUERY = gql`
query FIND_PART_BY_USENAME_TITLE($partTitle: String!, $userName: String!) { query FIND_PART_BY_USENAME_TITLE($partTitle: String!, $userName: String!) {
@@ -45,12 +47,19 @@ export const Empty = () => <div>Part not found</div>
export const Success = ({ part, refetch }) => { export const Success = ({ part, refetch }) => {
const { addMessage } = useFlash() const { addMessage } = useFlash()
const { user } = useUser()
const [updatePart, { loading, error }] = useMutation(UPDATE_PART_MUTATION, { const [updatePart, { loading, error }] = useMutation(UPDATE_PART_MUTATION, {
onCompleted: () => { onCompleted: () => {
addMessage('Part updated.', { classes: 'rw-flash-success' }) addMessage('Part updated.', { classes: 'rw-flash-success' })
}, },
}) })
const [forkPart] = useMutation(FORK_PART_MUTATION, { const [forkPart] = useMutation(FORK_PART_MUTATION, {
refetchQueries: [
{
query: UsersPartsQuery,
variables: { userName: user?.userName },
},
],
onCompleted: ({ forkPart }) => { onCompleted: ({ forkPart }) => {
navigate( navigate(
routes.ide({ routes.ide({

View File

@@ -11,6 +11,8 @@ import ImageUploader from 'src/components/ImageUploader'
import Svg from '../Svg/Svg' import Svg from '../Svg/Svg'
import LoginModal from 'src/components/LoginModal' import LoginModal from 'src/components/LoginModal'
import { FORK_PART_MUTATION } from 'src/components/IdePartCell' import { FORK_PART_MUTATION } from 'src/components/IdePartCell'
import { QUERY as UsersPartsQuery } from 'src/components/PartsOfUserCell'
import useUser from 'src/helpers/hooks/useUser'
const IdeToolbar = ({ const IdeToolbar = ({
canEdit, canEdit,
@@ -26,20 +28,17 @@ const IdeToolbar = ({
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false) const [isLoginModalOpen, setIsLoginModalOpen] = useState(false)
const { isAuthenticated, currentUser } = useAuth() const { isAuthenticated, currentUser } = useAuth()
const showForkButton = !(canEdit || isDraft) const showForkButton = !(canEdit || isDraft)
const [title, setTitle] = useState('untitled-part')
const { user } = useUser()
const { addMessage } = useFlash() const { addMessage } = useFlash()
const [forkPart] = useMutation(FORK_PART_MUTATION, { const [forkPart] = useMutation(FORK_PART_MUTATION, {
onCompleted: ({ forkPart }) => { refetchQueries: [
navigate( {
routes.ide({ query: UsersPartsQuery,
userName: forkPart?.user?.userName, variables: { userName: userNamePart?.userName || user?.userName },
partTitle: forkPart?.title, },
}) ],
)
addMessage(`Part created with title: ${forkPart?.title}.`, {
classes: 'rw-flash-success',
})
},
}) })
const handleClick = ({ event, whichPopup }) => { const handleClick = ({ event, whichPopup }) => {
@@ -52,21 +51,42 @@ const IdeToolbar = ({
setWhichPopup(null) setWhichPopup(null)
} }
const handleSave = () => { const saveFork = () =>
if (isDraft && isAuthenticated) forkPart({
forkPart({ variables: {
variables: { input: {
input: { userId: currentUser.sub,
userId: currentUser.sub, title,
title: 'draft', code,
code,
},
}, },
},
})
const handleSave = async () => {
if (isDraft && isAuthenticated) {
const { data } = await saveFork()
navigate(
routes.ide({
userName: data?.forkPart?.user?.userName,
partTitle: data?.forkPart?.title,
})
)
addMessage(`Part created with title: ${data?.forkPart?.title}.`, {
classes: 'rw-flash-success',
}) })
else if (isAuthenticated) onSave() } else if (isAuthenticated) onSave()
else recordedLogin() else recordedLogin()
} }
const handleSaveAndEdit = async () => {
const { data } = await saveFork()
const {
user: { userName },
title: partTitle,
} = data?.forkPart || { user: {} }
navigate(routes.part({ userName, partTitle }))
}
const recordedLogin = async () => { const recordedLogin = async () => {
ReactGA.event({ ReactGA.event({
category: 'login', category: 'login',
@@ -135,6 +155,27 @@ const IdeToolbar = ({
</span> </span>
)} )}
</Button> </Button>
{isDraft && isAuthenticated && (
<div className="flex items-center">
<Button
iconName={'save'}
className="ml-3 shadow-md hover:shadow-lg border-indigo-600 border-2 border-opacity-0 hover:border-opacity-100 bg-indigo-800 text-indigo-200 mr-"
shouldAnimateHover
onClick={handleSaveAndEdit}
>
Save & Edit Profile
</Button>
<div className="ml-4 text-indigo-300">title:</div>
<input
className="rounded ml-4 px-2"
value={title}
onChange={({ target }) =>
setTitle(target?.value.replace(/([^a-zA-Z\d_:])/g, '-'))
}
/>
<div className="w-px ml-4 bg-pink-400 h-10"></div>
</div>
)}
<div> <div>
<Button <Button
iconName="logout" iconName="logout"

View File

@@ -7,19 +7,12 @@ import {
} from './mockEditorParts' } from './mockEditorParts'
import Svg from 'src/components/Svg' import Svg from 'src/components/Svg'
import OutBound from 'src/components/OutBound' import OutBound from 'src/components/OutBound'
import ReactGA from 'react-ga'
import LoginModal from 'src/components/LoginModal' import LoginModal from 'src/components/LoginModal'
import { useState } from 'react' import { useState } from 'react'
import { routes, Link } from '@redwoodjs/router'
const LandingSection = () => { const LandingSection = () => {
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false) const [isLoginModalOpen, setIsLoginModalOpen] = useState(false)
const recordedLogin = async () => {
ReactGA.event({
category: 'login',
action: 'landing section CTA',
})
setIsLoginModalOpen(true)
}
return ( return (
<div className="mt-16"> <div className="mt-16">
<div className="relative p-4 shadow-md"> <div className="relative p-4 shadow-md">
@@ -163,14 +156,13 @@ const LandingSection = () => {
</OutBound>{' '} </OutBound>{' '}
with more integrations coming soon. with more integrations coming soon.
</p> </p>
<button <Link to={routes.draftPart()}>
className="bg-texture bg-purple-800 text-center w-full py-6 rounded-b-md border border-indigo-300 border-opacity-0 hover:border-opacity-100 hover:shadow-xl" <div className="bg-texture bg-purple-800 text-center w-full py-6 rounded-b-md border border-indigo-300 border-opacity-0 hover:border-opacity-100 hover:shadow-xl">
onClick={recordedLogin} <span className="font-bold text-2xl text-indigo-200">
> Start Hacking Now
<span className="font-bold text-2xl text-indigo-200"> </span>
Start Hacking Now </div>
</span> </Link>
</button>
</div> </div>
</div> </div>
<div className="flex justify-center mt-64 pt-20 mb-32"> <div className="flex justify-center mt-64 pt-20 mb-32">

View File

@@ -97,9 +97,9 @@ const DELETE_PART_MUTATION = gql`
} }
` `
export const Loading = () => <div>Loading...</div> export const Loading = () => <div className="h-screen">Loading...</div>
export const Empty = () => <div>Empty</div> export const Empty = () => <div className="h-full">Empty</div>
export const Failure = ({ error }) => <div>Error: {error.message}</div> export const Failure = ({ error }) => <div>Error: {error.message}</div>

View File

@@ -130,6 +130,23 @@ const PartProfile = ({
> >
{isEditable ? 'Save Details' : 'Edit Details'} {isEditable ? 'Save Details' : 'Edit Details'}
</Button> </Button>
{isEditable && (
<Button
className="mt-4 ml-auto shadow-md hover:shadow-lg bg-indigo-200 relative z-20 w-full justify-end"
shouldAnimateHover
iconName="x"
onClick={() =>
navigate(
routes.part({
userName: userPart.userName,
partTitle: part?.title,
})
)
}
>
Cancel
</Button>
)}
<Button <Button
className="mt-4 ml-auto shadow-md hover:shadow-lg bg-red-200 relative z-20 w-full justify-end" className="mt-4 ml-auto shadow-md hover:shadow-lg bg-red-200 relative z-20 w-full justify-end"
shouldAnimateHover shouldAnimateHover

View File

@@ -24,14 +24,7 @@ export const QUERY = gql`
export const Loading = () => <div>Loading...</div> export const Loading = () => <div>Loading...</div>
export const Empty = () => { export const Empty = () => {
return ( return <div className="rw-text-center">No parts yet.</div>
<div className="rw-text-center">
{'No parts yet. '}
<Link to={routes.draftPart()} className="rw-link">
{'Create one?'}
</Link>
</div>
)
} }
export const Success = ({ export const Success = ({

View File

@@ -322,6 +322,21 @@ const Svg = ({ name, className: className2, strokeWidth = 2 }) => {
/> />
</svg> </svg>
), ),
x: (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={strokeWidth}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
),
} }
return <div className={className2 || 'h-10 w-10'}>{svgs[name]}</div> return <div className={className2 || 'h-10 w-10'}>{svgs[name]}</div>

View File

@@ -0,0 +1,22 @@
import { useQuery } from '@redwoodjs/web'
import { useAuth } from '@redwoodjs/auth'
const QUERY = gql`
query FIND_USER_BY_ID($id: String!) {
user: user(id: $id) {
id
image
userName
name
}
}
`
export default function () {
const { currentUser } = useAuth()
const { data, loading } = useQuery(QUERY, {
skip: !currentUser?.sub,
variables: { id: currentUser?.sub },
})
return { user: data?.user, loading }
}

View File

@@ -1,7 +1,7 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { Link, routes, navigate } from '@redwoodjs/router' import { Link, routes, navigate } from '@redwoodjs/router'
import { useAuth } from '@redwoodjs/auth' import { useAuth } from '@redwoodjs/auth'
import { Flash, useQuery, useFlash } from '@redwoodjs/web' import { Flash, useFlash } from '@redwoodjs/web'
import Tooltip from '@material-ui/core/Tooltip' import Tooltip from '@material-ui/core/Tooltip'
import Popover from '@material-ui/core/Popover' import Popover from '@material-ui/core/Popover'
import { getActiveClasses } from 'get-active-classes' import { getActiveClasses } from 'get-active-classes'
@@ -10,28 +10,16 @@ import { useLocation } from '@redwoodjs/router'
import LoginModal from 'src/components/LoginModal' import LoginModal from 'src/components/LoginModal'
import ReactGA from 'react-ga' import ReactGA from 'react-ga'
export const QUERY = gql`
query FIND_USER_BY_ID($id: String!) {
user: user(id: $id) {
id
image
userName
name
}
}
`
import Svg from 'src/components/Svg' import Svg from 'src/components/Svg'
import ImageUploader from 'src/components/ImageUploader' import ImageUploader from 'src/components/ImageUploader'
import useUser from 'src/helpers/hooks/useUser'
let previousSubmission = '' let previousSubmission = ''
const MainLayout = ({ children, shouldRemoveFooterInIde }) => { const MainLayout = ({ children, shouldRemoveFooterInIde }) => {
const { logOut, isAuthenticated, currentUser, client } = useAuth() const { logOut, isAuthenticated, currentUser, client } = useAuth()
const { addMessage } = useFlash() const { addMessage } = useFlash()
const { data, loading } = useQuery(QUERY, { const { user, loading } = useUser()
skip: !currentUser?.sub,
variables: { id: currentUser?.sub },
})
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false) const [isLoginModalOpen, setIsLoginModalOpen] = useState(false)
const [isOpen, setIsOpen] = useState(false) const [isOpen, setIsOpen] = useState(false)
const [anchorEl, setAnchorEl] = useState(null) const [anchorEl, setAnchorEl] = useState(null)
@@ -154,7 +142,7 @@ const MainLayout = ({ children, shouldRemoveFooterInIde }) => {
<ImageUploader <ImageUploader
className="rounded-full object-cover" className="rounded-full object-cover"
aspectRatio={1} aspectRatio={1}
imageUrl={data?.user?.image} imageUrl={user?.image}
width={80} width={80}
/> />
)} )}
@@ -188,14 +176,14 @@ const MainLayout = ({ children, shouldRemoveFooterInIde }) => {
}} }}
> >
<div className="p-4 w-48"> <div className="p-4 w-48">
<Link to={routes.user({ userName: data?.user?.userName })}> <Link to={routes.user({ userName: user?.userName })}>
<h3 className="text-indigo-800" style={{ fontWeight: '500' }}> <h3 className="text-indigo-800" style={{ fontWeight: '500' }}>
Hello {data?.user?.name} Hello {user?.name}
</h3> </h3>
</Link> </Link>
<hr /> <hr />
<br /> <br />
<Link to={routes.user({ userName: data?.user?.userName })}> <Link to={routes.user({ userName: user?.userName })}>
<div className="text-indigo-800">Your Profile</div> <div className="text-indigo-800">Your Profile</div>
</Link> </Link>
<a href="#" className="text-indigo-800" onClick={logOut}> <a href="#" className="text-indigo-800" onClick={logOut}>