├── src ├── styles.css ├── index.js ├── components │ ├── templates │ │ ├── AboutHtml.jsx │ │ ├── HeaderHtml.jsx │ │ └── InboxHtml.jsx │ ├── ModalMessage.js │ ├── Inbox.js │ └── ModalCompose.js └── data │ └── messages.json ├── public └── index.html ├── package.json ├── LICENSE.txt └── README.md /src/styles.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import bootstrap from "bootstrap"; // eslint-disable-line no-unused-vars 4 | import Inbox from "./components/Inbox"; 5 | import HeaderHtml from "./components/templates/HeaderHtml"; 6 | 7 | function App() { 8 | return ( 9 |
10 | 11 |
12 | 13 |
14 |
15 | ); 16 | } 17 | 18 | const rootElement = document.getElementById("root"); 19 | ReactDOM.render(, rootElement); 20 | -------------------------------------------------------------------------------- /src/components/templates/AboutHtml.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export const AboutHtml = () => { 4 | return ( 5 |
6 |
App Features
7 |
8 | Inbox loads data from json 9 | Open message in modal 10 | Compose message modal 11 | Mark items as "read" 12 | Mark items as "deleted" 13 | Mark single items or toggle all 14 | View deleted items 15 | Refresh/reload messages 16 | Unread messages count 17 | Deleted messages count 18 |
19 |
20 | ); 21 | }; 22 | 23 | export default AboutHtml; 24 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | React Inbox App 12 | 13 | 14 | 17 |
18 | 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-bootstrap-4-inbox", 3 | "version": "1.0.0", 4 | "description": "A simple ReactJs Inbox app that uses Bootstrap 4 and FontAwesome icons. Reads messages.json data, and displays in a list. Messages can be marked as read, and there's a modal to view or compose messages.", 5 | "keywords": [ 6 | "inbox", 7 | "react", 8 | "reactjs", 9 | "bootstrap", 10 | "messages" 11 | ], 12 | "main": "src/index.js", 13 | "dependencies": { 14 | "react": "16.4.2", 15 | "react-dom": "16.4.2", 16 | "react-scripts": "1.1.4", 17 | "jquery": "^3.3.1", 18 | "bootstrap": "^4.1.3", 19 | "popper.js": "^1.14.3" 20 | }, 21 | "devDependencies": {}, 22 | "scripts": { 23 | "start": "react-scripts start", 24 | "build": "react-scripts build", 25 | "test": "react-scripts test --env=jsdom", 26 | "eject": "react-scripts eject" 27 | } 28 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License(MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files(the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ReactJs + Bootstrap 4 Inbox 2 | == 3 | 4 | 👋 Hello developer,
5 | I created this ReactJs app using create-react-app and Bootstrap. 6 | 7 | 8 | React Inbox Screenshot 9 | 10 | Demo:
11 | Repo: 12 | 13 | Features 14 | -- 15 | 16 | Inbox loads data from json 17 | 18 | Open message in modal 19 | 20 | Compose message modal 21 | 22 | Mark items as "read" 23 | 24 | Mark items as "deleted" 25 | 26 | Mark single items or toggle all 27 | 28 | View deleted items 29 | 30 | 31 | Demonstrated Concepts 32 | -- 33 | - Use create-react-app to create a simple messaging app 34 | - Read data from a .json file in ReactJs 35 | - Separate Component and template HTML in ReactJs (Inbox.js & InboxHtml.jsx) 36 | - Share data/state between child to parent Component 37 | - Use and import Bootstrap CSS and Js in ReactJs 38 | - Open a Bootstrap 4 Modal in ReactJs 39 | - Update a single object property in React State array (Inbox.js) 40 | - Delete multiple items in a React State array 41 | 42 | 43 | -- 44 | 45 | -------------------------------------------------------------------------------- /src/components/templates/HeaderHtml.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export const HeaderHtml = () => { 4 | return ( 5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 14 | 15 | 16 |
17 |
18 |

19 | React Inbox App 20 |

21 |
A working template with Bootstrap 4
22 | 23 | reactjs 24 | 25 | 26 | bootstrap-4 27 | 28 |
29 | 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | ); 46 | }; 47 | 48 | export default HeaderHtml; 49 | -------------------------------------------------------------------------------- /src/components/ModalMessage.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import jquery from "jquery"; 3 | 4 | export class ModalMessage extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.show = this.show.bind(this); 8 | } 9 | 10 | show() { 11 | jquery(this.refs.messageModal).modal("show"); 12 | } 13 | 14 | render() { 15 | return ( 16 | 83 | ); 84 | } 85 | } 86 | 87 | export default ModalMessage; 88 | -------------------------------------------------------------------------------- /src/data/messages.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "from": "Gary Lewis", 5 | "fromAddress": "test@foofoo.com", 6 | "subject": "I saw this posting on the board", 7 | "dtSent": "Today, 9:18AM", 8 | "read": false, 9 | "body": "Hey Mark,

