-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
738 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
export const schema = gql` | ||
type Product { | ||
id: Int! | ||
name: String! | ||
description: String! | ||
price_cents: Int! | ||
createdAt: DateTime! | ||
} | ||
type Query { | ||
products: [Product] | ||
product(id: Int!): Product | ||
} | ||
input ProductInput { | ||
name: String | ||
description: String | ||
price_cents: Int | ||
} | ||
type Mutation { | ||
createProduct(input: ProductInput!): Product | ||
updateProduct(id: Int!, input: ProductInput!): Product | ||
deleteProduct(id: Int!): Product | ||
} | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { db } from 'src/lib/db' | ||
|
||
export const products = () => { | ||
return db.product.findMany() | ||
} | ||
|
||
export const product = ({ id }) => { | ||
return db.product.findOne({ | ||
where: { id }, | ||
}) | ||
} | ||
|
||
export const createProduct = ({ input }) => { | ||
return db.product.create({ | ||
data: input, | ||
}) | ||
} | ||
|
||
export const updateProduct = ({ id, input }) => { | ||
return db.product.update({ | ||
data: input, | ||
where: { id }, | ||
}) | ||
} | ||
|
||
export const deleteProduct = ({ id }) => { | ||
return db.product.delete({ | ||
where: { id }, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { products } from './products' | ||
|
||
describe('products', () => { | ||
it('returns true', () => { | ||
expect(true).toBe(true) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { useMutation } from '@redwoodjs/web' | ||
import { navigate, routes } from '@redwoodjs/router' | ||
import ProductForm from 'src/components/ProductForm' | ||
|
||
export const QUERY = gql` | ||
query FIND_POST_BY_ID($id: Int!) { | ||
product: product(id: $id) { | ||
id | ||
name | ||
description | ||
price_cents | ||
createdAt | ||
} | ||
} | ||
` | ||
const UPDATE_POST_MUTATION = gql` | ||
mutation UpdateProductMutation($id: Int!, $input: ProductInput!) { | ||
updateProduct(id: $id, input: $input) { | ||
id | ||
} | ||
} | ||
` | ||
|
||
export const Loading = () => <div>Loading...</div> | ||
|
||
export const Success = ({ product }) => { | ||
const [updateProduct, { loading, error }] = useMutation(UPDATE_POST_MUTATION, { | ||
onCompleted: () => { | ||
navigate(routes.products()) | ||
}, | ||
}) | ||
|
||
const onSave = (input, id) => { | ||
updateProduct({ variables: { id, input } }) | ||
} | ||
|
||
return ( | ||
<div className="bg-white border rounded-lg overflow-hidden"> | ||
<header className="bg-gray-300 text-gray-700 py-3 px-4"> | ||
<h2 className="text-sm font-semibold">Edit Product {product.id}</h2> | ||
</header> | ||
<div className="bg-gray-100 p-4"> | ||
<ProductForm product={product} onSave={onSave} error={error} loading={loading} /> | ||
</div> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { useMutation } from '@redwoodjs/web' | ||
import { navigate, routes } from '@redwoodjs/router' | ||
import ProductForm from 'src/components/ProductForm' | ||
|
||
const CREATE_POST_MUTATION = gql` | ||
mutation CreateProductMutation($input: ProductInput!) { | ||
createProduct(input: $input) { | ||
id | ||
} | ||
} | ||
` | ||
|
||
const NewProduct = () => { | ||
const [createProduct, { loading, error }] = useMutation( | ||
CREATE_POST_MUTATION, | ||
{ | ||
onCompleted: () => { | ||
navigate(routes.products()) | ||
}, | ||
} | ||
) | ||
|
||
const onSave = (input) => { | ||
createProduct({ variables: { input } }) | ||
} | ||
|
||
return ( | ||
<div className="bg-white border rounded-lg overflow-hidden"> | ||
<header className="bg-gray-300 text-gray-700 py-3 px-4"> | ||
<h2 className="text-sm font-semibold">New Product</h2> | ||
</header> | ||
<div className="bg-gray-100 p-4"> | ||
<ProductForm onSave={onSave} loading={loading} error={error} /> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default NewProduct |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { useMutation } from '@redwoodjs/web' | ||
import { Link, routes, navigate } from '@redwoodjs/router' | ||
|
||
const DELETE_POST_MUTATION = gql` | ||
mutation DeleteProductMutation($id: Int!) { | ||
deleteProduct(id: $id) { | ||
id | ||
} | ||
} | ||
` | ||
|
||
const Product = ({ product }) => { | ||
const [deleteProduct] = useMutation(DELETE_POST_MUTATION, { | ||
onCompleted: () => { | ||
navigate(routes.products()) | ||
location.reload() | ||
}, | ||
}) | ||
|
||
const onDeleteClick = (id) => { | ||
if (confirm('Are you sure you want to delete product ' + id + '?')) { | ||
deleteProduct({ variables: { id } }) | ||
} | ||
} | ||
|
||
return ( | ||
<> | ||
<div className="bg-white border rounded-lg overflow-hidden"> | ||
<header className="bg-gray-300 text-gray-700 py-3 px-4"> | ||
<h2 className="text-sm font-semibold">Product {product.id} Detail</h2> | ||
</header> | ||
<table className="w-full text-sm"> | ||
<tbody> | ||
<tr className="odd:bg-gray-100 even:bg-white border-t"> | ||
<td className="font-semibold p-3 text-right md:w-1/5">id</td> | ||
<td className="p-3">{product.id}</td> | ||
</tr> | ||
<tr className="odd:bg-gray-100 even:bg-white border-t"> | ||
<td className="font-semibold p-3 text-right md:w-1/5">name</td> | ||
<td className="p-3">{product.name}</td> | ||
</tr> | ||
<tr className="odd:bg-gray-100 even:bg-white border-t"> | ||
<td className="font-semibold p-3 text-right md:w-1/5">description</td> | ||
<td className="p-3">{product.description}</td> | ||
</tr> | ||
<tr className="odd:bg-gray-100 even:bg-white border-t"> | ||
<td className="font-semibold p-3 text-right md:w-1/5">price_cents</td> | ||
<td className="p-3">{product.price_cents}</td> | ||
</tr> | ||
<tr className="odd:bg-gray-100 even:bg-white border-t"> | ||
<td className="font-semibold p-3 text-right md:w-1/5">createdAt</td> | ||
<td className="p-3">{product.createdAt}</td> | ||
</tr> | ||
|
||
</tbody> | ||
</table> | ||
</div> | ||
<nav className="my-4 mx-2 text-center"> | ||
<ul> | ||
<li className="inline-block ml-2"> | ||
<Link | ||
to={routes.editProduct({ id: product.id })} | ||
className="text-xs bg-blue-600 text-white hover:bg-blue-700 rounded px-4 py-2 uppercase font-semibold tracking-wide" | ||
> | ||
Edit | ||
</Link> | ||
</li> | ||
<li className="inline-block ml-2"> | ||
<a | ||
href="#" | ||
className="text-xs bg-red-600 text-white hover:bg-red-700 rounded px-4 py-2 uppercase font-semibold tracking-wide" | ||
onClick={() => onDeleteClick(product.id)} | ||
> | ||
Delete | ||
</a> | ||
</li> | ||
</ul> | ||
</nav> | ||
</> | ||
) | ||
} | ||
|
||
export default Product |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import Product from 'src/components/Product' | ||
|
||
export const QUERY = gql` | ||
query FIND_POST_BY_ID($id: Int!) { | ||
product: product(id: $id) { | ||
id | ||
name | ||
description | ||
price_cents | ||
createdAt | ||
} | ||
} | ||
` | ||
|
||
export const Loading = () => <div>Loading...</div> | ||
|
||
export const Empty = () => <div>Product not found</div> | ||
|
||
export const Success = ({ product }) => { | ||
return <Product product={product} /> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { | ||
Form, | ||
FormError, | ||
FieldError, | ||
Label, | ||
TextField, | ||
Submit, | ||
} from '@redwoodjs/web' | ||
|
||
const CSS = { | ||
label: 'block mt-6 text-gray-700 font-semibold', | ||
labelError: 'block mt-6 font-semibold text-red-700', | ||
input: | ||
'block mt-2 w-full p-2 border border-gray-300 text-gray-700 rounded focus:outline-none focus:border-gray-500', | ||
inputError: | ||
'block mt-2 w-full p-2 border border-red-700 text-red-900 rounded focus:outline-none', | ||
errorMessage: 'block mt-1 font-semibold uppercase text-xs text-red-700', | ||
} | ||
|
||
const ProductForm = (props) => { | ||
const onSubmit = (data) => { | ||
props.onSave(data, props?.product?.id) | ||
} | ||
|
||
return ( | ||
<div className="text-sm -mt-4"> | ||
<Form onSubmit={onSubmit} error={props.error}> | ||
<FormError | ||
error={props.error} | ||
wrapperClassName="p-4 bg-red-100 text-red-700 border border-red-300 rounded mb-4" | ||
titleClassName="font-semibold" | ||
listClassName="mt-2 list-disc list-inside" | ||
/> | ||
|
||
<Label | ||
name="name" | ||
className={CSS.label} | ||
errorClassName={CSS.labelError} | ||
/> | ||
<TextField | ||
name="name" | ||
defaultValue={props.product?.name} | ||
className={CSS.input} | ||
errorClassName={CSS.inputError} | ||
validation={{ required: true }} | ||
/> | ||
<FieldError name="name" className={CSS.errorMessage} /> | ||
|
||
<Label | ||
name="description" | ||
className={CSS.label} | ||
errorClassName={CSS.labelError} | ||
/> | ||
<TextField | ||
name="description" | ||
defaultValue={props.product?.description} | ||
className={CSS.input} | ||
errorClassName={CSS.inputError} | ||
validation={{ required: true }} | ||
/> | ||
<FieldError name="description" className={CSS.errorMessage} /> | ||
|
||
<Label | ||
name="price_cents" | ||
className={CSS.label} | ||
errorClassName={CSS.labelError} | ||
/> | ||
<TextField | ||
name="price_cents" | ||
defaultValue={props.product?.price_cents} | ||
className={CSS.input} | ||
errorClassName={CSS.inputError} | ||
validation={{ required: true }} | ||
/> | ||
<FieldError name="price_cents" className={CSS.errorMessage} /> | ||
|
||
<div className="mt-8 text-center"> | ||
<Submit | ||
disabled={props.loading} | ||
className="bg-blue-600 text-white hover:bg-blue-700 text-xs rounded px-4 py-2 uppercase font-semibold tracking-wide" | ||
> | ||
Save | ||
</Submit> | ||
</div> | ||
</Form> | ||
</div> | ||
) | ||
} | ||
|
||
export default ProductForm |
Oops, something went wrong.