Skip to content

Commit

Permalink
Merge pull request #23 from alexlee-dev/v0.6.0
Browse files Browse the repository at this point in the history
📦 v0.6.0
  • Loading branch information
Alex Lee authored Jun 8, 2020
2 parents c332411 + 379e7d5 commit 9cf8c4c
Show file tree
Hide file tree
Showing 25 changed files with 1,124 additions and 65 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.6.0] - 2020-06-08

### 🍻Add/Edit/Delete Beers

### Added

- Ability to create a beer via UI [#16](https://github.com/alexlee-dev/create-mern-application/issues/16)
- Ability to delete a beer via UI [#18](https://github.com/alexlee-dev/create-mern-application/issues/18)
- Ability to edit a beer via UI [#17](https://github.com/alexlee-dev/create-mern-application/issues/17)

### Changed

### Removed

### Fixed

- Bumps websocket-extensions from 0.1.3 to 0.1.4.
- JS Template Assets not Copied to `/build` upon Build script [#21](https://github.com/alexlee-dev/create-mern-application/issues/21)

## [0.5.0] - 2020-06-05

### 🍻 Beers in the DB
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-mern-application",
"version": "0.5.0",
"version": "0.6.0",
"description": "A bootstrapper for creating a MERN application.",
"bin": {
"create-mern-application": "./index.js"
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const pkg = require("../package.json");
Sentry.init({
dsn:
"https://44111e696abc456c959aef6dfc97f6a7@o202486.ingest.sentry.io/5262339",
release: "0.5.0",
release: "0.6.0",
});

import {
Expand Down Expand Up @@ -42,7 +42,7 @@ const main = async (): Promise<void> => {
* The program that parses the initial user input
*/
const program = new commander.Command("create-mern-application")
.version("0.5.0")
.version("0.6.0")
.arguments("<application-name>")
.usage(`${chalk.blueBright("<application-name>")} [options]`)
.action((name) => {
Expand Down
2 changes: 1 addition & 1 deletion src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const createProjectDirectory = async (

const jsScripts = {
build:
"rimraf dist && webpack --display=errors-only && rimraf build && babel src/server --out-dir build",
"rimraf dist && webpack --display=errors-only && rimraf build && babel src/server --out-dir build && copyfiles -f src/server/assets/**/* build/assets",
dev: "env-cmd -e development npm run spinup",
spinup: "node build/index.js",
start:
Expand Down
35 changes: 32 additions & 3 deletions src/template/js/src/client/App.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import * as React from "react";
import logo from "./logo.svg";
import BeerDisplayer from "./components/BeerDisplayer";
import { initializeStarterBeers, getBeers } from "./api/beer";
import BeerDisplayer from "./components/BeerDisplayer";
import Modal from "./components/Modal";

const App = () => {
const [beers, setBeers] = React.useState([]);
const [isModalOpen, setIsModalOpen] = React.useState(false);
const [modalContent, setModalContent] = React.useState(null);
const [currentBeer, setCurrentBeer] = React.useState(null);

const refreshBeers = async () => {
try {
const beers = await getBeers();
setBeers(beers);
} catch (error) {
console.error(error);
}
};

React.useEffect(() => {
const initializeData = async () => {
Expand All @@ -15,7 +28,9 @@ const App = () => {
currentBeers = await getBeers();
}
setBeers(currentBeers);
} catch (error) {}
} catch (error) {
console.error(error);
}
};
initializeData();
}, []);
Expand All @@ -34,7 +49,21 @@ const App = () => {
>
View Documentation
</a>
<BeerDisplayer beers={beers} />
<BeerDisplayer
beers={beers}
setCurrentBeer={setCurrentBeer}
setIsModalOpen={setIsModalOpen}
setModalContent={setModalContent}
/>
<Modal
currentBeer={currentBeer}
isModalOpen={isModalOpen}
modalContent={modalContent}
refreshBeers={refreshBeers}
setCurrentBeer={setCurrentBeer}
setIsModalOpen={setIsModalOpen}
setModalContent={setModalContent}
/>
</div>
);
};
Expand Down
54 changes: 54 additions & 0 deletions src/template/js/src/client/api/beer.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,57 @@ export const getBeers = async () => {
console.error(error);
}
};

export const addBeer = async ({ abv, brewer, description, name, type }) => {
try {
await fetch("/beer", {
body: JSON.stringify({
abv,
brewer,
description,
name,
type,
}),
headers: {
"Content-Type": "application/json",
},
method: "POST",
});
} catch (error) {
console.error(error);
}
};

export const deleteBeer = async (id) => {
try {
await fetch(`/beer/${id}`, {
headers: {
"Content-Type": "application/json",
},
method: "DELETE",
});
} catch (error) {
console.error(error);
}
};

export const editBeer = async ({
id,
abv,
brewer,
description,
name,
type,
}) => {
try {
await fetch(`/beer/${id}`, {
body: JSON.stringify({ abv, brewer, description, name, type }),
headers: {
"Content-Type": "application/json",
},
method: "PATCH",
});
} catch (error) {
console.error(error);
}
};
89 changes: 65 additions & 24 deletions src/template/js/src/client/components/BeerDisplayer.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,69 @@
import * as React from "react";

const BeerDisplayer = ({ beers }) => (
<table>
<thead>
<tr>
<th className="column1">ABV</th>
<th>Brewer</th>
<th>Description</th>
<th>Name</th>
<th className="column5">Type</th>
</tr>
</thead>
<tbody>
{beers.map((beer) => (
<tr key={beer._id}>
<td className="column1">{beer.abv}</td>
<td>{beer.brewer}</td>
<td>{beer.description}</td>
<td>{beer.name}</td>
<td className="column5">{beer.type}</td>
</tr>
))}
</tbody>
</table>
);
const BeerDisplayer = ({
beers,
setCurrentBeer,
setIsModalOpen,
setModalContent,
}) => {
return (
<div>
<div id="beer-table-heading">
<h2>Beer List</h2>
<button
onClick={() => {
setModalContent("newBeerForm");
setIsModalOpen(true);
}}
>
Add
</button>
</div>
<table>
<thead>
<tr>
<th className="column1">ABV</th>
<th>Brewer</th>
<th>Description</th>
<th>Name</th>
<th>Type</th>
<th className="column6">Actions</th>
</tr>
</thead>
<tbody>
{beers.map((beer) => (
<tr key={beer._id}>
<td className="column1">{beer.abv}</td>
<td>{beer.brewer}</td>
<td>{beer.description}</td>
<td>{beer.name}</td>
<td>{beer.type}</td>
<td className="column6 action-column">
<button
onClick={() => {
setModalContent("editBeerForm");
setCurrentBeer(beer);
setIsModalOpen(true);
}}
>
Edit
</button>
<button
onClick={() => {
setModalContent("deleteBeerForm");
setCurrentBeer(beer);
setIsModalOpen(true);
}}
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};

export default BeerDisplayer;
66 changes: 66 additions & 0 deletions src/template/js/src/client/components/Modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import * as React from "react";
import DeleteBeerForm from "./forms/DeleteBeerForm";
import EditBeerForm from "./forms/EditBeerForm";
import NewBeerForm from "./forms/NewBeerForm";

const Modal = ({
currentBeer,
isModalOpen,
modalContent,
refreshBeers,
setCurrentBeer,
setIsModalOpen,
setModalContent,
}) => {
return (
<>
<div
className={!isModalOpen ? "hidden" : undefined}
id="shade"
onClick={() => {
if (isModalOpen) setIsModalOpen(false);
}}
/>
<div className={!isModalOpen ? "hidden" : undefined} id="modal">
<div id="modal-close-container">
<button
id="modal-close"
onClick={() => {
setIsModalOpen(false);
setModalContent(null);
}}
>
x
</button>
</div>
{modalContent === "newBeerForm" && (
<NewBeerForm
refreshBeers={refreshBeers}
setIsModalOpen={setIsModalOpen}
setModalContent={setModalContent}
/>
)}
{modalContent === "deleteBeerForm" && (
<DeleteBeerForm
currentBeer={currentBeer}
refreshBeers={refreshBeers}
setCurrentBeer={setCurrentBeer}
setIsModalOpen={setIsModalOpen}
setModalContent={setModalContent}
/>
)}
{modalContent === "editBeerForm" && (
<EditBeerForm
currentBeer={currentBeer}
refreshBeers={refreshBeers}
setCurrentBeer={setCurrentBeer}
setIsModalOpen={setIsModalOpen}
setModalContent={setModalContent}
/>
)}
</div>
</>
);
};

export default Modal;
41 changes: 41 additions & 0 deletions src/template/js/src/client/components/forms/DeleteBeerForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from "react";
import { deleteBeer } from "../../api/beer";

const DeleteBeerForm = ({
currentBeer,
refreshBeers,
setCurrentBeer,
setIsModalOpen,
setModalContent,
}) => {
return (
<form
className="form"
id="delete-beer-form"
onSubmit={async (e) => {
e.preventDefault();
await deleteBeer(currentBeer._id);
setIsModalOpen(false);
setModalContent(null);
refreshBeers();
setCurrentBeer(null);
}}
>
<h3>Delete Beer</h3>
<p>Are you sure you want to delete this beer?</p>
<label htmlFor="abv">ABV</label>
<input disabled id="abv" value={currentBeer.abv} />
<label htmlFor="brewer">Brewer</label>
<input disabled id="brewer" value={currentBeer.brewer} />
<label htmlFor="description">Description</label>
<input disabled id="description" value={currentBeer.description} />
<label htmlFor="name">Name</label>
<input disabled id="name" value={currentBeer.name} />
<label htmlFor="type">Type</label>
<input disabled id="type" value={currentBeer.type} />
<button type="submit">Delete</button>
</form>
);
};

export default DeleteBeerForm;
Loading

0 comments on commit 9cf8c4c

Please sign in to comment.