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:
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 = ({
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
22
web/src/helpers/hooks/useUser.js
Normal file
22
web/src/helpers/hooks/useUser.js
Normal 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 }
|
||||||
|
}
|
||||||
@@ -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}>
|
||||||
|
|||||||
Reference in New Issue
Block a user