{"id":1168,"date":"2023-04-05T12:53:35","date_gmt":"2023-04-05T09:53:35","guid":{"rendered":"https:\/\/notes.profidev.online\/?p=1168"},"modified":"2023-04-05T12:53:37","modified_gmt":"2023-04-05T09:53:37","slug":"react-inbox","status":"publish","type":"post","link":"https:\/\/notes.profidev.online\/ru\/reactjs\/1168\/","title":{"rendered":"React &#8211; Inbox"},"content":{"rendered":"\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe title=\"React - Inbox\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/DKmRHoAiJ1g?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;htmlmixed&quot;,&quot;mime&quot;:&quot;text\/html&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;HTML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;html&quot;}\">  &lt;div class=&quot;wrapper&quot;&gt;\n    &lt;div id=&quot;inbox&quot;&gt;&lt;\/div&gt;\n  &lt;\/div&gt;\n&lt;script src=&quot;https:\/\/code.jquery.com\/jquery-2.2.4.min.js&quot;&gt;&lt;\/script&gt;\n&lt;script  src=&quot;\/\/cdnjs.cloudflare.com\/ajax\/libs\/react\/0.14.3\/react.min.js&quot;&gt;&lt;\/script&gt;\n<\/pre><\/div>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;css&quot;,&quot;mime&quot;:&quot;text\/css&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;CSS&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;css&quot;}\">@import url(https:\/\/fonts.googleapis.com\/css?family=Open+Sans:400,300,600);\n*, *:before, *:after {\n  box-sizing: border-box;\n}\n\nbody {\n  \/* background: #216476;; *\/\n  background: url(https:\/\/images.unsplash.com\/photo-1476820865390-c52aeebb9891?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1170&amp;q=80);\n  background-size: cover;\n  background-repeat: no-repeat;\n  font-family: &quot;Open Sans&quot;, Arial, sans-serif;\n  font-size: 16px;\n  line-height: 150%;\n}\n\n.truncate {\n  display: inline-block;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  width: 100%;\n}\n\n.disclaimer {\n  margin: 0 auto 50px;\n  text-align: center;\n  width: 400px;\n}\n\n.btn {\n  border: none;\n  cursor: pointer;\n  display: block;\n  font-family: &quot;Open Sans&quot;, Arial, sans-serif;\n  font-size: 16px;\n  outline: none;\n  padding: 15px;\n  transition: all .1s linear;\n}\n\n.wrapper {\n  box-shadow: 0 4px 20px rgba(51, 51, 51, 0.2);\n  margin: 50px auto;\n  overflow: auto;\n  width: 1024px;\n}\n.wrapper .inbox-container {\n  float: left;\n  height: 500px;\n  width: calc(100% - 200px);\n}\n\n#sidebar {\n  background: #34393d;\n  float: left;\n  height: 500px;\n  width: 200px;\n}\n#sidebar .sidebar__inboxes {\n  padding-left: 0;\n  margin-top: 10px;\n}\n#sidebar .sidebar__inboxes .item-count {\n  background: #34393d;\n  border-radius: 5px;\n  float: right;\n  padding: 2px 8px;\n  margin: -2px -8px;\n}\n#sidebar .sidebar__inboxes li a {\n  color: #fff;\n  cursor: pointer;\n  display: block;\n  margin-bottom: 10px;\n  padding: 15px;\n  text-decoration: none;\n  transition: background .1s linear;\n  width: 100%;\n}\n#sidebar .sidebar__inboxes li a:hover {\n  background: #404549;\n}\n#sidebar .sidebar__inboxes .fa {\n  margin-right: 10px;\n}\n#sidebar .btn.compose {\n  color: #fff;\n  padding: 30px 15px;\n  text-align: center;\n  text-decoration: none;\n  transition: all .1s linear;\n  width: 100%;\n  background-image: url('data:image\/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjEuMCIgeTE9IjEuMCIgeDI9IjAuMCIgeTI9IjAuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwOWZjNCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzBjN2VhZCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');\n  background-size: 100%;\n  background-image: -webkit-gradient(linear, 100% 100%, 0% 0%, color-stop(0%, #216476), color-stop(100%, #0c7ead));\n  background-image: -moz-linear-gradient(bottom right, #216476, #0c7ead);\n  background-image: -webkit-linear-gradient(bottom right, #216476, #0c7ead);\n  background-image: linear-gradient(to top left, #216476, #0c7ead);\n}\n#sidebar .btn.compose:hover {\n  background-size: 150%;\n}\n#sidebar .btn.compose:hover .fa {\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n#sidebar .btn.compose .fa {\n  margin-left: 10px;\n  transition: all .1s linear;\n}\n\n.email-list {\n  background: #f5f5f5;\n  float: left;\n  height: 500px;\n  max-height: 100%;\n  overflow-y: auto;\n  width: 35%;\n}\n.email-list.empty {\n  color: #aaa;\n  padding-top: 200px;\n  text-align: center;\n}\n.email-list .email-item {\n  background: #fff;\n  border-bottom: 1px solid #eee;\n  cursor: pointer;\n  padding: 10px 15px;\n  position: relative;\n}\n.email-list .email-item.selected {\n  background-color: aliceblue;\n  color: #216476;\n}\n.email-list .email-item__subject {\n  margin-bottom: 8px;\n}\n.email-list .email-item__details {\n  font-size: 12px;\n  opacity: .5;\n  text-transform: uppercase;\n}\n.email-list .email-item__unread-dot {\n  height: 100%;\n  right: 10px;\n  position: absolute;\n  top: 10px;\n}\n.email-list .email-item__unread-dot[data-read=&quot;false&quot;]:before {\n  background: #216476;\n  border-radius: 50%;\n  content: '';\n  display: block;\n  height: 6px;\n  width: 6px;\n}\n.email-list .email-item__time {\n  float: right;\n  text-align: right;\n  width: 40%;\n}\n.email-list .email-item__from.truncate {\n  width: 60%;\n}\n.email-list .email-item:hover:not(.selected) {\n  background: #fafafa;\n}\n\n.email-content {\n  background: #fff;\n  border-left: 1px solid #ddd;\n  float: left;\n  height: 500px;\n  position: relative;\n  width: 65%;\n}\n.email-content__header {\n  background: #f5f5f5;\n  border-bottom: 1px solid #eee;\n  padding: 10px 15px;\n}\n.email-content__subject {\n  font-size: 18px;\n  margin: 10px 0;\n}\n.email-content__details {\n  font-size: 12px;\n  opacity: .5;\n  text-transform: uppercase;\n}\n.email-content__time {\n  color: #878787;\n  float: right;\n}\n.email-content__from {\n  color: #878787;\n}\n.email-content__message {\n  padding: 20px 15px 15px;\n}\n.email-content .delete-btn {\n  cursor: pointer;\n  margin: -5px;\n  padding: 5px;\n  position: absolute;\n  right: 20px;\n  top: 24px;\n  transition: color .1s linear;\n}\n.email-content .delete-btn:hover {\n  color: #E23E57;\n}\n\n.footer {\n  background: #f5f5f5;\n  border-top: 1px solid #ddd;\n  color: #999;\n  clear: both;\n  font-size: 14px;\n  padding: 10px;\n  text-align: center;\n  width: 100%;\n}\nul.sidebar__inboxes {\n  list-style-type: none;\n  }\n\n .fa {\n  font-size: large;\n }<\/pre><\/div>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;text\/javascript&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;JavaScript&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;js&quot;}\">var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\n\/* App *\/\nclass App extends React.Component {\n  constructor(args) {\n    super(args);\n\n    \/\/ Assign unique IDs to the emails\n    const emails = this.props.emails;\n    let id = 0;\n    for (const email of emails) {\n      email.id = id++;\n    }\n\n    this.state = {\n      selectedEmailId: 0,\n      currentSection: 'inbox',\n      emails };\n  }\n\n  openEmail(id) {\n    const emails = this.state.emails;\n    const index = emails.findIndex(x =&gt; x.id === id);\n    emails[index].read = 'true';\n    this.setState({\n      selectedEmailId: id,\n      emails });\n  }\n\n  deleteMessage(id) {\n    \/\/ Mark the message as 'deleted'\n    const emails = this.state.emails;\n    const index = emails.findIndex(x =&gt; x.id === id);\n    emails[index].tag = 'deleted';\n\n    \/\/ Select the next message in the list\n    let selectedEmailId = '';\n    for (const email of emails) {\n      if (email.tag === this.state.currentSection) {\n        selectedEmailId = email.id;\n        break;\n      }\n    }\n\n    this.setState({\n      emails,\n      selectedEmailId });\n  }\n\n  setSidebarSection(section) {\n    let selectedEmailId = this.state.selectedEmailId;\n    if (section !== this.state.currentSection) {\n      selectedEmailId = '';\n    }\n    this.setState({\n      currentSection: section,\n      selectedEmailId });\n  }\n\n  render() {\n    const currentEmail = this.state.emails.find(x =&gt; x.id === this.state.selectedEmailId);\n    return \/*#__PURE__*\/(\n      React.createElement(&quot;div&quot;, null, \/*#__PURE__*\/\n      React.createElement(Sidebar, {\n        emails: this.props.emails,\n        setSidebarSection: section =&gt; {this.setSidebarSection(section);} }), \/*#__PURE__*\/\n      React.createElement(&quot;div&quot;, { className: &quot;inbox-container&quot; }, \/*#__PURE__*\/\n      React.createElement(EmailList, {\n        emails: this.state.emails.filter(x =&gt; x.tag === this.state.currentSection),\n        onEmailSelected: id =&gt; {this.openEmail(id);},\n        selectedEmailId: this.state.selectedEmailId,\n        currentSection: this.state.currentSection }), \/*#__PURE__*\/\n      React.createElement(EmailDetails, {\n        email: currentEmail,\n        onDelete: id =&gt; {this.deleteMessage(id);} }))));\n  }}\n\n\/* Sidebar *\/\nconst Sidebar = ({ emails, setSidebarSection }) =&gt; {\n  var unreadCount = emails.reduce(\n  function (previous, msg) {\n    if (msg.read !== &quot;true&quot;) {\n      return previous + 1;\n    } else\n    {\n      return previous;\n    }\n  }.bind(this), 0);\n\n  var deletedCount = emails.reduce(\n  function (previous, msg) {\n    if (msg.tag === &quot;deleted&quot;) {\n      return previous + 1;\n    } else\n    {\n      return previous;\n    }\n  }.bind(this), 0);\n\n  return \/*#__PURE__*\/(\n    React.createElement(&quot;div&quot;, { id: &quot;sidebar&quot; }, \/*#__PURE__*\/\n    React.createElement(&quot;div&quot;, { className: &quot;sidebar__compose&quot; }, \/*#__PURE__*\/\n    React.createElement(&quot;a&quot;, { href: &quot;#&quot;, className: &quot;btn compose&quot; }, &quot;Compose &quot;, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;fa fa-pencil&quot; }))), \/*#__PURE__*\/\n    React.createElement(&quot;ul&quot;, { className: &quot;sidebar__inboxes&quot; }, \/*#__PURE__*\/\n    React.createElement(&quot;li&quot;, { onClick: () =&gt; {setSidebarSection('inbox');} }, \/*#__PURE__*\/React.createElement(&quot;a&quot;, null, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;fa fa-inbox&quot; }), &quot; Inbox&quot;, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;item-count&quot; }, unreadCount))), \/*#__PURE__*\/\n    React.createElement(&quot;li&quot;, { onClick: () =&gt; {setSidebarSection('sent');} }, \/*#__PURE__*\/React.createElement(&quot;a&quot;, null, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;fa fa-paper-plane&quot; }), &quot; Sent&quot;, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;item-count&quot; }, &quot;0&quot;))), \/*#__PURE__*\/\n    React.createElement(&quot;li&quot;, { onClick: () =&gt; {setSidebarSection('drafts');} }, \/*#__PURE__*\/React.createElement(&quot;a&quot;, null, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;fa fa-pencil-square-o&quot; }), &quot; Drafts&quot;, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;item-count&quot; }, &quot;0&quot;))), \/*#__PURE__*\/\n\n    React.createElement(&quot;li&quot;, { onClick: () =&gt; {setSidebarSection('deleted');} }, \/*#__PURE__*\/React.createElement(&quot;a&quot;, null, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;fa fa-trash-o&quot; }), &quot; Trash&quot;, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;item-count&quot; }, deletedCount))))));\n};\n\n\/* Email classes *\/\nconst EmailListItem = ({ email, onEmailClicked, selected }) =&gt; {\n  let classes = &quot;email-item&quot;;\n  if (selected) {\n    classes += &quot; selected&quot;;\n  }\n\n  return \/*#__PURE__*\/(\n    React.createElement(&quot;div&quot;, { onClick: () =&gt; {onEmailClicked(email.id);}, className: classes }, \/*#__PURE__*\/\n    React.createElement(&quot;div&quot;, { className: &quot;email-item__unread-dot&quot;, &quot;data-read&quot;: email.read }), \/*#__PURE__*\/\n    React.createElement(&quot;div&quot;, { className: &quot;email-item__subject truncate&quot; }, email.subject), \/*#__PURE__*\/\n    React.createElement(&quot;div&quot;, { className: &quot;email-item__details&quot; }, \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;email-item__from truncate&quot; }, email.from), \/*#__PURE__*\/\n    React.createElement(&quot;span&quot;, { className: &quot;email-item__time truncate&quot; }, getPrettyDate(email.time)))));\n\n};\nconst EmailDetails = ({ email, onDelete }) =&gt; {\n  if (!email) {\n    return \/*#__PURE__*\/(\n      React.createElement(&quot;div&quot;, { className: &quot;email-content empty&quot; }));\n  }\n  \n  const date = `${getPrettyDate(email.time)} \u00b7 ${getPrettyTime(email.time)}`;\n  const getDeleteButton = () =&gt; {\n    if (email.tag !== 'deleted') {\n      return \/*#__PURE__*\/React.createElement(&quot;span&quot;, { onClick: () =&gt; {onDelete(email.id);}, className: &quot;delete-btn fa fa-trash-o&quot; });\n    }\n    return undefined;\n  };\n\n  return \/*#__PURE__*\/(\n    React.createElement(&quot;div&quot;, { className: &quot;email-content&quot; }, \/*#__PURE__*\/\n    React.createElement(&quot;div&quot;, { className: &quot;email-content__header&quot; }, \/*#__PURE__*\/\n    React.createElement(&quot;h3&quot;, { className: &quot;email-content__subject&quot; }, email.subject),\n    getDeleteButton(), \/*#__PURE__*\/\n    React.createElement(&quot;div&quot;, { className: &quot;email-content__time&quot; }, date), \/*#__PURE__*\/\n    React.createElement(&quot;div&quot;, { className: &quot;email-content__from&quot; }, email.from)), \/*#__PURE__*\/\n\n    React.createElement(&quot;div&quot;, { className: &quot;email-content__message&quot; }, email.message)));\n\n\n};\n\n\/* EmailList contains a list of Email components *\/\nconst EmailList = ({ emails, onEmailSelected, selectedEmailId }) =&gt; {\n  if (emails.length === 0) {\n    return \/*#__PURE__*\/(\n      React.createElement(&quot;div&quot;, { className: &quot;email-list empty&quot; }, &quot;Nothing to see here, great job!&quot;));\n  }\n\n  return \/*#__PURE__*\/(\n    React.createElement(&quot;div&quot;, { className: &quot;email-list&quot; },\n\n    emails.map(email =&gt; {\n      return \/*#__PURE__*\/(\n        React.createElement(EmailListItem, {\n          onEmailClicked: id =&gt; {onEmailSelected(id);},\n          email: email,\n          selected: selectedEmailId === email.id }));\n    })));\n};\n\n\/\/ Render\n$.ajax({ url: 'https:\/\/s3-us-west-2.amazonaws.com\/s.cdpn.io\/311743\/dummy-emails.json',\n  type: 'GET',\n  success: function (result) {\n    React.render( \/*#__PURE__*\/React.createElement(App, { emails: result }), document.getElementById('inbox'));\n  } });\n\n\n\n\/\/ Helper methods\nconst getPrettyDate = date =&gt; {\n  date = date.split(' ')[0];\n  const newDate = date.split('-');\n  const month = months[0];\n  return `${month} ${newDate[2]}, ${newDate[0]}`;\n};\n\n\/\/ Remove the seconds from the time\nconst getPrettyTime = date =&gt; {\n  const time = date.split(' ')[1].split(':');\n  return `${time[0]}:${time[1]}`;\n};<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":1170,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[66],"tags":[],"class_list":["post-1168","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-reactjs"],"_links":{"self":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1168","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/comments?post=1168"}],"version-history":[{"count":2,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1168\/revisions"}],"predecessor-version":[{"id":1172,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1168\/revisions\/1172"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media\/1170"}],"wp:attachment":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media?parent=1168"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/categories?post=1168"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/tags?post=1168"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}