Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Todo message #25

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
180 changes: 180 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
function App() {
const { Container, Row, Col } = ReactBootstrap;
return (
<Container>
<Row>
<Col md={{ offset: 3, span: 6 }}>
<TodoListCard />
</Col>
</Row>
</Container>
);
}

function TodoListCard() {
const [items, setItems] = React.useState(null);

React.useEffect(() => {
fetch('/items')
.then(r => r.json())
.then(setItems);
}, []);

const onNewItem = React.useCallback(
newItem => {
setItems([...items, newItem]);
},
[items],
);

const onItemUpdate = React.useCallback(
item => {
const index = items.findIndex(i => i.id === item.id);
setItems([
...items.slice(0, index),
item,
...items.slice(index + 1),
]);
},
[items],
);

const onItemRemoval = React.useCallback(
item => {
const index = items.findIndex(i => i.id === item.id);
setItems([...items.slice(0, index), ...items.slice(index + 1)]);
},
[items],
);

if (items === null) return 'Loading...';

return (
<React.Fragment>
<AddItemForm onNewItem={onNewItem} />
{items.length === 0 && (
<p className="text-center">You have no todo items yet! Add one today!</p>
)}
{items.map(item => (
<ItemDisplay
item={item}
key={item.id}
onItemUpdate={onItemUpdate}
onItemRemoval={onItemRemoval}
/>
))}
</React.Fragment>
);
}

function AddItemForm({ onNewItem }) {
const { Form, InputGroup, Button } = ReactBootstrap;

const [newItem, setNewItem] = React.useState('');
const [submitting, setSubmitting] = React.useState(false);

const submitNewItem = e => {
e.preventDefault();
setSubmitting(true);
fetch('/items', {
method: 'POST',
body: JSON.stringify({ name: newItem }),
headers: { 'Content-Type': 'application/json' },
})
.then(r => r.json())
.then(item => {
onNewItem(item);
setSubmitting(false);
setNewItem('');
});
};

return (
<Form onSubmit={submitNewItem}>
<InputGroup className="mb-3">
<Form.Control
value={newItem}
onChange={e => setNewItem(e.target.value)}
type="text"
placeholder="New Item"
aria-describedby="basic-addon1"
/>
<InputGroup.Append>
<Button
type="submit"
variant="success"
disabled={!newItem.length}
className={submitting ? 'disabled' : ''}
>
{submitting ? 'Adding...' : 'Add Task'}
</Button>
</InputGroup.Append>
</InputGroup>
</Form>
);
}

function ItemDisplay({ item, onItemUpdate, onItemRemoval }) {
const { Container, Row, Col, Button } = ReactBootstrap;

const toggleCompletion = () => {
fetch(`/items/${item.id}`, {
method: 'PUT',
body: JSON.stringify({
name: item.name,
completed: !item.completed,
}),
headers: { 'Content-Type': 'application/json' },
})
.then(r => r.json())
.then(onItemUpdate);
};

const removeItem = () => {
fetch(`/items/${item.id}`, { method: 'DELETE' }).then(() =>
onItemRemoval(item),
);
};

return (
<Container fluid className={`item ${item.completed && 'completed'}`}>
<Row>
<Col xs={1} className="text-center">
<Button
className="toggles"
size="sm"
variant="link"
onClick={toggleCompletion}
aria-label={
item.completed
? 'Mark item as incomplete'
: 'Mark item as complete'
}
>
<i
onClick={toggleCompletion}
className={`far ${
item.completed ? 'fa-check-square' : 'fa-square'
}`}
/>
</Button>
</Col>
<Col xs={10} className="name">
{item.name}
</Col>
<Col xs={1} className="text-center remove">
<Button
size="sm"
variant="link"
onClick={removeItem}
aria-label="Remove Item"
>
<i className="fa fa-trash text-danger" />
</Button>
</Col>
</Row>
</Container>
);
}

ReactDOM.render(<App />, document.getElementById('root'));
18 changes: 14 additions & 4 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
# Base image
FROM node:10-alpine
FROM node:18-alpine

# Install build dependencies
RUN apk add --no-cache libc6-compat build-base

# Create a directory to hold the application code inside the image
WORKDIR /app

COPY . .
# Copy package.json and yarn.lock first to leverage Docker caching
COPY package.json yarn.lock ./

# Install app dependencies
RUN yarn install --production

#ENTRYPOINT ["tail", "-f", "/dev/null"]
CMD ["node", "/app/src/index.js"]
# Copy the rest of the application code
COPY . .

# Expose the application port
EXPOSE 3000

# Start the application
CMD ["node", "/app/src/index.js"]
27 changes: 27 additions & 0 deletions app/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: "3.7"

services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos

mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos

volumes:
todo-mysql-data:
1 change: 1 addition & 0 deletions app/node_modules/.bin/browserslist

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/color-support

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/create-jest

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/esparse

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/esvalidate

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/import-local-fixture

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/jest

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/js-yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/jsesc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/json5

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/mime

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/mkdirp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/node-gyp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/node-which

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/nodemon

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/nodetouch

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/nopt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/parser

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/prebuild-install

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/prettier

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/rc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/resolve

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/rimraf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/semver

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/update-browserslist-db

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/uuid

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/node_modules/.bin/wait-port

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading