Skip to content

Instantly share code, notes, and snippets.

@DZuz14
Created December 5, 2021 17:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DZuz14/9b4e3ef1c7fba0608dad4e6df9f77ef9 to your computer and use it in GitHub Desktop.
Save DZuz14/9b4e3ef1c7fba0608dad4e6df9f77ef9 to your computer and use it in GitHub Desktop.
Invoice 7
/** @jsx jsx */
import { useState } from 'react'
import { css, jsx } from '@emotion/react'
import { Container, Row, Col, Form, Table } from 'react-bootstrap'
const customers = ['Jack', 'Sally', 'Jane', 'Mark']
const itemInitializer = {
description: '',
qty: '',
price: '',
amount: ''
}
const Invoice = () => {
const [customer, setCustomer] = useState('')
const [title, setTitle] = useState('')
const [message, setMessage] = useState('')
const [items, setItems] = useState([{ ...itemInitializer }])
const handleChange = (e) => {
const name = e.target.getAttribute('name')
const index = parseInt(e.target.dataset.index)
let itemsClone = [...items]
itemsClone = itemsClone.map((item, i) => {
if (index !== i) {
return item
}
if (name === 'description') {
return { ...item, description: e.target.value }
}
item[name] = parseFloat(e.target.value)
let amount = ''
if (item.qty && item.price) {
amount = item.qty * item.price
}
return { ...item, amount }
})
setItems(itemsClone)
}
const handleDelete = (index) => {
const filteredItems = items.filter((item, i) => i !== index)
if (filteredItems.length === 0) {
setItems([{ ...itemInitializer }])
} else {
setItems(filteredItems)
}
}
return (
<div className="invoice" css={CSS}>
<Container>
<Row>
<Col sm={6}>
<select
value={customer}
onChange={(e) => setCustomer(e.target.value)}
>
<option value="" disabled>
Select
</option>
{customers.map((c) => (
<option key={c} value={c}>
{c}
</option>
))}
</select>
</Col>
<Col sm={6}>
<Form.Group>
<Form.Control
type="text"
placeholder="Enter a title..."
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
</Form.Group>
<Form.Group>
<Form.Control
as="textarea"
placeholder="Enter a message..."
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
</Form.Group>
</Col>
</Row>
</Container>
<Container>
<Table bordered>
<thead>
<tr>
<th className="item">Item</th>
<th>Quantity</th>
<th>Price</th>
<th>Amount</th>
<th />
</tr>
</thead>
<tbody>
{items.map((item, i) => (
<tr key={i}>
<td>
<Form.Control
name="description"
type="text"
placeholder="Enter a description..."
value={item.description}
data-index={i}
onChange={handleChange}
/>
</td>
<td>
<Form.Control
name="qty"
type="number"
placeholder="0"
min={0}
value={item.qty}
data-index={i}
onChange={handleChange}
/>
</td>
<td>
<Form.Control
name="price"
type="number"
placeholder="$0.00"
value={item.price}
data-index={i}
onChange={handleChange}
/>
</td>
<td>
<Form.Control
name="amount"
type="number"
placeholder="$0.00"
value={item.amount ? item.amount.toFixed(2) : ''}
readOnly
/>
</td>
<td>
<span
style={{ cursor: 'pointer' }}
onClick={() => handleDelete(i)}
>
<i className="fa fa-times" />
</span>
</td>
</tr>
))}
</tbody>
</Table>
</Container>
<Container>
<span
style={{ cursor: 'pointer' }}
onClick={() =>
setItems((prevItems) => [...prevItems, { ...itemInitializer }])
}
>
<i className="fa fa-plus" />
</span>
</Container>
</div>
)
}
export default Invoice
const CSS = css`
padding: 40px 0;
table {
th.item {
width: 650px;
}
}
`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment