Allow for new parts to be created

This commit is contained in:
Kurt Hutten
2020-11-08 18:39:56 +11:00
parent 8107c7dcea
commit 8fa017beed
10 changed files with 78 additions and 10 deletions

View File

@@ -17,6 +17,7 @@
"./web/src/Routes.js",
],
"cSpell.words": [
"Uploader"
"Uploader",
"redwoodjs"
]
}

View File

@@ -9,7 +9,7 @@ export const schema = gql`
image: String
bio: String
Parts: [Part]!
Part(partTitle: String!): Part
Part(partTitle: String): Part
Reaction: [PartReaction]!
Comment: [Comment]!
}

View File

@@ -1,6 +1,7 @@
import { db } from 'src/lib/db'
import { requireAuth } from 'src/lib/auth'
import { requireOwnership } from 'src/lib/owner'
import { UserInputError } from '@redwoodjs/api'
export const users = () => {
requireAuth({ role: 'admin' })
@@ -43,6 +44,9 @@ export const updateUserByUserName = async ({ userName, input }) => {
if(input.userName) {
input.userName = input.userName.replace(/([^a-zA-Z\d_:])/g, '-')
}
if(input.userName && ['new', 'edit', 'update'].includes(input.userName)) { //TODO complete this and use a regexp so that it's not case sensitive, don't want someone with the userName eDiT
throw new UserInputError(`You've tried to used a protected word as you userName, try something other than `)
}
return db.user.update({
data: input,
where: { userName },
@@ -58,7 +62,7 @@ export const deleteUser = ({ id }) => {
export const User = {
Parts: (_obj, { root }) => db.user.findOne({ where: { id: root.id } }).Part(),
Part: (_obj, { root, ...rest }) => db.part.findOne({where: { title_userId: {
Part: (_obj, { root, ...rest }) => _obj.partTitle && db.part.findOne({where: { title_userId: {
title: _obj.partTitle,
userId: root.id,
}}}),

View File

@@ -17,6 +17,7 @@ const Routes = () => {
<Route notfound page={NotFoundPage} />
{/* Ownership enforced routes */}
<Route path="/u/{userName}/new" page={NewPart2Page} name="newPart2" />
<Route path="/u/{userName}/edit" page={EditUser2Page} name="editUser2" />
<Route path="/u/{userName}/{partTitle}/edit" page={EditPart2Page} name="editPart2" />
{/* End ownership enforced routes */}

View File

@@ -5,7 +5,7 @@ import { useAuth } from '@redwoodjs/auth'
import PartProfile from 'src/components/PartProfile'
export const QUERY = gql`
query FIND_PART_BY_USERNAME_TITLE($userName: String!, $partTitle: String!, $currentUserId: String) {
query FIND_PART_BY_USERNAME_TITLE($userName: String!, $partTitle: String, $currentUserId: String) {
userPart: userName(userName: $userName) {
id
name
@@ -52,6 +52,18 @@ const UPDATE_PART_MUTATION = gql`
}
}
`
const CREATE_PART_MUTATION = gql`
mutation CreatePartMutation($input: CreatePartInput!) {
createPart(input: $input) {
id
title
user {
id
userName
}
}
}
`
const TOGGLE_REACTION_MUTATION = gql`
mutation ToggleReactionMutation($input: TogglePartReactionInput!) {
togglePartReaction(input: $input){
@@ -84,7 +96,17 @@ export const Success = ({ userPart, variables: {isEditable}, refetch}) => {
addMessage('Part updated.', { classes: 'rw-flash-success' })
},
})
const [createUser] = useMutation(CREATE_PART_MUTATION, {
onCompleted: ({createPart}) => {
navigate(routes.part2({userName: createPart?.user?.userName, partTitle: createPart?.title}))
addMessage('Part Created.', { classes: 'rw-flash-success' })
},
})
const onSave = (id, input) => {
if(!id) {
createUser({ variables: { input } })
return
}
updateUser({ variables: { id, input } })
}

View File

@@ -33,6 +33,7 @@ const PartProfile = ({
title: part?.title,
mainImage: part?.mainImage,
description: part?.description,
userId: userPart?.id,
})
const setProperty = (property, value) => setInput({
...input,
@@ -43,7 +44,7 @@ const PartProfile = ({
const onImageUpload = ({cloudinaryPublicId}) => setProperty('mainImage', cloudinaryPublicId)
const onEditSaveClick = () => {
if (isEditable) {
onSave(part.id, input)
input.title && onSave(part?.id, input)
return
}
navigate(routes.editPart2({userName: userPart.userName, partTitle: part.title}))
@@ -98,7 +99,7 @@ const PartProfile = ({
{/* main project center column */}
<section className="col-start-3">
<Breadcrumb className="inline" onPartTitleChange={isEditable && onTitleChange} userName={userPart.userName} partTitle={input?.title}/>
{ input?.mainImage && <ImageUploader
{ !!(input?.mainImage || isEditable) && <ImageUploader
className="rounded-lg shadow-md border-2 border-gray-200 border-solid mt-8"
onImageUpload={onImageUpload}
aspectRatio={16/9}

View File

@@ -3,6 +3,7 @@ import { useAuth } from '@redwoodjs/auth'
import { Flash } from '@redwoodjs/web'
import Tooltip from '@material-ui/core/Tooltip';
import { useQuery } from '@redwoodjs/web'
import {getActiveClasses} from 'get-active-classes'
export const QUERY = gql`
query FIND_USER_BY_ID($id: String!) {
@@ -44,10 +45,10 @@ const MainLayout = ({ children }) => {
</li>
</ul>
<ul className="flex items-center">
<li className="mr-8 h-10 w-10 rounded-full border-2 border-indigo-300 flex items-center justify-center">
{/* <Link to={routes.newPart()}> */}
<Svg name="plus" className="text-indigo-300 w-full h-full" />
{/* </Link> */}
<li className={getActiveClasses("mr-8 h-10 w-10 rounded-full border-2 border-gray-700 flex items-center justify-center", {'border-indigo-300': currentUser})}>
<button className="h-full w-full" onClick={() => currentUser && routes.newPart2({userName: data?.user?.userName})}>
<Svg name="plus" className={getActiveClasses("text-gray-700 w-full h-full",{'text-indigo-300': currentUser})} />
</button>
</li>
{
isAuthenticated ?

View File

@@ -0,0 +1,20 @@
import { useAuth } from '@redwoodjs/auth'
import MainLayout from 'src/layouts/MainLayout'
import Part2Cell from 'src/components/Part2Cell'
const NewPart2Page = ({userName}) => {
const { currentUser } = useAuth()
return (
<MainLayout>
<Part2Cell
userName={userName}
currentUserId={currentUser?.sub}
isEditable
/>
</MainLayout>
)
}
export default NewPart2Page

View File

@@ -0,0 +1,7 @@
import NewPart2Page from './NewPart2Page'
export const generated = () => {
return <NewPart2Page />
}
export default { title: 'Pages/NewPart2Page' }

View File

@@ -0,0 +1,11 @@
import { render } from '@redwoodjs/testing'
import NewPart2Page from './NewPart2Page'
describe('NewPart2Page', () => {
it('renders successfully', () => {
expect(() => {
render(<NewPart2Page />)
}).not.toThrow()
})
})