I saw your post on the message board and I was wondering if you still had that item available. Can you call me if you still do?

Thanks,
Gary Lewis" 10 | }, 11 | { 12 | "id": 2, 13 | "from": "Bob Sutton", 14 | "fromAddress": "test@testdomain.com", 15 | "subject": "In Late Today", 16 | "dtSent": "Today, 8:54AM", 17 | "read": false, 18 | "body": "Mark,
I will be in late today due to an appt.
v/r Bob", 19 | "attachment": false 20 | }, 21 | { 22 | "id": 3, 23 | "from": "Will Adivo", 24 | "fromAddress": "test@testbar.com", 25 | "subject": "New developer", 26 | "dtSent": "Yesterday, 4:48PM", 27 | "read": true, 28 | "body": "Here is the last resume for the developer position we posted on SO. Please review and let me know your thoughts!", 29 | "attachment": true 30 | }, 31 | { 32 | "id": 4, 33 | "from": "Al Kowalski", 34 | "fromAddress": "test@domain.com", 35 | "subject": "RE: New developer", 36 | "dtSent": "Yesterday, 4:40PM", 37 | "read": false, 38 | "body": "I looked at the resume, but the guy looks like a moron.", 39 | "priority": 1 40 | }, 41 | { 42 | "id": 4, 43 | "from": "Beth Maloney", 44 | "fromAddress": "test@mail.com", 45 | "subject": "July Reports", 46 | "dtSent": "3 Days Ago", 47 | "read": true, 48 | "body": "PYC Staff-
Our weekly meeting is canceled due to the holiday. Please review and submit your PID report before next week's meeting.
Thanks,
Beth" 49 | }, 50 | { 51 | "id": 6, 52 | "from": "Jason Furgano", 53 | "fromAddress": "test@domain.com", 54 | "subject": "New developer", 55 | "dtSent": "3 Days Ago", 56 | "read": true, 57 | "body": "All,
I'd like to introduce Joe Canfigliata our new S/W developer. If you see him in the office introduce yourself and make him feel welcome." 58 | }, 59 | { 60 | "id": 7, 61 | "from": "Bob Sutton", 62 | "fromAddress": "test@test.com", 63 | "subject": "Tasking request", 64 | "dtSent": "3 Days Ago", 65 | "read": true, 66 | "body": "Ovi lipsu doir. The message body goes here..." 67 | }, 68 | { 69 | "id": 8, 70 | "from": "Will Adivo", 71 | "fromAddress": "test@test.com", 72 | "subject": "Proposal for Avid Consulting", 73 | "dtSent": "3 Days Ago", 74 | "read": true, 75 | "body": "Mark, I reviewed your proposal with Beth and we have a few questions. Let me know when you time to meet." 76 | }, 77 | { 78 | "id": 9, 79 | "from": "Philip Corrigan", 80 | "fromAddress": "test@testdomain.com", 81 | "subject": "Follow-up Appt.", 82 | "dtSent": "4 Days Ago", 83 | "read": true, 84 | "body": "Hi,
Can you please confirm the expense report I submitted for my last trip to SD?
Thanks,
Tom Grey" 85 | } 86 | ] -------------------------------------------------------------------------------- /src/components/Inbox.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { InboxHtml } from "./templates/InboxHtml"; 3 | import ModalCompose from "./ModalCompose"; 4 | import ModalMessage from "./ModalMessage"; 5 | import messages from "../data/messages.json"; 6 | 7 | export class Inbox extends Component { 8 | constructor(props) { 9 | super(props); 10 | this.markRead = this.markRead.bind(this); 11 | this.doShow = this.doShow.bind(this); 12 | this.doDelete = this.doDelete.bind(this); 13 | this.toggleMark = this.toggleMark.bind(this); 14 | this.toggleMarkAll = this.toggleMarkAll.bind(this); 15 | this.deleteMarked = this.deleteMarked.bind(this); 16 | this.refreshMessages = this.refreshMessages.bind(this); 17 | this.deleteMessages = this.deleteMessages.bind(this); 18 | this.ModalMessage = React.createRef(); 19 | this.ModalCompose = React.createRef(); 20 | this.state = { 21 | initMessages: messages, 22 | messages: messages, 23 | selected: {}, 24 | deleted: [] 25 | }; 26 | } 27 | 28 | markRead(idx) { 29 | /* mark this message as read */ 30 | let messages = [...this.state.messages]; 31 | messages[idx].read = true; 32 | this.setState({ messages }); 33 | } 34 | 35 | doShow(idx) { 36 | this.markRead(idx); 37 | this.setState({ 38 | selected: messages[idx] 39 | }); 40 | /* open message in modal */ 41 | this.ModalMessage.current.show(); 42 | } 43 | 44 | doCompose() { 45 | /* open compose modal */ 46 | this.ModalCompose.current.show(); 47 | } 48 | 49 | toggleMark(idx) { 50 | let messages = [...this.state.messages]; 51 | messages[idx].marked = messages[idx].marked ? 0 : 1; 52 | this.setState({ messages }); 53 | } 54 | 55 | doDelete(idx) { 56 | let messages = [...this.state.messages]; 57 | let deleted = [...this.state.deleted]; 58 | /* append it to deleted */ 59 | deleted.push(messages[idx]); 60 | /* remove the message at idx */ 61 | messages.splice(idx, 1); 62 | this.setState({ messages, deleted }); 63 | } 64 | 65 | toggleMarkAll() { 66 | let messages = [...this.state.messages]; 67 | messages.map((v, k) => { 68 | return (v.marked = v.marked ? 0 : 1); 69 | }); 70 | this.setState({ messages }); 71 | } 72 | 73 | deleteMarked() { 74 | var self = this; 75 | let messages = [...this.state.messages]; 76 | var tbd = []; 77 | for (var k = 0; k < messages.length; k++) { 78 | if (messages[k].marked === 1) { 79 | tbd.push(k); 80 | } 81 | } 82 | 83 | if (tbd.length > 0) { 84 | self.deleteMessages(tbd); 85 | } 86 | } 87 | 88 | refreshMessages() { 89 | let initMessages = [...this.state.initMessages]; 90 | this.setState({ messages: initMessages }); 91 | } 92 | 93 | deleteMessages(arr) { 94 | let messages = [...this.state.messages]; 95 | let deleted = [...this.state.deleted]; 96 | for (var i = arr.length - 1; i >= 0; i--) { 97 | deleted.push(messages[i]); 98 | messages.splice(arr[i], 1); 99 | } 100 | this.setState({ messages, deleted }); 101 | } 102 | 103 | render() { 104 | return ( 105 |
106 | 107 | 108 | 109 |
110 | ); 111 | } 112 | } 113 | 114 | export default Inbox; 115 | -------------------------------------------------------------------------------- /src/components/ModalCompose.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import jquery from "jquery"; 3 | 4 | export class ModalCompose extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.show = this.show.bind(this); 8 | this.state = {}; 9 | } 10 | 11 | show(idx) { 12 | /* open message in modal */ 13 | jquery(this.refs.composeModal).modal("show"); 14 | } 15 | 16 | render() { 17 | return ( 18 |