├── .gitignore ├── _config.yml ├── logo.png ├── favicon.ico ├── public ├── logo.png ├── favicon.ico ├── manifest.json └── index.html ├── .idea ├── dictionaries │ └── albiona.xml ├── misc.xml ├── vcs.xml ├── modules.xml ├── react_admin_dashboard.iml └── workspace.xml ├── .storybook ├── addons.js └── config.js ├── src ├── components │ ├── layout │ │ ├── App.test.js │ │ ├── Layout.js │ │ ├── App.js │ │ ├── Notification.js │ │ ├── NavMenu.js │ │ ├── NotificationContent.js │ │ ├── VerticalMenu.js │ │ ├── TopMenu.js │ │ └── SideMenu.js │ ├── pages │ │ ├── Button.js │ │ ├── Home.js │ │ ├── Card.js │ │ └── UserManagement.js │ ├── extension │ │ └── TextIcon.js │ └── common │ │ └── registerServiceWorker.js ├── store │ ├── SideMenu.js │ ├── SearchStore.js │ ├── Card.js │ ├── configureStore.js │ └── UserManagement.js ├── stories │ └── index.js ├── index.js └── styles │ ├── NavMenu.css │ └── index.css ├── manifest.json ├── CONTRIBUTING.md ├── index.html ├── README.md ├── package.json ├── asset-manifest.json └── service-worker.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbionaHoti/react_admin_dashboard/HEAD/logo.png -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbionaHoti/react_admin_dashboard/HEAD/favicon.ico -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbionaHoti/react_admin_dashboard/HEAD/public/logo.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbionaHoti/react_admin_dashboard/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.idea/dictionaries/albiona.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-actions/register'; 2 | import '@storybook/addon-links/register'; 3 | import '@storybook/addon-notes/register'; -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { 2 | configure 3 | } from '@storybook/react'; 4 | 5 | function loadStories() { 6 | import('../src/stories/index.js'); 7 | // You can require as many stories as you need. 8 | } 9 | 10 | configure(loadStories, module); -------------------------------------------------------------------------------- /src/components/layout/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './components/layout/App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /src/components/pages/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import {Button} from "semantic-ui-react"; 4 | 5 | const ClickButton = props => ( 6 | 9 | ); 10 | 11 | export default connect()(ClickButton); 12 | -------------------------------------------------------------------------------- /src/components/pages/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import {Segment} from "semantic-ui-react"; 4 | 5 | const Home = props => ( 6 | 7 |

React Admin Dashboard

8 |
9 | ); 10 | 11 | export default connect()(Home); 12 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "ReactAdmin", 3 | "name": "ReactAdminDashboard", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "ReactAdmin", 3 | "name": "ReactAdminDashboard", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### Installing / Getting started 2 | 3 | ``` 4 | git clone https://github.com/AlbionaHoti/react_admin_dashboard.git 5 | cd react_admin_dashboard 6 | ``` 7 | 8 | To start the project run 9 | ``` 10 | npm install 11 | npm start 12 | ``` 13 | To start storybook run 14 | 15 | ``` 16 | npm run storybook 17 | ``` 18 | Feel free to add issues if you want to fix something or add new features :) 19 | -------------------------------------------------------------------------------- /src/store/SideMenu.js: -------------------------------------------------------------------------------- 1 | const toggleMenu = 'TOGGLE_MENU'; 2 | const initialState = { smallMenu: false }; 3 | 4 | export const actionCreators = { 5 | toggleSideMenu: () => ({ type: toggleMenu }), 6 | }; 7 | 8 | export const reducer = (state, action) => { 9 | state = state || initialState; 10 | 11 | if (action.type === toggleMenu) { 12 | return { ...state, smallMenu: !state.smallMenu}; 13 | } 14 | 15 | return state; 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/layout/Layout.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import SideMenu from "../layout/SideMenu"; 3 | import TopMenu from "../layout/TopMenu"; 4 | 5 | export default props => ( 6 |
7 |
8 | 9 |
10 |
11 | 12 | {props.children} 13 | 14 |
15 |
16 | ); 17 | -------------------------------------------------------------------------------- /src/stories/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { action } from '@storybook/addon-actions'; 4 | import Button from '../components/'; 5 | 6 | storiesOf('Button', module) 7 | .add('with text', () => ( 8 | 9 | )) 10 | .add('with some emoji', () => ( 11 | 12 | )); -------------------------------------------------------------------------------- /src/store/SearchStore.js: -------------------------------------------------------------------------------- 1 | const SEARCH_BY_TEXT = 'SEARCH_BY_TEXT'; 2 | const initialState = { text: '' }; 3 | 4 | export const actionCreators = { 5 | search: (text) => async (dispatch, getState) => { 6 | dispatch({ type: SEARCH_BY_TEXT, text: text }); 7 | }, 8 | }; 9 | 10 | export const reducer = (state, action) => { 11 | state = state || initialState; 12 | 13 | if (action.type === SEARCH_BY_TEXT) { 14 | return { ...state, text: action.text }; 15 | } 16 | 17 | return state; 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/layout/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Route } from 'react-router' 3 | import Layout from '.././layout/Layout' 4 | import Home from '.././pages/Home' 5 | import UserManagement from '.././pages/UserManagement' 6 | import CardForm from '.././pages/Card' 7 | 8 | export default () => ( 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /.idea/react_admin_dashboard.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/layout/Notification.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { Popup, Icon } from "semantic-ui-react"; 3 | import NotificationContent from "./NotificationContent"; 4 | 5 | export default class Notification extends Component { 6 | state = {}; 7 | 8 | render() { 9 | return ( 10 | } 13 | position='bottom right' 14 | verticalOffset={18} 15 | size="small" 16 | 17 | > 18 | 19 | 20 | 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/store/Card.js: -------------------------------------------------------------------------------- 1 | const incrementCountType = 'INCREMENT_COUNT'; 2 | const decrementCountType = 'DECREMENT_COUNT'; 3 | const initialState = { count: 0 }; 4 | 5 | export const actionCreators = { 6 | increment: () => ({ type: incrementCountType }), 7 | decrement: () => ({ type: decrementCountType }) 8 | }; 9 | 10 | export const reducer = (state, action) => { 11 | state = state || initialState; 12 | 13 | if (action.type === incrementCountType) { 14 | return { ...state, count: state.count + 1 }; 15 | } 16 | 17 | if (action.type === decrementCountType) { 18 | return { ...state, count: state.count - 1 }; 19 | } 20 | 21 | return state; 22 | }; 23 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | React Admin UI
-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Admin Dashboard 2 | Admin Dashboard build with ReactJs and React Semantic UI. Which enables jump starting a new 3 | project with a prepared layout and React Semantic UI provides access to many useful [components](https://react.semantic-ui.com/). 4 | 5 | ## Installing / Getting started 6 | 7 | ```shell 8 | git clone https://github.com/AlbionaHoti/react_admin_dashboard.git 9 | cd react_admin_dashboard 10 | ``` 11 | ## To start the project run 12 | ``` 13 | npm install 14 | npm start 15 | ``` 16 | 17 | ## To start storybook run 18 | ``` 19 | npm run storybook 20 | ``` 21 | 22 | [Project Demo](https://albionahoti.github.io/react_admin_dashboard/) 23 | 24 | Author: [Albiona Hoti](https://albionahoti.github.io) 25 | 26 | ![alt text](https://i.imgur.com/rTXO96K.png) 27 | 28 | ## Demo Details 29 | 30 | ![alt text](https://i.imgur.com/KzYwvL5.png) 31 | -------------------------------------------------------------------------------- /src/components/extension/TextIcon.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import {Icon} from "semantic-ui-react"; 4 | 5 | export default class TextIcon extends Component { 6 | 7 | style = { 8 | alignSelf: 'center', 9 | paddingLeft: '4px' 10 | }; 11 | 12 | static propTypes = { 13 | name: PropTypes.string.isRequired, 14 | hideText: PropTypes.bool.isRequired, 15 | color: PropTypes.string 16 | }; 17 | 18 | render() { 19 | return ( 20 |
21 | 24 | 27 |
28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/layout/NavMenu.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | import { Glyphicon, Nav, Navbar, NavItem } from 'react-bootstrap'; 4 | import { LinkContainer } from 'react-router-bootstrap'; 5 | import './NavMenu.css'; 6 | 7 | export default props => ( 8 | 9 | 10 | 11 | React Admin Dashboard 12 | 13 | 14 | 15 | 16 | 28 | 29 | 30 | ); 31 | -------------------------------------------------------------------------------- /src/components/pages/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { bindActionCreators } from 'redux' 3 | import { connect } from 'react-redux' 4 | import { actionCreators } from '../../store/Card' 5 | import 'semantic-ui-css/semantic.min.css' 6 | import { Card, Icon, Image } from 'semantic-ui-react' 7 | 8 | 9 | const CardForm = props => ( 10 | 11 | 12 | 13 | Matthew 14 | 15 | Joined in 2015 16 | 17 | Matthew is a musician living in Nashville. 18 | 19 | 20 | 21 | 22 | 22 Friends 23 | 24 | 25 | 26 | ); 27 | 28 | export default connect( 29 | state => state.card, 30 | dispatch => bindActionCreators(actionCreators, dispatch) 31 | )(CardForm) 32 | -------------------------------------------------------------------------------- /src/components/layout/NotificationContent.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | 3 | import { 4 | Button, 5 | Grid, 6 | Header, 7 | Segment 8 | } from "semantic-ui-react"; 9 | 10 | export default class NotificationContent extends Component { 11 | state = {}; 12 | render() { 13 | const patients = [ 14 | { 15 | name: "Elliot Fu", 16 | bio: "Elliot has been a member since July 2012", 17 | button: "More Info" 18 | }, 19 | { 20 | name: "James Frank", 21 | bio: "James has been a member since Sep 2011", 22 | button: "More Info" 23 | }, 24 | { 25 | name: "Algo Hemil", 26 | bio: "Algo has been a member since Nov 2015", 27 | button: "More Info" 28 | } 29 | ]; 30 | 31 | return ( 32 | 33 | {patients.map(patient => ( 34 | 35 | 36 |
Basic Plan
37 |

38 | {patient.bio} 39 |

40 | 41 |
42 | ))} 43 |
44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap/dist/css/bootstrap.css' 2 | import 'bootstrap/dist/css/bootstrap-theme.css' 3 | import './styles/index.css' 4 | import React from 'react' 5 | import ReactDOM from 'react-dom' 6 | import { Provider } from 'react-redux' 7 | import { ConnectedRouter } from 'react-router-redux' 8 | import { createBrowserHistory } from 'history' 9 | import configureStore from './store/configureStore' 10 | import App from './components/layout/App' 11 | import registerServiceWroker from './components/common/registerServiceWorker' 12 | 13 | // Create browser history to use in the Redux store 14 | const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href') 15 | const history = createBrowserHistory({ basename: baseUrl }) 16 | 17 | // Get the application-wide store instance, prepopulating with state from the server where available. 18 | const initialState = window.initialReduxState 19 | const store = configureStore(history, initialState) 20 | 21 | const rootElement = document.getElementById('root') 22 | 23 | ReactDOM.render( 24 | 25 | 26 | 27 | 28 | , 29 | rootElement) 30 | 31 | registerServiceWroker() 32 | -------------------------------------------------------------------------------- /src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { applyMiddleware, combineReducers, compose, createStore } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | import { routerReducer, routerMiddleware } from 'react-router-redux'; 4 | import * as Card from './Card'; 5 | import * as SideMenu from "./SideMenu"; 6 | import * as UserManagement from "./UserManagement"; 7 | import * as SearchStore from "./SearchStore"; 8 | 9 | export default function configureStore(history, initialState) { 10 | const reducers = { 11 | card: Card.reducer, 12 | sideMenu: SideMenu.reducer, 13 | userManagement: UserManagement.reducer, 14 | searchStore: SearchStore.reducer, 15 | }; 16 | 17 | const middleware = [ 18 | thunk, 19 | routerMiddleware(history) 20 | ]; 21 | 22 | // In development, use the browser's Redux dev tools extension if installed 23 | const enhancers = []; 24 | const isDevelopment = process.env.NODE_ENV === 'development'; 25 | if (isDevelopment && typeof window !== 'undefined' && window.devToolsExtension) { 26 | enhancers.push(window.devToolsExtension()); 27 | } 28 | 29 | const rootReducer = combineReducers({ 30 | ...reducers, 31 | routing: routerReducer 32 | }); 33 | 34 | return createStore( 35 | rootReducer, 36 | initialState, 37 | compose(applyMiddleware(...middleware), ...enhancers) 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /src/styles/NavMenu.css: -------------------------------------------------------------------------------- 1 | .navbar li .glyphicon { 2 | margin-right: 10px; 3 | } 4 | 5 | /* Highlighting rules for nav menu items */ 6 | .navbar .navbar-nav .active a, 7 | .navbar .navbar-nav .active a:hover, 8 | .navbar .navbar-nav .active a:focus { 9 | background-image: none; 10 | background-color: #4189C7; 11 | color: white; 12 | } 13 | 14 | @media (min-width: 768px) { 15 | /* On large screens, convert the nav menu to a vertical sidebar */ 16 | .navbar { 17 | height: 100%; 18 | width: calc(25% - 20px); 19 | } 20 | .navbar { 21 | border-radius: 0; 22 | border-width: 0; 23 | height: 100%; 24 | } 25 | .navbar-header { 26 | float: none; 27 | } 28 | .navbar .navbar-collapse { 29 | border-top: 1px solid #444; 30 | padding: 0; 31 | } 32 | .navbar .container-fluid { 33 | padding: 0; 34 | margin: 0; 35 | } 36 | .navbar .container-fluid .navbar-brand { 37 | margin: 0; 38 | } 39 | .navbar ul { 40 | float: none; 41 | } 42 | .navbar li { 43 | float: none; 44 | font-size: 15px; 45 | margin: 6px; 46 | } 47 | .navbar li a { 48 | padding: 10px 16px; 49 | border-radius: 4px; 50 | } 51 | .navbar a { 52 | /* If a menu item's text is too long, truncate it */ 53 | width: 100%; 54 | white-space: nowrap; 55 | overflow: hidden; 56 | text-overflow: ellipsis; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "homepage": "http://AlbionaHoti/react_admin_dashboard", 3 | "name": "ReactAdminDashboard", 4 | "version": "0.1.0", 5 | "private": true, 6 | "dependencies": { 7 | "bootstrap": "^3.3.7", 8 | "file-loader": "^1.1.9", 9 | "informed": "^1.10.4", 10 | "prop-types": "latest", 11 | "react": "^16.4.2", 12 | "react-bootstrap": "^0.31.5", 13 | "react-dom": "^16.4.2", 14 | "react-redux": "^5.0.6", 15 | "react-router-bootstrap": "^0.24.4", 16 | "react-router-dom": "^4.2.2", 17 | "react-router-redux": "^5.0.0-alpha.8", 18 | "react-scripts": "^2.1.8", 19 | "redux": "^3.7.2", 20 | "redux-thunk": "^2.2.0", 21 | "rimraf": "^2.6.2", 22 | "semantic-ui-css": "^2.3.1", 23 | "semantic-ui-react": "^0.78.3", 24 | "url-loader": "^0.6.2" 25 | }, 26 | "scripts": { 27 | "start": "rimraf ./build && react-scripts start", 28 | "build": "react-scripts build", 29 | "test": "react-scripts test --env=jsdom", 30 | "eject": "react-scripts eject", 31 | "predeploy": "npm run build", 32 | "deploy": "gh-pages -d build", 33 | "storybook": "start-storybook -p 9001 -c .storybook" 34 | }, 35 | "devDependencies": { 36 | "@storybook/addon-actions": "^3.4.8", 37 | "@storybook/addon-links": "^3.4.8", 38 | "@storybook/addon-notes": "^3.4.8", 39 | "@storybook/addons": "^3.4.8", 40 | "@storybook/react": "^5.0.6", 41 | "babel-core": "^6.26.3", 42 | "gh-pages": "^1.2.0" 43 | }, 44 | "browserslist": [ 45 | ">0.2%", 46 | "not dead", 47 | "not ie <= 11", 48 | "not op_mini all" 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 24 | React Admin UI 25 | 26 | 27 | 28 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/styles/index.css: -------------------------------------------------------------------------------- 1 | @media (max-width: 767px) { 2 | /* On small screens, the nav menu spans the full width of the screen. Leave a space for it. */ 3 | body { 4 | padding-top: 50px; 5 | } 6 | } 7 | :root { 8 | --top-menu-height: 4em; 9 | } 10 | 11 | .top-menu { 12 | height: var(--top-menu-height); 13 | } 14 | .grid { 15 | width: 100%; 16 | display: grid; 17 | grid: var(--top-menu-height) / 1fr; 18 | grid-template-areas: "menu" 19 | "maincontent"; 20 | min-height: 100vh; 21 | } 22 | 23 | .menu { 24 | grid-area: menu; 25 | z-index: 100; 26 | } 27 | 28 | .main-content { 29 | grid-area: maincontent; 30 | background-color: #f9fafb; 31 | } 32 | 33 | .parent { 34 | display: inline-flex; 35 | } 36 | 37 | .side { 38 | transition: width 0.3s; 39 | width: 14em !important; 40 | overflow: hidden; 41 | padding-top: var(--top-menu-height); 42 | z-index: 99; 43 | } 44 | 45 | .small-side { 46 | width: 4em !important; 47 | flex-basis: 4em; 48 | } 49 | 50 | .content { 51 | position: absolute; 52 | right: 0; 53 | transition: all 0.3s; 54 | padding: 10px; 55 | width: calc(100% - 14em); 56 | } 57 | 58 | .small-content { 59 | padding: 10px; 60 | width: calc(100% - 4em); 61 | } 62 | 63 | .logo-space-menu-item { 64 | width: 14em; 65 | } 66 | 67 | .display-inline { 68 | display: inline-flex; 69 | align-items: center; 70 | } 71 | 72 | .logo-space { 73 | font-family: "Roboto Light", serif; 74 | font-size: 24px; 75 | margin: 0 auto; 76 | 77 | } 78 | 79 | .logo-space img, .display-inline img { 80 | margin-right: 8px; 81 | } 82 | 83 | .no-border::before { 84 | display: none; 85 | } 86 | .top-menu i.icon 87 | { 88 | margin: 0 !important; 89 | } 90 | 91 | 92 | .drop-left-padding{ 93 | padding-left: 0 !important; 94 | } 95 | 96 | .label-on-corner { 97 | top: 0.8em !important; 98 | left: 78% !important; 99 | } -------------------------------------------------------------------------------- /asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main.css": "static/css/main.8b61b94c.css", 3 | "main.css.map": "static/css/main.8b61b94c.css.map", 4 | "main.js": "static/js/main.511cd0c4.js", 5 | "main.js.map": "static/js/main.511cd0c4.js.map", 6 | "static/media/brand-icons.eot": "static/media/brand-icons.13db00b7.eot", 7 | "static/media/brand-icons.svg": "static/media/brand-icons.a1a749e8.svg", 8 | "static/media/brand-icons.ttf": "static/media/brand-icons.c5ebe0b3.ttf", 9 | "static/media/brand-icons.woff": "static/media/brand-icons.a046592b.woff", 10 | "static/media/brand-icons.woff2": "static/media/brand-icons.e8c322de.woff2", 11 | "static/media/flags.png": "static/media/flags.9c74e172.png", 12 | "static/media/glyphicons-halflings-regular.eot": "static/media/glyphicons-halflings-regular.f4769f9b.eot", 13 | "static/media/glyphicons-halflings-regular.svg": "static/media/glyphicons-halflings-regular.89889688.svg", 14 | "static/media/glyphicons-halflings-regular.ttf": "static/media/glyphicons-halflings-regular.e18bbf61.ttf", 15 | "static/media/glyphicons-halflings-regular.woff": "static/media/glyphicons-halflings-regular.fa277232.woff", 16 | "static/media/glyphicons-halflings-regular.woff2": "static/media/glyphicons-halflings-regular.448c34a5.woff2", 17 | "static/media/icons.eot": "static/media/icons.8e3c7f55.eot", 18 | "static/media/icons.svg": "static/media/icons.962a1bf3.svg", 19 | "static/media/icons.ttf": "static/media/icons.b87b9ba5.ttf", 20 | "static/media/icons.woff": "static/media/icons.faff9214.woff", 21 | "static/media/icons.woff2": "static/media/icons.0ab54153.woff2", 22 | "static/media/outline-icons.eot": "static/media/outline-icons.701ae6ab.eot", 23 | "static/media/outline-icons.svg": "static/media/outline-icons.82f60bd0.svg", 24 | "static/media/outline-icons.ttf": "static/media/outline-icons.ad97afd3.ttf", 25 | "static/media/outline-icons.woff": "static/media/outline-icons.ef60a4f6.woff", 26 | "static/media/outline-icons.woff2": "static/media/outline-icons.cd6c777f.woff2" 27 | } -------------------------------------------------------------------------------- /src/store/UserManagement.js: -------------------------------------------------------------------------------- 1 | const GET_ALL_USERS_ACTION = "GET_ALL_USERS"; 2 | const DELETE_USER_ACTION = "DELETE_USER"; 3 | const UPDATE_USER_ACTION = "UPDATE_USER"; 4 | const ADD_USER_ACTION = "ADD_USER"; 5 | 6 | const initialState = { 7 | users: [ 8 | { 9 | name: "Albiona", 10 | email: "alb@gmail.com", 11 | role: "Admin", 12 | caloryLimit: 123 13 | }, 14 | { 15 | name: "Albiona", 16 | email: "alb@gmail.com", 17 | role: "Admin", 18 | caloryLimit: 123 19 | }, 20 | { 21 | name: "Albiona", 22 | email: "alb@gmail.com", 23 | role: "Admin", 24 | caloryLimit: 123 25 | } 26 | ] 27 | }; 28 | 29 | export const actionCreators = { 30 | getUsers: () => async (dispatch, getState) => { 31 | // dispatch({ type: GET_ALL_USERS_ACTION, users: json }); 32 | }, 33 | removeUser: id => async (dispatch, getState) => { 34 | dispatch({ 35 | type: DELETE_USER_ACTION, 36 | users: getState().userManagement.users.filter(m => m.id !== id) 37 | }); 38 | }, 39 | editUser: user => async (dispatch, getState) => { 40 | dispatch({ 41 | type: UPDATE_USER_ACTION, 42 | users: getState().userManagement.users.map( 43 | m => (m.id === user.id ? user : m) 44 | ) 45 | }); 46 | }, 47 | addUser: user => async (dispatch, getState) => { 48 | dispatch({ 49 | type: ADD_USER_ACTION, 50 | user: Object.assign({}, user, { id: Math.random() }) 51 | }); 52 | } 53 | }; 54 | 55 | export const reducer = (state, action) => { 56 | state = state || initialState; 57 | 58 | if (action.type === GET_ALL_USERS_ACTION) { 59 | return { ...state, users: action.users }; 60 | } 61 | if (action.type === DELETE_USER_ACTION) { 62 | return { ...state, users: action.users }; 63 | } 64 | if (action.type === UPDATE_USER_ACTION) { 65 | return { ...state, users: action.users }; 66 | } 67 | if (action.type === ADD_USER_ACTION) { 68 | return { ...state, users: [...state.users, action.user] }; 69 | } 70 | 71 | return state; 72 | }; 73 | -------------------------------------------------------------------------------- /src/components/layout/VerticalMenu.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { Icon, Menu, Rail } from "semantic-ui-react"; 3 | import { NavLink } from "react-router-dom"; 4 | 5 | export default class VerticalMenu extends Component { 6 | state = { activeItem: "dashboard" }; 7 | handleItemClick = (e, { name }) => this.setState({ activeItem: name }); 8 | 9 | render() { 10 | const { activeItem } = this.state; 11 | 12 | return ( 13 | 14 | 15 | 20 | 21 | 22 | 23 | Dashboard 24 | 25 | 26 | 27 | 28 | 33 | 34 | Appointments 35 | 36 | 37 | 38 | 39 | 44 | 45 | Patients 46 | 47 | 48 | 49 | 50 | 55 | Card 56 | 57 | 58 | 59 | {/* 60 | 65 | 66 | Layout 67 | 68 | */} 69 | 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/components/layout/TopMenu.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import {Icon, 3 | Image, 4 | Input, 5 | Label, 6 | Menu, 7 | } from 'semantic-ui-react' 8 | import {actionCreators as sideAction} from "../../store/SideMenu"; 9 | import {actionCreators as searchAction} from "../../store/SearchStore"; 10 | import {bindActionCreators} from "redux"; 11 | import { connect } from 'react-redux'; 12 | import Notification from './Notification'; 13 | 14 | class TopMenu extends Component { 15 | state = {}; 16 | 17 | handleItemClick = (e, { name }) => this.setState({ activeItem: name }); 18 | 19 | doSearch(event) { 20 | this.props.actions.search(event.target.value); 21 | } 22 | 23 | render() { 24 | return ( 25 | 26 | 27 |
28 | 29 |

React Dashboard

30 |
31 |
32 | 33 | 37 | 38 | 39 | 40 | 41 | 47 | 48 | 49 | 50 | 51 | 52 | 61 | 62 | 63 |
64 | 69 | Albiona 70 |
71 |
72 |
73 |
74 | ); 75 | } 76 | } 77 | 78 | export default connect( 79 | state => state.sideMenu, 80 | dispatch => { 81 | return { 82 | actions: bindActionCreators(Object.assign({}, sideAction, searchAction), dispatch) 83 | }} 84 | )(TopMenu); 85 | -------------------------------------------------------------------------------- /src/components/layout/SideMenu.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import {Menu} from 'semantic-ui-react' 3 | import {Link} from "react-router-dom"; 4 | import TextIcon from "../extension/TextIcon"; 5 | import {bindActionCreators} from "redux"; 6 | import {connect} from "react-redux"; 7 | import { actionCreators } from "../../store/SideMenu"; 8 | 9 | class SideMenu extends Component { 10 | state = { 11 | activeItem: 'dashboard', 12 | }; 13 | 14 | handleItemClick = (e, {name}) => this.setState({activeItem: name}); 15 | changeSize = () => this.setState({smallSidebar: !this.props.smallMenu}); 16 | 17 | getMenu() { 18 | const {activeItem} = this.state; 19 | return ( 20 | 21 | 23 | 24 | Dashboard 25 | 26 | 27 | 28 | 31 | 32 | Appointments 33 | 34 | 35 | 36 | 42 | 43 | Patients 44 | 45 | 46 | 47 | 49 | 50 | 51 | Card 52 | 53 | 54 | 55 | {/* 57 | 58 | Layout 59 | 60 | 61 | */} 62 | 63 | ) 64 | } 65 | 66 | render() { 67 | return ( 68 |
69 |
70 | {this.getMenu()} 71 |
72 |
73 | {this.props.children} 74 |
75 |
76 | ) 77 | } 78 | } 79 | 80 | export default connect( 81 | state => state.sideMenu, 82 | dispatch => bindActionCreators(actionCreators, dispatch) 83 | )(SideMenu); 84 | -------------------------------------------------------------------------------- /src/components/common/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (isLocalhost) { 36 | // This is running on localhost. Lets check if a service worker still exists or not. 37 | checkValidServiceWorker(swUrl); 38 | } else { 39 | // Is not local host. Just register service worker 40 | registerValidSW(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /service-worker.js: -------------------------------------------------------------------------------- 1 | "use strict";var precacheConfig=[["/react_admin_dashboard/index.html","eb685f747f816197c324765c8c27e331"],["/react_admin_dashboard/static/css/main.8b61b94c.css","760997b04eb646c970ea09376b99e04a"],["/react_admin_dashboard/static/js/main.511cd0c4.js","abb50e667c21f3144abaa930898195ee"],["/react_admin_dashboard/static/media/brand-icons.13db00b7.eot","13db00b7a34fee4d819ab7f9838cc428"],["/react_admin_dashboard/static/media/brand-icons.a046592b.woff","a046592bac8f2fd96e994733faf3858c"],["/react_admin_dashboard/static/media/brand-icons.a1a749e8.svg","a1a749e89f578a49306ec2b055c073da"],["/react_admin_dashboard/static/media/brand-icons.c5ebe0b3.ttf","c5ebe0b32dc1b5cc449a76c4204d13bb"],["/react_admin_dashboard/static/media/brand-icons.e8c322de.woff2","e8c322de9658cbeb8a774b6624167c2c"],["/react_admin_dashboard/static/media/flags.9c74e172.png","9c74e172f87984c48ddf5c8108cabe67"],["/react_admin_dashboard/static/media/glyphicons-halflings-regular.448c34a5.woff2","448c34a56d699c29117adc64c43affeb"],["/react_admin_dashboard/static/media/glyphicons-halflings-regular.89889688.svg","89889688147bd7575d6327160d64e760"],["/react_admin_dashboard/static/media/glyphicons-halflings-regular.e18bbf61.ttf","e18bbf611f2a2e43afc071aa2f4e1512"],["/react_admin_dashboard/static/media/glyphicons-halflings-regular.f4769f9b.eot","f4769f9bdb7466be65088239c12046d1"],["/react_admin_dashboard/static/media/glyphicons-halflings-regular.fa277232.woff","fa2772327f55d8198301fdb8bcfc8158"],["/react_admin_dashboard/static/media/icons.0ab54153.woff2","0ab54153eeeca0ce03978cc463b257f7"],["/react_admin_dashboard/static/media/icons.8e3c7f55.eot","8e3c7f5520f5ae906c6cf6d7f3ddcd19"],["/react_admin_dashboard/static/media/icons.962a1bf3.svg","962a1bf31c081691065fe333d9fa8105"],["/react_admin_dashboard/static/media/icons.b87b9ba5.ttf","b87b9ba532ace76ae9f6edfe9f72ded2"],["/react_admin_dashboard/static/media/icons.faff9214.woff","faff92145777a3cbaf8e7367b4807987"],["/react_admin_dashboard/static/media/outline-icons.701ae6ab.eot","701ae6abd4719e9c2ada3535a497b341"],["/react_admin_dashboard/static/media/outline-icons.82f60bd0.svg","82f60bd0b94a1ed68b1e6e309ce2e8c3"],["/react_admin_dashboard/static/media/outline-icons.ad97afd3.ttf","ad97afd3337e8cda302d10ff5a4026b8"],["/react_admin_dashboard/static/media/outline-icons.cd6c777f.woff2","cd6c777f1945164224dee082abaea03a"],["/react_admin_dashboard/static/media/outline-icons.ef60a4f6.woff","ef60a4f6c25ef7f39f2d25a748dbecfe"]],cacheName="sw-precache-v3-sw-precache-webpack-plugin-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,a){var t=new URL(e);return"/"===t.pathname.slice(-1)&&(t.pathname+=a),t.toString()},cleanResponse=function(e){if(!e.redirected)return Promise.resolve(e);return("body"in e?Promise.resolve(e.body):e.blob()).then(function(a){return new Response(a,{headers:e.headers,status:e.status,statusText:e.statusText})})},createCacheKey=function(e,a,t,n){var r=new URL(e);return n&&r.pathname.match(n)||(r.search+=(r.search?"&":"")+encodeURIComponent(a)+"="+encodeURIComponent(t)),r.toString()},isPathWhitelisted=function(e,a){if(0===e.length)return!0;var t=new URL(a).pathname;return e.some(function(e){return t.match(e)})},stripIgnoredUrlParameters=function(e,a){var t=new URL(e);return t.hash="",t.search=t.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return a.every(function(a){return!a.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),t.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var a=e[0],t=e[1],n=new URL(a,self.location),r=createCacheKey(n,hashParamName,t,/\.\w{8}\./);return[n.toString(),r]}));function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(a){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(t){if(!a.has(t)){var n=new Request(t,{credentials:"same-origin"});return fetch(n).then(function(a){if(!a.ok)throw new Error("Request for "+t+" returned a response with status "+a.status);return cleanResponse(a).then(function(a){return e.put(t,a)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var a=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(t){return Promise.all(t.map(function(t){if(!a.has(t.url))return e.delete(t)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var a,t=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching),n="index.html";(a=urlsToCacheKeys.has(t))||(t=addDirectoryIndex(t,n),a=urlsToCacheKeys.has(t));var r="/react_admin_dashboard/index.html";!a&&"navigate"===e.request.mode&&isPathWhitelisted(["^(?!\\/__).*"],e.request.url)&&(t=new URL(r,self.location).toString(),a=urlsToCacheKeys.has(t)),a&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(t)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(a){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,a),fetch(e.request)}))}}); -------------------------------------------------------------------------------- /src/components/pages/UserManagement.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { 3 | Button, 4 | Form, 5 | Header, 6 | Icon, 7 | Input, 8 | Message, 9 | Segment, 10 | Table 11 | } from "semantic-ui-react"; 12 | import { bindActionCreators } from "redux"; 13 | import { actionCreators } from "../../store/UserManagement"; 14 | import { connect } from "react-redux"; 15 | 16 | class UserManagement extends Component { 17 | constructor(props) { 18 | super(props); 19 | this.state = { 20 | newUser: { 21 | name: "", 22 | email: "", 23 | role: "", 24 | caloryLimit: 0 25 | } 26 | }; 27 | this.handleSubmit = this.handleSubmit.bind(this); 28 | } 29 | 30 | getTableData = props => { 31 | return props.state.userManagement.users.filter(user => { 32 | return user.name.includes(props.state.searchStore.text) 33 | }).map(user => 34 | 35 | {user.name + 36 | (user.password 37 | ? ' | Pass: "' + user.password + '" !!Attention' 38 | : "")} 39 | 40 | {user.email} 41 | {user.role} 42 | {user.caloryLimit} 43 | 44 | 47 | 50 | 51 | ); 52 | }; 53 | 54 | deleteUser = id => { 55 | this.props.removeUser(id); 56 | }; 57 | 58 | selectUserForEditing = id => { 59 | let user = this.props.state.userManagement.users.find(v => v.id === id); 60 | 61 | this.setState({ 62 | newUser: user 63 | }); 64 | }; 65 | 66 | handleSubmit = () => { 67 | if (this.state.newUser.id) this.props.editUser(this.state.newUser); 68 | else this.props.addUser(this.state.newUser); 69 | 70 | this.clearUserForm(); 71 | }; 72 | 73 | handleChange = event => { 74 | const target = event.target; 75 | const value = target.type === "checkbox" ? target.checked : target.value; 76 | const name = target.name; 77 | 78 | this.setState({ 79 | newUser: Object.assign({}, this.state.newUser, { 80 | [name]: value 81 | }) 82 | }); 83 | }; 84 | 85 | onDropdownSelection = (e, { value }) => { 86 | this.setState({ 87 | newUser: Object.assign({}, this.state.newUser, { 88 | role: value 89 | }) 90 | }); 91 | }; 92 | 93 | clearUserForm = () => { 94 | this.setState({ 95 | newUser: { 96 | name: "", 97 | email: "", 98 | role: "", 99 | caloryLimit: 0 100 | } 101 | }); 102 | }; 103 | 104 | render() { 105 | if (!this.props.state.userManagement.users) { 106 | return USERMNG Loading; 107 | } 108 | return [ 109 | 110 |
Registered Users
111 | 112 | 113 | 114 | Name 115 | Email 116 | Role 117 | Calory Limit 118 | Actions 119 | 120 | 121 | 122 | {this.getTableData(this.props)} 123 | 124 | 125 | 126 | 127 | 128 | 129 |
130 |
, 131 | 132 |
133 | 134 | 135 | 136 | 143 | 144 | 145 | 146 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 166 | 167 | 168 | 169 | 177 | 178 | 179 | 182 | 183 |
184 |
185 | ]; 186 | } 187 | } 188 | 189 | 190 | export default connect( 191 | state => { 192 | const { searchStore, userManagement } = state; 193 | return { 194 | state: { searchStore, userManagement } 195 | }; 196 | }, 197 | dispatch => bindActionCreators(actionCreators, dispatch) 198 | )(UserManagement); 199 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | weatherforecast 152 | forecasts 153 | toggle 154 | submit 155 | import cou 156 | 157 | 158 | 159 | 161 | 162 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | true 181 | DEFINITION_ORDER 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 |