Re-init DB and scaffold all models
This commit is contained in:
@@ -12,8 +12,24 @@ import { Router, Route, Private } from '@redwoodjs/router'
|
||||
const Routes = () => {
|
||||
return (
|
||||
<Router>
|
||||
<Route path="/" page={PartsPage} name="home" />
|
||||
<Route path="/blah/*" page={PartsPage} name="home" />
|
||||
<Route path="/part-reactions/new" page={NewPartReactionPage} name="newPartReaction" />
|
||||
<Route path="/part-reactions/{id}/edit" page={EditPartReactionPage} name="editPartReaction" />
|
||||
<Route path="/part-reactions/{id}" page={PartReactionPage} name="partReaction" />
|
||||
<Route path="/part-reactions" page={PartReactionsPage} name="partReactions" />
|
||||
<Route path="/parts/new" page={NewPartPage} name="newPart" />
|
||||
<Route path="/parts/{id}/edit" page={EditPartPage} name="editPart" />
|
||||
<Route path="/parts/{id}" page={PartPage} name="part" />
|
||||
<Route path="/parts" page={PartsPage} name="parts" />
|
||||
<Route path="/comments/new" page={NewCommentPage} name="newComment" />
|
||||
<Route path="/comments/{id}/edit" page={EditCommentPage} name="editComment" />
|
||||
<Route path="/comments/{id}" page={CommentPage} name="comment" />
|
||||
<Route path="/comments" page={CommentsPage} name="comments" />
|
||||
<Route path="/users/new" page={NewUserPage} name="newUser" />
|
||||
<Route path="/users/{id}/edit" page={EditUserPage} name="editUser" />
|
||||
<Route path="/users/{id}" page={UserPage} name="user" />
|
||||
<Route path="/users" page={UsersPage} name="users" />
|
||||
<Route path="/" page={HomePage} name="home" />
|
||||
{/* <Route path="/blah/*" page={PartsPage} name="home" /> */}
|
||||
<Route notfound page={NotFoundPage} />
|
||||
</Router>
|
||||
)
|
||||
|
||||
103
web/src/components/Comment/Comment.js
Normal file
103
web/src/components/Comment/Comment.js
Normal file
@@ -0,0 +1,103 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes, navigate } from '@redwoodjs/router'
|
||||
|
||||
const DELETE_COMMENT_MUTATION = gql`
|
||||
mutation DeleteCommentMutation($id: String!) {
|
||||
deleteComment(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const jsonDisplay = (obj) => {
|
||||
return (
|
||||
<pre>
|
||||
<code>{JSON.stringify(obj, null, 2)}</code>
|
||||
</pre>
|
||||
)
|
||||
}
|
||||
|
||||
const timeTag = (datetime) => {
|
||||
return (
|
||||
<time dateTime={datetime} title={datetime}>
|
||||
{new Date(datetime).toUTCString()}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
const checkboxInputTag = (checked) => {
|
||||
return <input type="checkbox" checked={checked} disabled />
|
||||
}
|
||||
|
||||
const Comment = ({ comment }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [deleteComment] = useMutation(DELETE_COMMENT_MUTATION, {
|
||||
onCompleted: () => {
|
||||
navigate(routes.comments())
|
||||
addMessage('Comment deleted.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onDeleteClick = (id) => {
|
||||
if (confirm('Are you sure you want to delete comment ' + id + '?')) {
|
||||
deleteComment({ variables: { id } })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">
|
||||
Comment {comment.id} Detail
|
||||
</h2>
|
||||
</header>
|
||||
<table className="rw-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<td>{comment.id}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Text</th>
|
||||
<td>{comment.text}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>User id</th>
|
||||
<td>{comment.userId}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Part id</th>
|
||||
<td>{comment.partId}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Created at</th>
|
||||
<td>{timeTag(comment.createdAt)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Updated at</th>
|
||||
<td>{timeTag(comment.updatedAt)}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<nav className="rw-button-group">
|
||||
<Link
|
||||
to={routes.editComment({ id: comment.id })}
|
||||
className="rw-button rw-button-blue"
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
<a
|
||||
href="#"
|
||||
className="rw-button rw-button-red"
|
||||
onClick={() => onDeleteClick(comment.id)}
|
||||
>
|
||||
Delete
|
||||
</a>
|
||||
</nav>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Comment
|
||||
22
web/src/components/CommentCell/CommentCell.js
Normal file
22
web/src/components/CommentCell/CommentCell.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import Comment from 'src/components/Comment'
|
||||
|
||||
export const QUERY = gql`
|
||||
query FIND_COMMENT_BY_ID($id: String!) {
|
||||
comment: comment(id: $id) {
|
||||
id
|
||||
text
|
||||
userId
|
||||
partId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Empty = () => <div>Comment not found</div>
|
||||
|
||||
export const Success = ({ comment }) => {
|
||||
return <Comment comment={comment} />
|
||||
}
|
||||
83
web/src/components/CommentForm/CommentForm.js
Normal file
83
web/src/components/CommentForm/CommentForm.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
Form,
|
||||
FormError,
|
||||
FieldError,
|
||||
Label,
|
||||
TextField,
|
||||
Submit,
|
||||
} from '@redwoodjs/forms'
|
||||
|
||||
const CommentForm = (props) => {
|
||||
const onSubmit = (data) => {
|
||||
props.onSave(data, props?.comment?.id)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-form-wrapper">
|
||||
<Form onSubmit={onSubmit} error={props.error}>
|
||||
<FormError
|
||||
error={props.error}
|
||||
wrapperClassName="rw-form-error-wrapper"
|
||||
titleClassName="rw-form-error-title"
|
||||
listClassName="rw-form-error-list"
|
||||
/>
|
||||
|
||||
<Label
|
||||
name="text"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Text
|
||||
</Label>
|
||||
<TextField
|
||||
name="text"
|
||||
defaultValue={props.comment?.text}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="text" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="userId"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
User id
|
||||
</Label>
|
||||
<TextField
|
||||
name="userId"
|
||||
defaultValue={props.comment?.userId}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="userId" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="partId"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Part id
|
||||
</Label>
|
||||
<TextField
|
||||
name="partId"
|
||||
defaultValue={props.comment?.partId}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="partId" className="rw-field-error" />
|
||||
|
||||
<div className="rw-button-group">
|
||||
<Submit disabled={props.loading} className="rw-button rw-button-blue">
|
||||
Save
|
||||
</Submit>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommentForm
|
||||
109
web/src/components/Comments/Comments.js
Normal file
109
web/src/components/Comments/Comments.js
Normal file
@@ -0,0 +1,109 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
|
||||
const DELETE_COMMENT_MUTATION = gql`
|
||||
mutation DeleteCommentMutation($id: String!) {
|
||||
deleteComment(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const MAX_STRING_LENGTH = 150
|
||||
|
||||
const truncate = (text) => {
|
||||
let output = text
|
||||
if (text && text.length > MAX_STRING_LENGTH) {
|
||||
output = output.substring(0, MAX_STRING_LENGTH) + '...'
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
const jsonTruncate = (obj) => {
|
||||
return truncate(JSON.stringify(obj, null, 2))
|
||||
}
|
||||
|
||||
const timeTag = (datetime) => {
|
||||
return (
|
||||
<time dateTime={datetime} title={datetime}>
|
||||
{new Date(datetime).toUTCString()}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
const checkboxInputTag = (checked) => {
|
||||
return <input type="checkbox" checked={checked} disabled />
|
||||
}
|
||||
|
||||
const CommentsList = ({ comments }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [deleteComment] = useMutation(DELETE_COMMENT_MUTATION, {
|
||||
onCompleted: () => {
|
||||
addMessage('Comment deleted.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onDeleteClick = (id) => {
|
||||
if (confirm('Are you sure you want to delete comment ' + id + '?')) {
|
||||
deleteComment({ variables: { id }, refetchQueries: ['COMMENTS'] })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment rw-table-wrapper-responsive">
|
||||
<table className="rw-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Text</th>
|
||||
<th>User id</th>
|
||||
<th>Part id</th>
|
||||
<th>Created at</th>
|
||||
<th>Updated at</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{comments.map((comment) => (
|
||||
<tr key={comment.id}>
|
||||
<td>{truncate(comment.id)}</td>
|
||||
<td>{truncate(comment.text)}</td>
|
||||
<td>{truncate(comment.userId)}</td>
|
||||
<td>{truncate(comment.partId)}</td>
|
||||
<td>{timeTag(comment.createdAt)}</td>
|
||||
<td>{timeTag(comment.updatedAt)}</td>
|
||||
<td>
|
||||
<nav className="rw-table-actions">
|
||||
<Link
|
||||
to={routes.comment({ id: comment.id })}
|
||||
title={'Show comment ' + comment.id + ' detail'}
|
||||
className="rw-button rw-button-small"
|
||||
>
|
||||
Show
|
||||
</Link>
|
||||
<Link
|
||||
to={routes.editComment({ id: comment.id })}
|
||||
title={'Edit comment ' + comment.id}
|
||||
className="rw-button rw-button-small rw-button-blue"
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
<a
|
||||
href="#"
|
||||
title={'Delete comment ' + comment.id}
|
||||
className="rw-button rw-button-small rw-button-red"
|
||||
onClick={() => onDeleteClick(comment.id)}
|
||||
>
|
||||
Delete
|
||||
</a>
|
||||
</nav>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommentsList
|
||||
33
web/src/components/CommentsCell/CommentsCell.js
Normal file
33
web/src/components/CommentsCell/CommentsCell.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
|
||||
import Comments from 'src/components/Comments'
|
||||
|
||||
export const QUERY = gql`
|
||||
query COMMENTS {
|
||||
comments {
|
||||
id
|
||||
text
|
||||
userId
|
||||
partId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Empty = () => {
|
||||
return (
|
||||
<div className="rw-text-center">
|
||||
{'No comments yet. '}
|
||||
<Link to={routes.newComment()} className="rw-link">
|
||||
{'Create one?'}
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Success = ({ comments }) => {
|
||||
return <Comments comments={comments} />
|
||||
}
|
||||
60
web/src/components/EditCommentCell/EditCommentCell.js
Normal file
60
web/src/components/EditCommentCell/EditCommentCell.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import CommentForm from 'src/components/CommentForm'
|
||||
|
||||
export const QUERY = gql`
|
||||
query FIND_COMMENT_BY_ID($id: String!) {
|
||||
comment: comment(id: $id) {
|
||||
id
|
||||
text
|
||||
userId
|
||||
partId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
const UPDATE_COMMENT_MUTATION = gql`
|
||||
mutation UpdateCommentMutation($id: String!, $input: UpdateCommentInput!) {
|
||||
updateComment(id: $id, input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Success = ({ comment }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [updateComment, { loading, error }] = useMutation(
|
||||
UPDATE_COMMENT_MUTATION,
|
||||
{
|
||||
onCompleted: () => {
|
||||
navigate(routes.comments())
|
||||
addMessage('Comment updated.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const onSave = (input, id) => {
|
||||
updateComment({ variables: { id, input } })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">
|
||||
Edit Comment {comment.id}
|
||||
</h2>
|
||||
</header>
|
||||
<div className="rw-segment-main">
|
||||
<CommentForm
|
||||
comment={comment}
|
||||
onSave={onSave}
|
||||
error={error}
|
||||
loading={loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
52
web/src/components/EditPartCell/EditPartCell.js
Normal file
52
web/src/components/EditPartCell/EditPartCell.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import PartForm from 'src/components/PartForm'
|
||||
|
||||
export const QUERY = gql`
|
||||
query FIND_PART_BY_ID($id: String!) {
|
||||
part: part(id: $id) {
|
||||
id
|
||||
title
|
||||
description
|
||||
code
|
||||
mainImage
|
||||
createdAt
|
||||
updatedAt
|
||||
userId
|
||||
}
|
||||
}
|
||||
`
|
||||
const UPDATE_PART_MUTATION = gql`
|
||||
mutation UpdatePartMutation($id: String!, $input: UpdatePartInput!) {
|
||||
updatePart(id: $id, input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Success = ({ part }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [updatePart, { loading, error }] = useMutation(UPDATE_PART_MUTATION, {
|
||||
onCompleted: () => {
|
||||
navigate(routes.parts())
|
||||
addMessage('Part updated.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onSave = (input, id) => {
|
||||
updatePart({ variables: { id, input } })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">Edit Part {part.id}</h2>
|
||||
</header>
|
||||
<div className="rw-segment-main">
|
||||
<PartForm part={part} onSave={onSave} error={error} loading={loading} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import PartReactionForm from 'src/components/PartReactionForm'
|
||||
|
||||
export const QUERY = gql`
|
||||
query FIND_PART_REACTION_BY_ID($id: String!) {
|
||||
partReaction: partReaction(id: $id) {
|
||||
id
|
||||
emote
|
||||
userId
|
||||
partId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
const UPDATE_PART_REACTION_MUTATION = gql`
|
||||
mutation UpdatePartReactionMutation(
|
||||
$id: String!
|
||||
$input: UpdatePartReactionInput!
|
||||
) {
|
||||
updatePartReaction(id: $id, input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Success = ({ partReaction }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [updatePartReaction, { loading, error }] = useMutation(
|
||||
UPDATE_PART_REACTION_MUTATION,
|
||||
{
|
||||
onCompleted: () => {
|
||||
navigate(routes.partReactions())
|
||||
addMessage('PartReaction updated.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const onSave = (input, id) => {
|
||||
updatePartReaction({ variables: { id, input } })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">
|
||||
Edit PartReaction {partReaction.id}
|
||||
</h2>
|
||||
</header>
|
||||
<div className="rw-segment-main">
|
||||
<PartReactionForm
|
||||
partReaction={partReaction}
|
||||
onSave={onSave}
|
||||
error={error}
|
||||
loading={loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
51
web/src/components/EditUserCell/EditUserCell.js
Normal file
51
web/src/components/EditUserCell/EditUserCell.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import UserForm from 'src/components/UserForm'
|
||||
|
||||
export const QUERY = gql`
|
||||
query FIND_USER_BY_ID($id: String!) {
|
||||
user: user(id: $id) {
|
||||
id
|
||||
userName
|
||||
email
|
||||
createdAt
|
||||
updatedAt
|
||||
image
|
||||
bio
|
||||
}
|
||||
}
|
||||
`
|
||||
const UPDATE_USER_MUTATION = gql`
|
||||
mutation UpdateUserMutation($id: String!, $input: UpdateUserInput!) {
|
||||
updateUser(id: $id, input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Success = ({ user }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [updateUser, { loading, error }] = useMutation(UPDATE_USER_MUTATION, {
|
||||
onCompleted: () => {
|
||||
navigate(routes.users())
|
||||
addMessage('User updated.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onSave = (input, id) => {
|
||||
updateUser({ variables: { id, input } })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">Edit User {user.id}</h2>
|
||||
</header>
|
||||
<div className="rw-segment-main">
|
||||
<UserForm user={user} onSave={onSave} error={error} loading={loading} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import Part from 'src/components/Part'
|
||||
// import Part from 'src/components/Part'
|
||||
|
||||
export const QUERY = gql`
|
||||
query FIND_PART_BY_ID($id: Int!) {
|
||||
@@ -42,5 +42,6 @@ export const Success = ({ part }) => {
|
||||
console.log(id, input, 'wowow')
|
||||
updatePart({ variables: { id, input } })
|
||||
}
|
||||
return <Part part={{...part, code: part.code}} saveCode={saveCode} loading={loading} error={error} />
|
||||
return <div>TODO part</div>
|
||||
// return <Part part={{...part, code: part.code}} saveCode={saveCode} loading={loading} error={error} />
|
||||
}
|
||||
|
||||
41
web/src/components/NewComment/NewComment.js
Normal file
41
web/src/components/NewComment/NewComment.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import CommentForm from 'src/components/CommentForm'
|
||||
|
||||
const CREATE_COMMENT_MUTATION = gql`
|
||||
mutation CreateCommentMutation($input: CreateCommentInput!) {
|
||||
createComment(input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const NewComment = () => {
|
||||
const { addMessage } = useFlash()
|
||||
const [createComment, { loading, error }] = useMutation(
|
||||
CREATE_COMMENT_MUTATION,
|
||||
{
|
||||
onCompleted: () => {
|
||||
navigate(routes.comments())
|
||||
addMessage('Comment created.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const onSave = (input) => {
|
||||
createComment({ variables: { input } })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">New Comment</h2>
|
||||
</header>
|
||||
<div className="rw-segment-main">
|
||||
<CommentForm onSave={onSave} loading={loading} error={error} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewComment
|
||||
38
web/src/components/NewPart/NewPart.js
Normal file
38
web/src/components/NewPart/NewPart.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import PartForm from 'src/components/PartForm'
|
||||
|
||||
const CREATE_PART_MUTATION = gql`
|
||||
mutation CreatePartMutation($input: CreatePartInput!) {
|
||||
createPart(input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const NewPart = () => {
|
||||
const { addMessage } = useFlash()
|
||||
const [createPart, { loading, error }] = useMutation(CREATE_PART_MUTATION, {
|
||||
onCompleted: () => {
|
||||
navigate(routes.parts())
|
||||
addMessage('Part created.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onSave = (input) => {
|
||||
createPart({ variables: { input } })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">New Part</h2>
|
||||
</header>
|
||||
<div className="rw-segment-main">
|
||||
<PartForm onSave={onSave} loading={loading} error={error} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewPart
|
||||
41
web/src/components/NewPartReaction/NewPartReaction.js
Normal file
41
web/src/components/NewPartReaction/NewPartReaction.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import PartReactionForm from 'src/components/PartReactionForm'
|
||||
|
||||
const CREATE_PART_REACTION_MUTATION = gql`
|
||||
mutation CreatePartReactionMutation($input: CreatePartReactionInput!) {
|
||||
createPartReaction(input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const NewPartReaction = () => {
|
||||
const { addMessage } = useFlash()
|
||||
const [createPartReaction, { loading, error }] = useMutation(
|
||||
CREATE_PART_REACTION_MUTATION,
|
||||
{
|
||||
onCompleted: () => {
|
||||
navigate(routes.partReactions())
|
||||
addMessage('PartReaction created.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const onSave = (input) => {
|
||||
createPartReaction({ variables: { input } })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">New PartReaction</h2>
|
||||
</header>
|
||||
<div className="rw-segment-main">
|
||||
<PartReactionForm onSave={onSave} loading={loading} error={error} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewPartReaction
|
||||
38
web/src/components/NewUser/NewUser.js
Normal file
38
web/src/components/NewUser/NewUser.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import UserForm from 'src/components/UserForm'
|
||||
|
||||
const CREATE_USER_MUTATION = gql`
|
||||
mutation CreateUserMutation($input: CreateUserInput!) {
|
||||
createUser(input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const NewUser = () => {
|
||||
const { addMessage } = useFlash()
|
||||
const [createUser, { loading, error }] = useMutation(CREATE_USER_MUTATION, {
|
||||
onCompleted: () => {
|
||||
navigate(routes.users())
|
||||
addMessage('User created.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onSave = (input) => {
|
||||
createUser({ variables: { input } })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">New User</h2>
|
||||
</header>
|
||||
<div className="rw-segment-main">
|
||||
<UserForm onSave={onSave} loading={loading} error={error} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewUser
|
||||
111
web/src/components/Part/Part.js
Normal file
111
web/src/components/Part/Part.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes, navigate } from '@redwoodjs/router'
|
||||
|
||||
const DELETE_PART_MUTATION = gql`
|
||||
mutation DeletePartMutation($id: String!) {
|
||||
deletePart(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const jsonDisplay = (obj) => {
|
||||
return (
|
||||
<pre>
|
||||
<code>{JSON.stringify(obj, null, 2)}</code>
|
||||
</pre>
|
||||
)
|
||||
}
|
||||
|
||||
const timeTag = (datetime) => {
|
||||
return (
|
||||
<time dateTime={datetime} title={datetime}>
|
||||
{new Date(datetime).toUTCString()}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
const checkboxInputTag = (checked) => {
|
||||
return <input type="checkbox" checked={checked} disabled />
|
||||
}
|
||||
|
||||
const Part = ({ part }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [deletePart] = useMutation(DELETE_PART_MUTATION, {
|
||||
onCompleted: () => {
|
||||
navigate(routes.parts())
|
||||
addMessage('Part deleted.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onDeleteClick = (id) => {
|
||||
if (confirm('Are you sure you want to delete part ' + id + '?')) {
|
||||
deletePart({ variables: { id } })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">
|
||||
Part {part.id} Detail
|
||||
</h2>
|
||||
</header>
|
||||
<table className="rw-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<td>{part.id}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<td>{part.title}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
<td>{part.description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Code</th>
|
||||
<td>{part.code}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Main image</th>
|
||||
<td>{part.mainImage}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Created at</th>
|
||||
<td>{timeTag(part.createdAt)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Updated at</th>
|
||||
<td>{timeTag(part.updatedAt)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>User id</th>
|
||||
<td>{part.userId}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<nav className="rw-button-group">
|
||||
<Link
|
||||
to={routes.editPart({ id: part.id })}
|
||||
className="rw-button rw-button-blue"
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
<a
|
||||
href="#"
|
||||
className="rw-button rw-button-red"
|
||||
onClick={() => onDeleteClick(part.id)}
|
||||
>
|
||||
Delete
|
||||
</a>
|
||||
</nav>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Part
|
||||
24
web/src/components/PartCell/PartCell.js
Normal file
24
web/src/components/PartCell/PartCell.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import Part from 'src/components/Part'
|
||||
|
||||
export const QUERY = gql`
|
||||
query FIND_PART_BY_ID($id: String!) {
|
||||
part: part(id: $id) {
|
||||
id
|
||||
title
|
||||
description
|
||||
code
|
||||
mainImage
|
||||
createdAt
|
||||
updatedAt
|
||||
userId
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Empty = () => <div>Part not found</div>
|
||||
|
||||
export const Success = ({ part }) => {
|
||||
return <Part part={part} />
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import axios from 'axios'
|
||||
import ReactCrop from 'react-image-crop'
|
||||
import { Dialog } from '@material-ui/core'
|
||||
import { Image as CloudinaryImage } from 'cloudinary-react'
|
||||
import 'react-image-crop/dist/ReactCrop.css'
|
||||
import Svg from 'src/components/Svg/Svg.js'
|
||||
|
||||
const CLOUDINARY_UPLOAD_PRESET = "CadHub_project_images";
|
||||
const CLOUDINARY_UPLOAD_URL = "https://api.cloudinary.com/v1_1/irevdev/upload";
|
||||
|
||||
export default function ImageUploader({ onImageUpload, imageUrl }) {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const [file, setFile] = useState()
|
||||
const [cloudinaryId, setCloudinaryId] = useState(imageUrl)
|
||||
const [imageObj, setImageObj] = useState()
|
||||
const [crop, setCrop] = useState({
|
||||
aspect: 16 / 9,
|
||||
unit: '%',
|
||||
width: 100,
|
||||
});
|
||||
async function handleImageUpload() {
|
||||
const croppedFile = await getCroppedImg(imageObj, crop, 'avatar')
|
||||
console.log(croppedFile)
|
||||
const imageData = new FormData();
|
||||
imageData.append('upload_preset', CLOUDINARY_UPLOAD_PRESET);
|
||||
imageData.append('file', croppedFile);
|
||||
let upload = axios.post(CLOUDINARY_UPLOAD_URL, imageData)
|
||||
try {
|
||||
const { data } = await upload
|
||||
if (data && data.public_id !== "") {
|
||||
onImageUpload({cloudinaryPublicId: data.public_id})
|
||||
setCloudinaryId(data.public_id)
|
||||
setIsModalOpen(false)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('ERROR', e)
|
||||
}
|
||||
}
|
||||
// Drag and Drop
|
||||
const onDrop = useCallback(acceptedFiles => {
|
||||
setIsModalOpen(true)
|
||||
const fileReader = new FileReader()
|
||||
fileReader.onload = () => {
|
||||
setFile(fileReader.result)
|
||||
}
|
||||
fileReader.readAsDataURL(acceptedFiles[0])
|
||||
}, []);
|
||||
|
||||
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
|
||||
return (
|
||||
<div className="m-8">
|
||||
<div className="w-full relative" {...getRootProps()}>
|
||||
{cloudinaryId && <button className="absolute z-10 w-full inset-0 bg-indigo-900 opacity-50 flex justify-center items-center">
|
||||
<Svg name="pencil" strokeWidth={2} className="text-gray-300 h-48 w-48" />
|
||||
</button>}
|
||||
<input {...getInputProps()} />
|
||||
{cloudinaryId && <div className="relative">
|
||||
<CloudinaryImage
|
||||
className="object-cover w-full rounded shadow"
|
||||
cloudName="irevdev"
|
||||
publicId={cloudinaryId}
|
||||
width="600"
|
||||
crop="scale"
|
||||
/>
|
||||
</div>}
|
||||
{!cloudinaryId && <button className="absolute inset-0"></button>}
|
||||
{!cloudinaryId && <div className="mt-3 text-indigo-500 border-dashed border border-indigo-500 py-8 text-center rounded-lg w-full">
|
||||
Drop files here ...
|
||||
or <span className="group flex w-full items-center justify-center py-4">
|
||||
<span className="bg-indigo-500 shadow rounded text-gray-200 cursor-pointer p-2 hover:shadow-lg transform hover:-translate-y-1 transition-all duration-150">upload</span>
|
||||
</span>
|
||||
</div>}
|
||||
</div>
|
||||
<Dialog
|
||||
open={isModalOpen}
|
||||
onClose={() => setIsModalOpen(false)}
|
||||
>
|
||||
<div className="p-4">
|
||||
<ReactCrop src={file} crop={crop} onImageLoaded={(image) => setImageObj(image)} onChange={newCrop => setCrop(newCrop)} />
|
||||
<Button onClick={handleImageUpload} variant="outlined">Upload</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getCroppedImg(image, crop, fileName) {
|
||||
const canvas = document.createElement('canvas');
|
||||
const scaleX = image.naturalWidth / image.width;
|
||||
const scaleY = image.naturalHeight / image.height;
|
||||
canvas.width = crop.width;
|
||||
canvas.height = crop.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(
|
||||
image,
|
||||
crop.x * scaleX,
|
||||
crop.y * scaleY,
|
||||
crop.width * scaleX,
|
||||
crop.height * scaleY,
|
||||
0,
|
||||
0,
|
||||
crop.width,
|
||||
crop.height
|
||||
);
|
||||
|
||||
// As Base64 string
|
||||
// const base64Image = canvas.toDataURL('image/jpeg');
|
||||
|
||||
// As a blob
|
||||
return new Promise((resolve, reject) => {
|
||||
canvas.toBlob(blob => {
|
||||
blob.name = fileName;
|
||||
resolve(blob);
|
||||
}, 'image/jpeg', 1);
|
||||
});
|
||||
}
|
||||
|
||||
115
web/src/components/PartForm/PartForm.js
Normal file
115
web/src/components/PartForm/PartForm.js
Normal file
@@ -0,0 +1,115 @@
|
||||
import {
|
||||
Form,
|
||||
FormError,
|
||||
FieldError,
|
||||
Label,
|
||||
TextField,
|
||||
Submit,
|
||||
} from '@redwoodjs/forms'
|
||||
|
||||
const PartForm = (props) => {
|
||||
const onSubmit = (data) => {
|
||||
props.onSave(data, props?.part?.id)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-form-wrapper">
|
||||
<Form onSubmit={onSubmit} error={props.error}>
|
||||
<FormError
|
||||
error={props.error}
|
||||
wrapperClassName="rw-form-error-wrapper"
|
||||
titleClassName="rw-form-error-title"
|
||||
listClassName="rw-form-error-list"
|
||||
/>
|
||||
|
||||
<Label
|
||||
name="title"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Title
|
||||
</Label>
|
||||
<TextField
|
||||
name="title"
|
||||
defaultValue={props.part?.title}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="title" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="description"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Description
|
||||
</Label>
|
||||
<TextField
|
||||
name="description"
|
||||
defaultValue={props.part?.description}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="description" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="code"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Code
|
||||
</Label>
|
||||
<TextField
|
||||
name="code"
|
||||
defaultValue={props.part?.code}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="code" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="mainImage"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Main image
|
||||
</Label>
|
||||
<TextField
|
||||
name="mainImage"
|
||||
defaultValue={props.part?.mainImage}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="mainImage" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="userId"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
User id
|
||||
</Label>
|
||||
<TextField
|
||||
name="userId"
|
||||
defaultValue={props.part?.userId}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="userId" className="rw-field-error" />
|
||||
|
||||
<div className="rw-button-group">
|
||||
<Submit disabled={props.loading} className="rw-button rw-button-blue">
|
||||
Save
|
||||
</Submit>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartForm
|
||||
103
web/src/components/PartReaction/PartReaction.js
Normal file
103
web/src/components/PartReaction/PartReaction.js
Normal file
@@ -0,0 +1,103 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes, navigate } from '@redwoodjs/router'
|
||||
|
||||
const DELETE_PART_REACTION_MUTATION = gql`
|
||||
mutation DeletePartReactionMutation($id: String!) {
|
||||
deletePartReaction(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const jsonDisplay = (obj) => {
|
||||
return (
|
||||
<pre>
|
||||
<code>{JSON.stringify(obj, null, 2)}</code>
|
||||
</pre>
|
||||
)
|
||||
}
|
||||
|
||||
const timeTag = (datetime) => {
|
||||
return (
|
||||
<time dateTime={datetime} title={datetime}>
|
||||
{new Date(datetime).toUTCString()}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
const checkboxInputTag = (checked) => {
|
||||
return <input type="checkbox" checked={checked} disabled />
|
||||
}
|
||||
|
||||
const PartReaction = ({ partReaction }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [deletePartReaction] = useMutation(DELETE_PART_REACTION_MUTATION, {
|
||||
onCompleted: () => {
|
||||
navigate(routes.partReactions())
|
||||
addMessage('PartReaction deleted.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onDeleteClick = (id) => {
|
||||
if (confirm('Are you sure you want to delete partReaction ' + id + '?')) {
|
||||
deletePartReaction({ variables: { id } })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">
|
||||
PartReaction {partReaction.id} Detail
|
||||
</h2>
|
||||
</header>
|
||||
<table className="rw-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<td>{partReaction.id}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Emote</th>
|
||||
<td>{partReaction.emote}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>User id</th>
|
||||
<td>{partReaction.userId}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Part id</th>
|
||||
<td>{partReaction.partId}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Created at</th>
|
||||
<td>{timeTag(partReaction.createdAt)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Updated at</th>
|
||||
<td>{timeTag(partReaction.updatedAt)}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<nav className="rw-button-group">
|
||||
<Link
|
||||
to={routes.editPartReaction({ id: partReaction.id })}
|
||||
className="rw-button rw-button-blue"
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
<a
|
||||
href="#"
|
||||
className="rw-button rw-button-red"
|
||||
onClick={() => onDeleteClick(partReaction.id)}
|
||||
>
|
||||
Delete
|
||||
</a>
|
||||
</nav>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartReaction
|
||||
22
web/src/components/PartReactionCell/PartReactionCell.js
Normal file
22
web/src/components/PartReactionCell/PartReactionCell.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import PartReaction from 'src/components/PartReaction'
|
||||
|
||||
export const QUERY = gql`
|
||||
query FIND_PART_REACTION_BY_ID($id: String!) {
|
||||
partReaction: partReaction(id: $id) {
|
||||
id
|
||||
emote
|
||||
userId
|
||||
partId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Empty = () => <div>PartReaction not found</div>
|
||||
|
||||
export const Success = ({ partReaction }) => {
|
||||
return <PartReaction partReaction={partReaction} />
|
||||
}
|
||||
83
web/src/components/PartReactionForm/PartReactionForm.js
Normal file
83
web/src/components/PartReactionForm/PartReactionForm.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
Form,
|
||||
FormError,
|
||||
FieldError,
|
||||
Label,
|
||||
TextField,
|
||||
Submit,
|
||||
} from '@redwoodjs/forms'
|
||||
|
||||
const PartReactionForm = (props) => {
|
||||
const onSubmit = (data) => {
|
||||
props.onSave(data, props?.partReaction?.id)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-form-wrapper">
|
||||
<Form onSubmit={onSubmit} error={props.error}>
|
||||
<FormError
|
||||
error={props.error}
|
||||
wrapperClassName="rw-form-error-wrapper"
|
||||
titleClassName="rw-form-error-title"
|
||||
listClassName="rw-form-error-list"
|
||||
/>
|
||||
|
||||
<Label
|
||||
name="emote"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Emote
|
||||
</Label>
|
||||
<TextField
|
||||
name="emote"
|
||||
defaultValue={props.partReaction?.emote}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="emote" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="userId"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
User id
|
||||
</Label>
|
||||
<TextField
|
||||
name="userId"
|
||||
defaultValue={props.partReaction?.userId}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="userId" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="partId"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Part id
|
||||
</Label>
|
||||
<TextField
|
||||
name="partId"
|
||||
defaultValue={props.partReaction?.partId}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="partId" className="rw-field-error" />
|
||||
|
||||
<div className="rw-button-group">
|
||||
<Submit disabled={props.loading} className="rw-button rw-button-blue">
|
||||
Save
|
||||
</Submit>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartReactionForm
|
||||
112
web/src/components/PartReactions/PartReactions.js
Normal file
112
web/src/components/PartReactions/PartReactions.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
|
||||
const DELETE_PART_REACTION_MUTATION = gql`
|
||||
mutation DeletePartReactionMutation($id: String!) {
|
||||
deletePartReaction(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const MAX_STRING_LENGTH = 150
|
||||
|
||||
const truncate = (text) => {
|
||||
let output = text
|
||||
if (text && text.length > MAX_STRING_LENGTH) {
|
||||
output = output.substring(0, MAX_STRING_LENGTH) + '...'
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
const jsonTruncate = (obj) => {
|
||||
return truncate(JSON.stringify(obj, null, 2))
|
||||
}
|
||||
|
||||
const timeTag = (datetime) => {
|
||||
return (
|
||||
<time dateTime={datetime} title={datetime}>
|
||||
{new Date(datetime).toUTCString()}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
const checkboxInputTag = (checked) => {
|
||||
return <input type="checkbox" checked={checked} disabled />
|
||||
}
|
||||
|
||||
const PartReactionsList = ({ partReactions }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [deletePartReaction] = useMutation(DELETE_PART_REACTION_MUTATION, {
|
||||
onCompleted: () => {
|
||||
addMessage('PartReaction deleted.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onDeleteClick = (id) => {
|
||||
if (confirm('Are you sure you want to delete partReaction ' + id + '?')) {
|
||||
deletePartReaction({
|
||||
variables: { id },
|
||||
refetchQueries: ['PART_REACTIONS'],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment rw-table-wrapper-responsive">
|
||||
<table className="rw-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Emote</th>
|
||||
<th>User id</th>
|
||||
<th>Part id</th>
|
||||
<th>Created at</th>
|
||||
<th>Updated at</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{partReactions.map((partReaction) => (
|
||||
<tr key={partReaction.id}>
|
||||
<td>{truncate(partReaction.id)}</td>
|
||||
<td>{truncate(partReaction.emote)}</td>
|
||||
<td>{truncate(partReaction.userId)}</td>
|
||||
<td>{truncate(partReaction.partId)}</td>
|
||||
<td>{timeTag(partReaction.createdAt)}</td>
|
||||
<td>{timeTag(partReaction.updatedAt)}</td>
|
||||
<td>
|
||||
<nav className="rw-table-actions">
|
||||
<Link
|
||||
to={routes.partReaction({ id: partReaction.id })}
|
||||
title={'Show partReaction ' + partReaction.id + ' detail'}
|
||||
className="rw-button rw-button-small"
|
||||
>
|
||||
Show
|
||||
</Link>
|
||||
<Link
|
||||
to={routes.editPartReaction({ id: partReaction.id })}
|
||||
title={'Edit partReaction ' + partReaction.id}
|
||||
className="rw-button rw-button-small rw-button-blue"
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
<a
|
||||
href="#"
|
||||
title={'Delete partReaction ' + partReaction.id}
|
||||
className="rw-button rw-button-small rw-button-red"
|
||||
onClick={() => onDeleteClick(partReaction.id)}
|
||||
>
|
||||
Delete
|
||||
</a>
|
||||
</nav>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartReactionsList
|
||||
33
web/src/components/PartReactionsCell/PartReactionsCell.js
Normal file
33
web/src/components/PartReactionsCell/PartReactionsCell.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
|
||||
import PartReactions from 'src/components/PartReactions'
|
||||
|
||||
export const QUERY = gql`
|
||||
query PART_REACTIONS {
|
||||
partReactions {
|
||||
id
|
||||
emote
|
||||
userId
|
||||
partId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Empty = () => {
|
||||
return (
|
||||
<div className="rw-text-center">
|
||||
{'No partReactions yet. '}
|
||||
<Link to={routes.newPartReaction()} className="rw-link">
|
||||
{'Create one?'}
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Success = ({ partReactions }) => {
|
||||
return <PartReactions partReactions={partReactions} />
|
||||
}
|
||||
113
web/src/components/Parts/Parts.js
Normal file
113
web/src/components/Parts/Parts.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
|
||||
const DELETE_PART_MUTATION = gql`
|
||||
mutation DeletePartMutation($id: String!) {
|
||||
deletePart(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const MAX_STRING_LENGTH = 150
|
||||
|
||||
const truncate = (text) => {
|
||||
let output = text
|
||||
if (text && text.length > MAX_STRING_LENGTH) {
|
||||
output = output.substring(0, MAX_STRING_LENGTH) + '...'
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
const jsonTruncate = (obj) => {
|
||||
return truncate(JSON.stringify(obj, null, 2))
|
||||
}
|
||||
|
||||
const timeTag = (datetime) => {
|
||||
return (
|
||||
<time dateTime={datetime} title={datetime}>
|
||||
{new Date(datetime).toUTCString()}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
const checkboxInputTag = (checked) => {
|
||||
return <input type="checkbox" checked={checked} disabled />
|
||||
}
|
||||
|
||||
const PartsList = ({ parts }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [deletePart] = useMutation(DELETE_PART_MUTATION, {
|
||||
onCompleted: () => {
|
||||
addMessage('Part deleted.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onDeleteClick = (id) => {
|
||||
if (confirm('Are you sure you want to delete part ' + id + '?')) {
|
||||
deletePart({ variables: { id }, refetchQueries: ['PARTS'] })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment rw-table-wrapper-responsive">
|
||||
<table className="rw-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Title</th>
|
||||
<th>Description</th>
|
||||
<th>Code</th>
|
||||
<th>Main image</th>
|
||||
<th>Created at</th>
|
||||
<th>Updated at</th>
|
||||
<th>User id</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{parts.map((part) => (
|
||||
<tr key={part.id}>
|
||||
<td>{truncate(part.id)}</td>
|
||||
<td>{truncate(part.title)}</td>
|
||||
<td>{truncate(part.description)}</td>
|
||||
<td>{truncate(part.code)}</td>
|
||||
<td>{truncate(part.mainImage)}</td>
|
||||
<td>{timeTag(part.createdAt)}</td>
|
||||
<td>{timeTag(part.updatedAt)}</td>
|
||||
<td>{truncate(part.userId)}</td>
|
||||
<td>
|
||||
<nav className="rw-table-actions">
|
||||
<Link
|
||||
to={routes.part({ id: part.id })}
|
||||
title={'Show part ' + part.id + ' detail'}
|
||||
className="rw-button rw-button-small"
|
||||
>
|
||||
Show
|
||||
</Link>
|
||||
<Link
|
||||
to={routes.editPart({ id: part.id })}
|
||||
title={'Edit part ' + part.id}
|
||||
className="rw-button rw-button-small rw-button-blue"
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
<a
|
||||
href="#"
|
||||
title={'Delete part ' + part.id}
|
||||
className="rw-button rw-button-small rw-button-red"
|
||||
onClick={() => onDeleteClick(part.id)}
|
||||
>
|
||||
Delete
|
||||
</a>
|
||||
</nav>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartsList
|
||||
35
web/src/components/PartsCell/PartsCell.js
Normal file
35
web/src/components/PartsCell/PartsCell.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
|
||||
import Parts from 'src/components/Parts'
|
||||
|
||||
export const QUERY = gql`
|
||||
query PARTS {
|
||||
parts {
|
||||
id
|
||||
title
|
||||
description
|
||||
code
|
||||
mainImage
|
||||
createdAt
|
||||
updatedAt
|
||||
userId
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Empty = () => {
|
||||
return (
|
||||
<div className="rw-text-center">
|
||||
{'No parts yet. '}
|
||||
<Link to={routes.newPart()} className="rw-link">
|
||||
{'Create one?'}
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Success = ({ parts }) => {
|
||||
return <Parts parts={parts} />
|
||||
}
|
||||
107
web/src/components/User/User.js
Normal file
107
web/src/components/User/User.js
Normal file
@@ -0,0 +1,107 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes, navigate } from '@redwoodjs/router'
|
||||
|
||||
const DELETE_USER_MUTATION = gql`
|
||||
mutation DeleteUserMutation($id: String!) {
|
||||
deleteUser(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const jsonDisplay = (obj) => {
|
||||
return (
|
||||
<pre>
|
||||
<code>{JSON.stringify(obj, null, 2)}</code>
|
||||
</pre>
|
||||
)
|
||||
}
|
||||
|
||||
const timeTag = (datetime) => {
|
||||
return (
|
||||
<time dateTime={datetime} title={datetime}>
|
||||
{new Date(datetime).toUTCString()}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
const checkboxInputTag = (checked) => {
|
||||
return <input type="checkbox" checked={checked} disabled />
|
||||
}
|
||||
|
||||
const User = ({ user }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [deleteUser] = useMutation(DELETE_USER_MUTATION, {
|
||||
onCompleted: () => {
|
||||
navigate(routes.users())
|
||||
addMessage('User deleted.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onDeleteClick = (id) => {
|
||||
if (confirm('Are you sure you want to delete user ' + id + '?')) {
|
||||
deleteUser({ variables: { id } })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="rw-segment">
|
||||
<header className="rw-segment-header">
|
||||
<h2 className="rw-heading rw-heading-secondary">
|
||||
User {user.id} Detail
|
||||
</h2>
|
||||
</header>
|
||||
<table className="rw-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<td>{user.id}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>User name</th>
|
||||
<td>{user.userName}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<td>{user.email}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Created at</th>
|
||||
<td>{timeTag(user.createdAt)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Updated at</th>
|
||||
<td>{timeTag(user.updatedAt)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<td>{user.image}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Bio</th>
|
||||
<td>{user.bio}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<nav className="rw-button-group">
|
||||
<Link
|
||||
to={routes.editUser({ id: user.id })}
|
||||
className="rw-button rw-button-blue"
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
<a
|
||||
href="#"
|
||||
className="rw-button rw-button-red"
|
||||
onClick={() => onDeleteClick(user.id)}
|
||||
>
|
||||
Delete
|
||||
</a>
|
||||
</nav>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default User
|
||||
23
web/src/components/UserCell/UserCell.js
Normal file
23
web/src/components/UserCell/UserCell.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import User from 'src/components/User'
|
||||
|
||||
export const QUERY = gql`
|
||||
query FIND_USER_BY_ID($id: String!) {
|
||||
user: user(id: $id) {
|
||||
id
|
||||
userName
|
||||
email
|
||||
createdAt
|
||||
updatedAt
|
||||
image
|
||||
bio
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Empty = () => <div>User not found</div>
|
||||
|
||||
export const Success = ({ user }) => {
|
||||
return <User user={user} />
|
||||
}
|
||||
99
web/src/components/UserForm/UserForm.js
Normal file
99
web/src/components/UserForm/UserForm.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import {
|
||||
Form,
|
||||
FormError,
|
||||
FieldError,
|
||||
Label,
|
||||
TextField,
|
||||
Submit,
|
||||
} from '@redwoodjs/forms'
|
||||
|
||||
const UserForm = (props) => {
|
||||
const onSubmit = (data) => {
|
||||
props.onSave(data, props?.user?.id)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-form-wrapper">
|
||||
<Form onSubmit={onSubmit} error={props.error}>
|
||||
<FormError
|
||||
error={props.error}
|
||||
wrapperClassName="rw-form-error-wrapper"
|
||||
titleClassName="rw-form-error-title"
|
||||
listClassName="rw-form-error-list"
|
||||
/>
|
||||
|
||||
<Label
|
||||
name="userName"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
User name
|
||||
</Label>
|
||||
<TextField
|
||||
name="userName"
|
||||
defaultValue={props.user?.userName}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="userName" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="email"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Email
|
||||
</Label>
|
||||
<TextField
|
||||
name="email"
|
||||
defaultValue={props.user?.email}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="email" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="image"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Image
|
||||
</Label>
|
||||
<TextField
|
||||
name="image"
|
||||
defaultValue={props.user?.image}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="image" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="bio"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Bio
|
||||
</Label>
|
||||
<TextField
|
||||
name="bio"
|
||||
defaultValue={props.user?.bio}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="bio" className="rw-field-error" />
|
||||
|
||||
<div className="rw-button-group">
|
||||
<Submit disabled={props.loading} className="rw-button rw-button-blue">
|
||||
Save
|
||||
</Submit>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserForm
|
||||
111
web/src/components/Users/Users.js
Normal file
111
web/src/components/Users/Users.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
|
||||
const DELETE_USER_MUTATION = gql`
|
||||
mutation DeleteUserMutation($id: String!) {
|
||||
deleteUser(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const MAX_STRING_LENGTH = 150
|
||||
|
||||
const truncate = (text) => {
|
||||
let output = text
|
||||
if (text && text.length > MAX_STRING_LENGTH) {
|
||||
output = output.substring(0, MAX_STRING_LENGTH) + '...'
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
const jsonTruncate = (obj) => {
|
||||
return truncate(JSON.stringify(obj, null, 2))
|
||||
}
|
||||
|
||||
const timeTag = (datetime) => {
|
||||
return (
|
||||
<time dateTime={datetime} title={datetime}>
|
||||
{new Date(datetime).toUTCString()}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
const checkboxInputTag = (checked) => {
|
||||
return <input type="checkbox" checked={checked} disabled />
|
||||
}
|
||||
|
||||
const UsersList = ({ users }) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [deleteUser] = useMutation(DELETE_USER_MUTATION, {
|
||||
onCompleted: () => {
|
||||
addMessage('User deleted.', { classes: 'rw-flash-success' })
|
||||
},
|
||||
})
|
||||
|
||||
const onDeleteClick = (id) => {
|
||||
if (confirm('Are you sure you want to delete user ' + id + '?')) {
|
||||
deleteUser({ variables: { id }, refetchQueries: ['USERS'] })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rw-segment rw-table-wrapper-responsive">
|
||||
<table className="rw-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>User name</th>
|
||||
<th>Email</th>
|
||||
<th>Created at</th>
|
||||
<th>Updated at</th>
|
||||
<th>Image</th>
|
||||
<th>Bio</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map((user) => (
|
||||
<tr key={user.id}>
|
||||
<td>{truncate(user.id)}</td>
|
||||
<td>{truncate(user.userName)}</td>
|
||||
<td>{truncate(user.email)}</td>
|
||||
<td>{timeTag(user.createdAt)}</td>
|
||||
<td>{timeTag(user.updatedAt)}</td>
|
||||
<td>{truncate(user.image)}</td>
|
||||
<td>{truncate(user.bio)}</td>
|
||||
<td>
|
||||
<nav className="rw-table-actions">
|
||||
<Link
|
||||
to={routes.user({ id: user.id })}
|
||||
title={'Show user ' + user.id + ' detail'}
|
||||
className="rw-button rw-button-small"
|
||||
>
|
||||
Show
|
||||
</Link>
|
||||
<Link
|
||||
to={routes.editUser({ id: user.id })}
|
||||
title={'Edit user ' + user.id}
|
||||
className="rw-button rw-button-small rw-button-blue"
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
<a
|
||||
href="#"
|
||||
title={'Delete user ' + user.id}
|
||||
className="rw-button rw-button-small rw-button-red"
|
||||
onClick={() => onDeleteClick(user.id)}
|
||||
>
|
||||
Delete
|
||||
</a>
|
||||
</nav>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UsersList
|
||||
34
web/src/components/UsersCell/UsersCell.js
Normal file
34
web/src/components/UsersCell/UsersCell.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
|
||||
import Users from 'src/components/Users'
|
||||
|
||||
export const QUERY = gql`
|
||||
query USERS {
|
||||
users {
|
||||
id
|
||||
userName
|
||||
email
|
||||
createdAt
|
||||
updatedAt
|
||||
image
|
||||
bio
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const Loading = () => <div>Loading...</div>
|
||||
|
||||
export const Empty = () => {
|
||||
return (
|
||||
<div className="rw-text-center">
|
||||
{'No users yet. '}
|
||||
<Link to={routes.newUser()} className="rw-link">
|
||||
{'Create one?'}
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Success = ({ users }) => {
|
||||
return <Users users={users} />
|
||||
}
|
||||
23
web/src/layouts/CommentsLayout/CommentsLayout.js
Normal file
23
web/src/layouts/CommentsLayout/CommentsLayout.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
import { Flash } from '@redwoodjs/web'
|
||||
|
||||
const CommentsLayout = (props) => {
|
||||
return (
|
||||
<div className="rw-scaffold">
|
||||
<Flash timeout={1000} />
|
||||
<header className="rw-header">
|
||||
<h1 className="rw-heading rw-heading-primary">
|
||||
<Link to={routes.comments()} className="rw-link">
|
||||
Comments
|
||||
</Link>
|
||||
</h1>
|
||||
<Link to={routes.newComment()} className="rw-button rw-button-green">
|
||||
<div className="rw-button-icon">+</div> New Comment
|
||||
</Link>
|
||||
</header>
|
||||
<main className="rw-main">{props.children}</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommentsLayout
|
||||
@@ -18,7 +18,7 @@ const MainLayout = ({ children }) => {
|
||||
<Link to={routes.home()}>
|
||||
<Tooltip title="We need a logo!" >
|
||||
|
||||
<img src={logo} style={{marginLeft : '50px'}}/>
|
||||
<img src={logo} style={{marginLeft : '50px'}}/>
|
||||
|
||||
</Tooltip>
|
||||
</Link>
|
||||
@@ -35,9 +35,9 @@ const MainLayout = ({ children }) => {
|
||||
</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()}>
|
||||
{/* <Link to={routes.newPart()}> */}
|
||||
<Svg name="plus" className="text-indigo-300" />
|
||||
</Link>
|
||||
{/* </Link> */}
|
||||
</li>
|
||||
{
|
||||
isAuthenticated ?
|
||||
|
||||
26
web/src/layouts/PartReactionsLayout/PartReactionsLayout.js
Normal file
26
web/src/layouts/PartReactionsLayout/PartReactionsLayout.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
import { Flash } from '@redwoodjs/web'
|
||||
|
||||
const PartReactionsLayout = (props) => {
|
||||
return (
|
||||
<div className="rw-scaffold">
|
||||
<Flash timeout={1000} />
|
||||
<header className="rw-header">
|
||||
<h1 className="rw-heading rw-heading-primary">
|
||||
<Link to={routes.partReactions()} className="rw-link">
|
||||
PartReactions
|
||||
</Link>
|
||||
</h1>
|
||||
<Link
|
||||
to={routes.newPartReaction()}
|
||||
className="rw-button rw-button-green"
|
||||
>
|
||||
<div className="rw-button-icon">+</div> New PartReaction
|
||||
</Link>
|
||||
</header>
|
||||
<main className="rw-main">{props.children}</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartReactionsLayout
|
||||
23
web/src/layouts/PartsLayout/PartsLayout.js
Normal file
23
web/src/layouts/PartsLayout/PartsLayout.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
import { Flash } from '@redwoodjs/web'
|
||||
|
||||
const PartsLayout = (props) => {
|
||||
return (
|
||||
<div className="rw-scaffold">
|
||||
<Flash timeout={1000} />
|
||||
<header className="rw-header">
|
||||
<h1 className="rw-heading rw-heading-primary">
|
||||
<Link to={routes.parts()} className="rw-link">
|
||||
Parts
|
||||
</Link>
|
||||
</h1>
|
||||
<Link to={routes.newPart()} className="rw-button rw-button-green">
|
||||
<div className="rw-button-icon">+</div> New Part
|
||||
</Link>
|
||||
</header>
|
||||
<main className="rw-main">{props.children}</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartsLayout
|
||||
23
web/src/layouts/UsersLayout/UsersLayout.js
Normal file
23
web/src/layouts/UsersLayout/UsersLayout.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
import { Flash } from '@redwoodjs/web'
|
||||
|
||||
const UsersLayout = (props) => {
|
||||
return (
|
||||
<div className="rw-scaffold">
|
||||
<Flash timeout={1000} />
|
||||
<header className="rw-header">
|
||||
<h1 className="rw-heading rw-heading-primary">
|
||||
<Link to={routes.users()} className="rw-link">
|
||||
Users
|
||||
</Link>
|
||||
</h1>
|
||||
<Link to={routes.newUser()} className="rw-button rw-button-green">
|
||||
<div className="rw-button-icon">+</div> New User
|
||||
</Link>
|
||||
</header>
|
||||
<main className="rw-main">{props.children}</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UsersLayout
|
||||
12
web/src/pages/CommentPage/CommentPage.js
Normal file
12
web/src/pages/CommentPage/CommentPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import CommentsLayout from 'src/layouts/CommentsLayout'
|
||||
import CommentCell from 'src/components/CommentCell'
|
||||
|
||||
const CommentPage = ({ id }) => {
|
||||
return (
|
||||
<CommentsLayout>
|
||||
<CommentCell id={id} />
|
||||
</CommentsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommentPage
|
||||
12
web/src/pages/CommentsPage/CommentsPage.js
Normal file
12
web/src/pages/CommentsPage/CommentsPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import CommentsLayout from 'src/layouts/CommentsLayout'
|
||||
import CommentsCell from 'src/components/CommentsCell'
|
||||
|
||||
const CommentsPage = () => {
|
||||
return (
|
||||
<CommentsLayout>
|
||||
<CommentsCell />
|
||||
</CommentsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommentsPage
|
||||
12
web/src/pages/EditCommentPage/EditCommentPage.js
Normal file
12
web/src/pages/EditCommentPage/EditCommentPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import CommentsLayout from 'src/layouts/CommentsLayout'
|
||||
import EditCommentCell from 'src/components/EditCommentCell'
|
||||
|
||||
const EditCommentPage = ({ id }) => {
|
||||
return (
|
||||
<CommentsLayout>
|
||||
<EditCommentCell id={id} />
|
||||
</CommentsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditCommentPage
|
||||
12
web/src/pages/EditPartPage/EditPartPage.js
Normal file
12
web/src/pages/EditPartPage/EditPartPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import PartsLayout from 'src/layouts/PartsLayout'
|
||||
import EditPartCell from 'src/components/EditPartCell'
|
||||
|
||||
const EditPartPage = ({ id }) => {
|
||||
return (
|
||||
<PartsLayout>
|
||||
<EditPartCell id={id} />
|
||||
</PartsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditPartPage
|
||||
12
web/src/pages/EditPartReactionPage/EditPartReactionPage.js
Normal file
12
web/src/pages/EditPartReactionPage/EditPartReactionPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import PartReactionsLayout from 'src/layouts/PartReactionsLayout'
|
||||
import EditPartReactionCell from 'src/components/EditPartReactionCell'
|
||||
|
||||
const EditPartReactionPage = ({ id }) => {
|
||||
return (
|
||||
<PartReactionsLayout>
|
||||
<EditPartReactionCell id={id} />
|
||||
</PartReactionsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditPartReactionPage
|
||||
12
web/src/pages/EditUserPage/EditUserPage.js
Normal file
12
web/src/pages/EditUserPage/EditUserPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import UsersLayout from 'src/layouts/UsersLayout'
|
||||
import EditUserCell from 'src/components/EditUserCell'
|
||||
|
||||
const EditUserPage = ({ id }) => {
|
||||
return (
|
||||
<UsersLayout>
|
||||
<EditUserCell id={id} />
|
||||
</UsersLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditUserPage
|
||||
@@ -1,5 +1,5 @@
|
||||
import MainLayout from 'src/layouts/MainLayout'
|
||||
import BlogPostsCell from 'src/components/BlogPostsCell'
|
||||
// import BlogPostsCell from 'src/components/BlogPostsCell'
|
||||
import { initialize } from 'src/cascade/js/MainPage/CascadeMain'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
@@ -27,7 +27,7 @@ Translate([-100, 0, 100], Text3D("cadhub.xyz"));
|
||||
// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!
|
||||
`;
|
||||
|
||||
const HomePage = () => {
|
||||
const HomePage1 = () => {
|
||||
const [code, setCode] = useState(starterCode)
|
||||
useEffect(() => {
|
||||
const sickCallback = (code) => setCode(code)
|
||||
@@ -73,4 +73,12 @@ const HomePage = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const HomePage = () => {
|
||||
return (
|
||||
<MainLayout>
|
||||
hi
|
||||
</MainLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default HomePage
|
||||
|
||||
12
web/src/pages/NewCommentPage/NewCommentPage.js
Normal file
12
web/src/pages/NewCommentPage/NewCommentPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import CommentsLayout from 'src/layouts/CommentsLayout'
|
||||
import NewComment from 'src/components/NewComment'
|
||||
|
||||
const NewCommentPage = () => {
|
||||
return (
|
||||
<CommentsLayout>
|
||||
<NewComment />
|
||||
</CommentsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewCommentPage
|
||||
12
web/src/pages/NewPartPage/NewPartPage.js
Normal file
12
web/src/pages/NewPartPage/NewPartPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import PartsLayout from 'src/layouts/PartsLayout'
|
||||
import NewPart from 'src/components/NewPart'
|
||||
|
||||
const NewPartPage = () => {
|
||||
return (
|
||||
<PartsLayout>
|
||||
<NewPart />
|
||||
</PartsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewPartPage
|
||||
12
web/src/pages/NewPartReactionPage/NewPartReactionPage.js
Normal file
12
web/src/pages/NewPartReactionPage/NewPartReactionPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import PartReactionsLayout from 'src/layouts/PartReactionsLayout'
|
||||
import NewPartReaction from 'src/components/NewPartReaction'
|
||||
|
||||
const NewPartReactionPage = () => {
|
||||
return (
|
||||
<PartReactionsLayout>
|
||||
<NewPartReaction />
|
||||
</PartReactionsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewPartReactionPage
|
||||
12
web/src/pages/NewUserPage/NewUserPage.js
Normal file
12
web/src/pages/NewUserPage/NewUserPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import UsersLayout from 'src/layouts/UsersLayout'
|
||||
import NewUser from 'src/components/NewUser'
|
||||
|
||||
const NewUserPage = () => {
|
||||
return (
|
||||
<UsersLayout>
|
||||
<NewUser />
|
||||
</UsersLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewUserPage
|
||||
12
web/src/pages/PartPage/PartPage.js
Normal file
12
web/src/pages/PartPage/PartPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import PartsLayout from 'src/layouts/PartsLayout'
|
||||
import PartCell from 'src/components/PartCell'
|
||||
|
||||
const PartPage = ({ id }) => {
|
||||
return (
|
||||
<PartsLayout>
|
||||
<PartCell id={id} />
|
||||
</PartsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartPage
|
||||
12
web/src/pages/PartReactionPage/PartReactionPage.js
Normal file
12
web/src/pages/PartReactionPage/PartReactionPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import PartReactionsLayout from 'src/layouts/PartReactionsLayout'
|
||||
import PartReactionCell from 'src/components/PartReactionCell'
|
||||
|
||||
const PartReactionPage = ({ id }) => {
|
||||
return (
|
||||
<PartReactionsLayout>
|
||||
<PartReactionCell id={id} />
|
||||
</PartReactionsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartReactionPage
|
||||
12
web/src/pages/PartReactionsPage/PartReactionsPage.js
Normal file
12
web/src/pages/PartReactionsPage/PartReactionsPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import PartReactionsLayout from 'src/layouts/PartReactionsLayout'
|
||||
import PartReactionsCell from 'src/components/PartReactionsCell'
|
||||
|
||||
const PartReactionsPage = () => {
|
||||
return (
|
||||
<PartReactionsLayout>
|
||||
<PartReactionsCell />
|
||||
</PartReactionsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartReactionsPage
|
||||
12
web/src/pages/PartsPage/PartsPage.js
Normal file
12
web/src/pages/PartsPage/PartsPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import PartsLayout from 'src/layouts/PartsLayout'
|
||||
import PartsCell from 'src/components/PartsCell'
|
||||
|
||||
const PartsPage = () => {
|
||||
return (
|
||||
<PartsLayout>
|
||||
<PartsCell />
|
||||
</PartsLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartsPage
|
||||
12
web/src/pages/UserPage/UserPage.js
Normal file
12
web/src/pages/UserPage/UserPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import UsersLayout from 'src/layouts/UsersLayout'
|
||||
import UserCell from 'src/components/UserCell'
|
||||
|
||||
const UserPage = ({ id }) => {
|
||||
return (
|
||||
<UsersLayout>
|
||||
<UserCell id={id} />
|
||||
</UsersLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserPage
|
||||
12
web/src/pages/UsersPage/UsersPage.js
Normal file
12
web/src/pages/UsersPage/UsersPage.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import UsersLayout from 'src/layouts/UsersLayout'
|
||||
import UsersCell from 'src/components/UsersCell'
|
||||
|
||||
const UsersPage = () => {
|
||||
return (
|
||||
<UsersLayout>
|
||||
<UsersCell />
|
||||
</UsersLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default UsersPage
|
||||
Reference in New Issue
Block a user