Skip to content

Commit 941b90e

Browse files
committed
Add listItems and menuItems in AppState
1 parent 9c383a9 commit 941b90e

File tree

12 files changed

+118
-153
lines changed

12 files changed

+118
-153
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"start": "node dist/server.js",
99
"build": "webpack",
1010
"watch": "webpack --watch",
11-
"test": "bundlesize -f dist/browser.js -s 15kB"
11+
"test": "bundlesize -f dist/browser.js -s 5kB"
1212
},
1313
"license": "MIT",
1414
"dependencies": {

src/components/app.tsx

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import * as React from 'react';
33
import Header from './header';
44
import Button from './button';
55
import Main from './main';
6+
import Menu from './menu';
67

78
interface AppState {
8-
items: string[],
9+
listItems: string[],
910
disabled: boolean;
1011
}
1112

@@ -14,51 +15,58 @@ export default class App extends React.Component<AppProps, AppState> {
1415
super(props);
1516
// We initialise its state by using the `props` that were passed in when it
1617
// was first rendered. We also want the button to be disabled until the
17-
// component has fully mounted on the DOM
18-
this.state = {items: this.props.items, disabled: true};
18+
// App component has fully mounted on the DOM
19+
this.state = { listItems: this.props.listItems, disabled: true };
1920
}
2021

21-
// Once the component has been mounted, we can enable the button
22+
// Once the App component has been mounted, we can enable the button
2223
componentDidMount() {
23-
this.setState({disabled: false});
24+
this.setState({ disabled: false });
2425
}
2526

2627
// Update the state whenever its clicked by adding a new item to
2728
// the list - imagine this being updated with the results of AJAX calls, etc
2829
handleAdd = () => {
29-
this.setState({
30-
items: this.state.items.concat('Item #' + this.state.items.length)
31-
});
30+
this.setState(prevState => ({
31+
listItems: prevState.listItems.concat('Item ' + prevState.listItems.length)
32+
}));
3233
}
3334

3435
handleSort = () => {
35-
this.setState({
36-
items: this.state.items.sort()
37-
});
36+
this.setState(prevState => ({
37+
listItems: prevState.listItems.sort()
38+
}));
3839
}
3940

4041
render() {
41-
const { items } = this.state;
42+
const { menuItems } = this.props;
43+
const { listItems, disabled } = this.state;
4244

43-
return (<div className="container">
44-
<Header/>
45+
return (<div>
46+
<Menu items={menuItems} />
4547
<Main>
48+
<Header
49+
title="Hello React"
50+
sub="This is an example using React & TypeScript"
51+
/>
4652
<ul>
47-
{items.map((item, i) =>
53+
{listItems.map((item, i) =>
4854
<li key={i}>{item}</li>
4955
)}
5056
</ul>
5157
<Button
5258
onClick={this.handleAdd}
53-
disabled={this.state.disabled}
59+
disabled={disabled}
5460
type="primary"
55-
value="Add Item" />
56-
<br/>
61+
text="Add Item"
62+
/>
63+
<span>&nbsp;</span>
5764
<Button
5865
onClick={this.handleSort}
59-
disabled={this.state.disabled}
66+
disabled={disabled}
6067
type="warning"
61-
value="Sort Items" />
68+
text="Sort Items"
69+
/>
6270
</Main>
6371
</div>);
6472
}

src/components/button.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@ import * as React from 'react';
22

33
interface ButtonProps {
44
type: 'default' | 'primary' | 'success' | 'info' | 'warning' | 'danger';
5-
value: string;
6-
disabled: boolean;
5+
text: string;
6+
disabled?: boolean;
77
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
88
}
99

1010
export default function Button (props: ButtonProps) {
11-
const { type, value, disabled, onClick } = props;
11+
const { type, text, disabled, onClick } = props;
1212

1313
return (<button type="button"
1414
onClick={onClick}
1515
disabled={disabled || false}
1616
className={'btn btn-' + type}>
17-
{value}
17+
{text}
1818
</button>);
1919
}

src/components/header.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import * as React from 'react';
2-
import Menu from './menu';
32

4-
export default function Header() {
3+
interface Props {
4+
title: string;
5+
sub: string;
6+
}
7+
8+
export default function Header(props: Props) {
9+
const { title, sub } = props;
510
return (<header role="banner">
6-
<h1>Hello React</h1>
11+
<h1>{title}</h1>
12+
<p>{sub}</p>
713
</header>);
814
}

src/components/main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ import * as React from 'react';
33
export default function Main(props: { children: React.ReactNode[] }) {
44
const { children } = props;
55
return (
6-
<div role="main">{children}</div>
6+
<div role="main" className="container">{children}</div>
77
);
88
}

src/components/menu-item.tsx

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,6 @@
11
import * as React from 'react';
22

3-
export default class MenuItem extends React.Component<MenuItemProps, {}> {
4-
constructor(props: MenuItemProps) {
5-
super(props);
6-
}
7-
handleClick = () => {
8-
const { onClick, id } = this.props;
9-
if (onClick) {
10-
onClick(id);
11-
}
12-
}
13-
render() {
14-
const { subitems, href, text, id, isVisible } = this.props;
15-
const style = {
16-
display: isVisible ? 'block' : 'none'
17-
};
18-
return (
19-
<li className="dropdown" onClick={this.handleClick}>
20-
<a id={this.props.id} role="button" data-toggle="dropdown" href={href}>{text}</a>
21-
<ul className="dropdown-menu" role="menu" aria-labelledby={id} style={style}>
22-
{(subitems || []).map((o, i) =>
23-
<li key={i}><a href={o.href}>{o.text}</a></li>
24-
)}
25-
</ul>
26-
</li>
27-
);
28-
}
3+
export default function MenuItem (props: MenuItemProps) {
4+
const { id, href, text } = props;
5+
return (<li><a id={id} href={href}>{text}</a></li>);
296
}

src/components/menu.tsx

Lines changed: 19 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,25 @@
11
import * as React from 'react';
22
import MenuItem from './menu-item';
33

4-
const data: MenuItemProps[] = [
5-
{
6-
id: 'dashboards',
7-
href: '#dashboards',
8-
text: 'Dashboard'
9-
},
10-
{
11-
id: "workflow-dropdown",
12-
href: "#workflow",
13-
text: "Workflow",
14-
subitems: [
15-
{ text: "Workflow Home", href: "workflow.html" },
16-
{ text: "Open Items", href: "#" },
17-
{ text: "History", href: "history.html" },
18-
{ text: "Receive Invoices", href: "#" },
19-
{ text: "Receive Packing List", href: "#" },
20-
]
21-
},
22-
{
23-
id: 'reports',
24-
href: '#reports',
25-
text: 'Reports'
26-
},
27-
{
28-
id: "shop-dropdown",
29-
href: "#shop",
30-
text: "Shop",
31-
subitems: [
32-
{ text: "Shop Home", href: "shop.html" },
33-
{ text: "Suppliers", href: "suppliers.html" },
34-
{ text: "Catalogs", href: "catalogs.html" },
35-
{ text: "Shopping List", href: "shopping-lists.html" },
36-
{ text: "Shop By Item Number", href: "shop-by-number.html" },
37-
]
38-
}
39-
];
40-
41-
interface MenuState {
42-
isVisible: {[id: string]: boolean};
4+
interface Props {
5+
items: MenuItemProps[];
436
}
447

45-
export default class Menu extends React.Component<{}, MenuState> {
46-
constructor() {
47-
super();
48-
this.state = {isVisible: {}};
49-
}
50-
51-
handleClick = (clickedId: string) => {
52-
console.log('clicked menu item', clickedId);
53-
let { isVisible } = this.state;
54-
55-
data.forEach(o => {
56-
isVisible[o.id] = (clickedId === o.id) ? !isVisible[o.id] : false;
57-
});
58-
59-
this.setState({isVisible: isVisible});
60-
}
61-
62-
render() {
63-
const { isVisible } = this.state;
64-
return (
65-
<ul role="navigation">
66-
{data.map( (o,i) =>
67-
<MenuItem
68-
key={o.id}
69-
id={o.id}
70-
text={o.text}
71-
href={o.href}
72-
subitems={o.subitems}
73-
onClick={this.handleClick}
74-
isVisible={isVisible[o.id]} />
75-
)}
76-
</ul>
77-
);
78-
}
8+
export default function Menu(props: Props) {
9+
const { items } = props;
10+
return (
11+
<nav className="navbar navbar-default">
12+
<div className="container">
13+
<ul className="nav navbar-nav">
14+
{items.map( (o,i) =>
15+
<MenuItem
16+
key={o.id}
17+
id={o.id}
18+
text={o.text}
19+
href={o.href} />
20+
)}
21+
</ul>
22+
</div>
23+
</nav>
24+
);
7925
}

src/db.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,40 @@
1-
export function getItems() {
2-
// This is a dummy data example to demonstrate
1+
export function getListItems(): string[] {
2+
// This dummy data is used to demonstrate
33
// all data is sanitized safely, however
4-
// you could imagine this would be data from a DB
5-
// in a real app
4+
// you could imagine this would be data from a
5+
// database in a real app
66
return [
77
'Item 0',
88
'Item 1',
99
'Item <script>alert(hack);</script>',
1010
'Item <!--injected!-->',
1111
'Just click to add more <b>bold</b>'
1212
];
13+
}
14+
15+
export function getMenuItems(): MenuItemProps[] {
16+
// These menu items represent each <li>
17+
// in the top menu bar, typically static data
18+
return [
19+
{
20+
id: 'home',
21+
href: '#',
22+
text: 'Home'
23+
},
24+
{
25+
id: "react-docs",
26+
href: "https://reactjs.org/",
27+
text: "React Docs"
28+
},
29+
{
30+
id: 'typescript-docs',
31+
href: 'https://www.typescriptlang.org/',
32+
text: 'TypeScript Docs'
33+
},
34+
{
35+
id: "ceriously",
36+
href: "https://www.ceriously.com",
37+
text: "Ceriously"
38+
}
39+
];
1340
}

src/file.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { readFile } from 'fs';
2+
import { promisify } from 'util';
3+
4+
export const readFileAsync = promisify(readFile);

src/interfaces/shared.d.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
interface AppProps {
2-
items: string[];
2+
listItems: string[];
3+
menuItems: MenuItemProps[];
34
}
45

5-
interface SubItemProps {
6+
interface MenuItemProps {
7+
id: string;
68
href: string;
79
text: string;
8-
}
9-
10-
interface MenuItemProps extends SubItemProps {
11-
id: string;
12-
subitems?: SubItemProps[];
13-
onClick?: (id: string) => void;
14-
isVisible?: boolean;
1510
}

0 commit comments

Comments
 (0)