diff --git a/package-lock.json b/package-lock.json index 937a670..9cdd9ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1233,6 +1233,19 @@ "@types/node": "*" } }, + "@types/jest": { + "version": "24.0.13", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.13.tgz", + "integrity": "sha512-3m6RPnO35r7Dg+uMLj1+xfZaOgIHHHut61djNjzwExXN4/Pm9has9C6I1KMYSfz7mahDhWUOVg4HW/nZdv5Pww==", + "requires": { + "@types/jest-diff": "*" + } + }, + "@types/jest-diff": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", + "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==" + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1246,10 +1259,14 @@ "dev": true }, "@types/node": { - "version": "11.13.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.5.tgz", - "integrity": "sha512-/OMMBnjVtDuwX1tg2pkYVSqRIDSmNTnvVvmvP/2xiMAAWf4a5+JozrApCrO4WCAILmXVxfNoQ3E+0HJbNpFVGg==", - "dev": true + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.4.tgz", + "integrity": "sha512-j8YL2C0fXq7IONwl/Ud5Kt0PeXw22zGERt+HSSnwbKOJVsAGkEz3sFCYwaF9IOuoG1HOtE0vKCj6sXF7Q0+Vaw==" + }, + "@types/prop-types": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.1.tgz", + "integrity": "sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==" }, "@types/q": { "version": "1.5.2", @@ -1257,6 +1274,23 @@ "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", "dev": true }, + "@types/react": { + "version": "16.8.19", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.19.tgz", + "integrity": "sha512-QzEzjrd1zFzY9cDlbIiFvdr+YUmefuuRYrPxmkwG0UQv5XF35gFIi7a95m1bNVcFU0VimxSZ5QVGSiBmlggQXQ==", + "requires": { + "@types/prop-types": "*", + "csstype": "^2.2.0" + } + }, + "@types/react-dom": { + "version": "16.8.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.8.4.tgz", + "integrity": "sha512-eIRpEW73DCzPIMaNBDP5pPIpK1KXyZwNgfxiVagb5iGiz6da+9A5hslSX6GAQKdO7SayVCS/Fr2kjqprgAvkfA==", + "requires": { + "@types/react": "*" + } + }, "@types/tapable": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.2.tgz", @@ -4890,6 +4924,11 @@ "cssom": "0.3.x" } }, + "csstype": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.5.tgz", + "integrity": "sha512-JsTaiksRsel5n7XwqPAfB0l3TFKdpjW/kgAELf9vrb5adGA7UCPLajKK5s3nFrcFm3Rkyp/Qkgl73ENc1UY3cA==" + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", diff --git a/package.json b/package.json index 9ede333..9d58f27 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,10 @@ "not op_mini all" ], "dependencies": { + "@types/jest": "24.0.13", + "@types/node": "12.0.4", + "@types/react": "16.8.19", + "@types/react-dom": "16.8.4", "react": "16.8.6", "react-dom": "16.8.6" }, @@ -27,12 +31,12 @@ "test": "react-scripts test", "build": "react-scripts build", "lint": "npm-run-all lint:*", - "lint:js": "eslint '**/*.{js,jsx}'", - "lint:css": "stylelint '**/*.css'", + "lint:js": "eslint \"**/*.{js,jsx}\"", + "lint:css": "stylelint \"**/*.css\"", "lint-fix": "npm-run-all lint-fix:*", - "lint-fix:js": "eslint --fix '**/*.{js,jsx}'", - "lint-fix:css": "stylelint --fix '**/*.css'", - "format": "prettier --write '**/*.{js,jsx,css,json,md}'", + "lint-fix:js": "eslint --fix \"**/*.{js,jsx}\"", + "lint-fix:css": "stylelint --fix \"**/*.css\"", + "format": "prettier --write \"**/*.{js,jsx,css,json,md}\"", "now-build": "npm run build" } } diff --git a/public/fonts/HelveticaNeue.ttf b/public/fonts/HelveticaNeue.ttf new file mode 100644 index 0000000..7864fce Binary files /dev/null and b/public/fonts/HelveticaNeue.ttf differ diff --git a/public/fonts/Yandex Sans Display-Regular.ttf b/public/fonts/Yandex Sans Display-Regular.ttf new file mode 100644 index 0000000..29a8017 Binary files /dev/null and b/public/fonts/Yandex Sans Display-Regular.ttf differ diff --git a/public/images/cat-face.png b/public/images/cat-face.png new file mode 100644 index 0000000..b86d178 Binary files /dev/null and b/public/images/cat-face.png differ diff --git a/public/images/logo.png b/public/images/logo.png new file mode 100644 index 0000000..ae13ce7 Binary files /dev/null and b/public/images/logo.png differ diff --git a/public/images/owl-face.jpg b/public/images/owl-face.jpg new file mode 100644 index 0000000..829e062 Binary files /dev/null and b/public/images/owl-face.jpg differ diff --git a/public/images/sova.png b/public/images/sova.png new file mode 100644 index 0000000..e8b5dd7 Binary files /dev/null and b/public/images/sova.png differ diff --git a/public/images/spam.png b/public/images/spam.png new file mode 100644 index 0000000..6ab6df2 Binary files /dev/null and b/public/images/spam.png differ diff --git a/public/index.html b/public/index.html index 9a8ef8f..5a426cf 100644 --- a/public/index.html +++ b/public/index.html @@ -7,8 +7,7 @@ name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> - - React App + Почта diff --git a/src/app/app.css b/src/app/app.css deleted file mode 100644 index 1c4d511..0000000 --- a/src/app/app.css +++ /dev/null @@ -1,27 +0,0 @@ -.app { - text-align: center; -} - -.app-header { - display: flex; - min-height: 100vh; - flex-direction: column; - align-items: center; - justify-content: center; - background-color: #282c34; - color: #fff; - font-size: calc(10px + 2vmin); -} - -.app-link { - color: #61dafb; -} - -@keyframes app-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/app/app.jsx b/src/app/app.jsx deleted file mode 100644 index f759eed..0000000 --- a/src/app/app.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { Component } from 'react'; - -import './app.css'; - -export class App extends Component { - render() { - return ( -
-
-

- Edit src/app/app.jsx and save to reload. -

- - Learn React - -
-
- ); - } -} diff --git a/src/app/app.module.css b/src/app/app.module.css new file mode 100644 index 0000000..f20cbff --- /dev/null +++ b/src/app/app.module.css @@ -0,0 +1,21 @@ +@font-face { + font-family: Yandex Sans; + src: url('/fonts/Yandex Sans Display-Regular.ttf'); +} + +@font-face { + font-family: Helvetica Neue; + src: url('/fonts/HelveticaNeue.ttf'); +} + +html { + height: 100%; +} + +body { + min-width: 800px; + height: 100%; + min-height: 500px; + margin: 0; + background-color: #e5eaf0; +} diff --git a/src/app/app.tsx b/src/app/app.tsx new file mode 100644 index 0000000..0b68b68 --- /dev/null +++ b/src/app/app.tsx @@ -0,0 +1,16 @@ +import React, { Component } from 'react'; +import Header from './header/header'; +import Main from './main/main'; + +import './app.module.css'; + +export class App extends Component { + render() { + return ( +
+
+
+
+ ); + } +} diff --git a/src/app/header/hamburger/hamburger.module.css b/src/app/header/hamburger/hamburger.module.css new file mode 100644 index 0000000..30c407f --- /dev/null +++ b/src/app/header/hamburger/hamburger.module.css @@ -0,0 +1,11 @@ +.hamburger { + width: 20px; + margin: 15px 11px 0px 0px; + float: left; +} + +.hamburger__div { + height: 3px; + margin: 4px 0; + background-color: black; +} diff --git a/src/app/header/hamburger/hamburger.tsx b/src/app/header/hamburger/hamburger.tsx new file mode 100644 index 0000000..31bfb4f --- /dev/null +++ b/src/app/header/hamburger/hamburger.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +import styles from './hamburger.module.css'; +import headerStyles from './../header.module.css'; + +function Header() { + const classes = `${styles.hamburger} ${headerStyles['header__inline-element']}`; + return ( +
+
+
+
+
+ ); +} + +export default Header; diff --git a/src/app/header/header.module.css b/src/app/header/header.module.css new file mode 100644 index 0000000..56161d2 --- /dev/null +++ b/src/app/header/header.module.css @@ -0,0 +1,14 @@ +.header { + width: 100%; + height: 56px; + box-sizing: border-box; + padding: 0px 20px 0px 22px; + font-family: Yandex Sans, sans-serif; + font-size: 15px; + text-align: center; +} + +.header__inline-element { + display: inline-block; + text-align: left; +} diff --git a/src/app/header/header.tsx b/src/app/header/header.tsx new file mode 100644 index 0000000..406393a --- /dev/null +++ b/src/app/header/header.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import Hamburger from './hamburger/hamburger'; +import Logo from './logo/logo'; +import Search from './search/search'; + +import styles from './header.module.css'; + +function Header() { + return ( +
+ + + +
+ ); +} + +export default Header; diff --git a/src/app/header/logo/logo.module.css b/src/app/header/logo/logo.module.css new file mode 100644 index 0000000..9cff198 --- /dev/null +++ b/src/app/header/logo/logo.module.css @@ -0,0 +1,4 @@ +.logo { + margin-top: 12px; + float: left; +} diff --git a/src/app/header/logo/logo.tsx b/src/app/header/logo/logo.tsx new file mode 100644 index 0000000..1a31d45 --- /dev/null +++ b/src/app/header/logo/logo.tsx @@ -0,0 +1,15 @@ +import React from 'react'; + +import styles from './logo.module.css'; +import headerStyles from './../header.module.css'; + +function Logo() { + const classes = `${styles.logo} ${headerStyles['header__inline-element']}`; + return ( +
+ Ямдекс Почта +
+ ); +} + +export default Logo; diff --git a/src/app/header/search/search.module.css b/src/app/header/search/search.module.css new file mode 100644 index 0000000..24cad11 --- /dev/null +++ b/src/app/header/search/search.module.css @@ -0,0 +1,16 @@ +.header__search { + margin-top: 11px; +} + +.search { + width: 301px; + height: 32px; + padding: 0 9px 0 9px; + + border: none; + background-color: white; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2); + font-size: 14px; + font-weight: 400; + line-height: 32px; +} diff --git a/src/app/header/search/search.tsx b/src/app/header/search/search.tsx new file mode 100644 index 0000000..4eaa580 --- /dev/null +++ b/src/app/header/search/search.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +import styles from './search.module.css'; +import headerStyles from './../header.module.css'; + +function Search() { + const classes = `${styles.search} ${styles.header__search} ${headerStyles['header__inline-element']}`; + return ( + + {/*
Поиск
+
×
*/} + + ); +} + +export default Search; diff --git a/src/app/main/mailbox/data.ts b/src/app/main/mailbox/data.ts new file mode 100644 index 0000000..a1ac73f --- /dev/null +++ b/src/app/main/mailbox/data.ts @@ -0,0 +1,205 @@ +export const MAX_VISIBLE_MAILS = 30; +export const MIN_AUTO_MAIL_INTERVAL = 10; +export const MIN_AUTO_MAIL_CONSEQUENT_SPAN_INTERVAL = 300000; +export const MAX_AUTO_MAIL_INTERVAL = 600000; + +let mailCnt = 0; + +export class Mail { + id: number; + + img: string; + author: string; + title: string; + date: string; + text: string; + state: string; + + old: boolean; + checked: boolean; + deleted: boolean; + + constructor({img, author, title, date, text, old, state = 'hidden'}: {img: string, author: string, title: string, date: string, text: string, old: boolean, state?: string}) { + this.img = img; + this.author = author; + this.title = title; + this.date = date; + this.text = text; + this.old = old; + this.state = state; + this.id = mailCnt++; + this.checked = false; + this.deleted = false; + } + + setCheck(value: boolean) { + this.checked = value; + } + + markDeleted() { + this.deleted = true; + } +} + +export const PRELOADED_MAILS = [ + new Mail({ + img: 'images/owl-face.jpg', + author: 'Сова', + title: 'От совы', + date: 'Mar 9', + text: `

Как падают кошки

+
+
+ Большинство представителей семейства кошачьих имеет склонность к обзору местности с высоты. Крупные лесные кошки-рыси вообше значительную часть времени проводят на деревьях, находясь в засаде или погоне за добычей. А львы и леопарды в саваннах Африки приспособились в жаркое время отдыхать на деревьях, распластавшись на ветках и опустив вниз лапы. Случается, однако, что кошки не удерживаются на высоте и падают. Но и в падении у них есть свои особенности. Многим приходилось наблюдать, как падает обыкновенная кошка, сорвавшись с карниза дома, с дерева или с забора. Сначала она падает к земле головой, спиной или боком, но затем, сделав резкий поворот в воздухе, вывертывается и становится на лапки. И так всегда. Как бы ни падала кошка, приземляется она всегда на лапки и тотчас же может бежать дальше. Такое мгновенное выравнивание положения тела у кошек обеспечивается действием ее вестибулярного аппарата. +
+ +
+ При падении кошки вестибулярный аппарат помогает ей осуществить ряд последовательно возникающих рефлексов и приземлиться на лапы. Ненормальное положение тела в пространстве приводит в раздражение отолитовый прибор каналов внутреннего уха кошки. В ответ на это раздражение происходит рефлекторное сокращение мускулов шеи, приводящих голову животного в нормальное положение по отношению к горизонту. Это - первый рефлекс. Сокращение же шейных мышц и постановка шеи при повороте головы являются возбудителем для осуществления другого рефлекса - сокращения определенных мышц туловища и конечностей. В итоге животное принимает правильное положение. +
+
+ Этот сложный врожденный цепной рефлекс выработался у некоторых животных как приспособление к образу жизни. Ведь животным, особенно из семейства кошачьих, часто приходится во время охоты прыгать и падать с деревьев, скал или со спины своей жертвы. И не будь у них этого приспособительного рефлекса, от них не только ушла бы добыча, но иной раз и самому охотнику пришлось бы пострадать от зубов, рогов или копыт своей жертвы. +
+

Текст статьи взят с сайта petsi.net

+
`, + old: false, + state: 'showed' + }), + new Mail({ + img: 'images/cat-face.png', + author: 'Кот', + title: 'Старое сообщение', + date: 'Feb 23', + text: 'Какое-то старое сообщение', + old: true, + state: 'showed' + }), + new Mail({ + img: 'images/spam.png', + author: 'Неспамнеспамнеспамнеспам', + title: 'Легкий способ зарабатывать 10000000000 в секунду, нужно всего-лишь...', + date: 'Jan 1', + text: '[Читать продолжение в источнике]', + old: false, + state: 'showed' + }), +]; + +export const CAT_NAMES = [ + 'Барсик', + 'Боня', + 'Бакс', + 'Алекс', + 'Бади', + 'Амур', + 'Абуссель', + 'Баксик', + 'Кузя', + 'Персик', + 'Абрек', + 'Абрикос', + 'Тимоша', + 'Авалон', + 'Саймон', + 'Бурбузяка Жабс', + 'Марсик', + 'Абу', + 'Маркиз', + 'Аадон', + 'Дымок', + 'Лаки', + 'Сёма', + 'Симба', + 'Абрамович', + 'Пушок', + 'Айс', + 'Бося', + 'Кекс', + 'Басик', + 'Алмаз', + 'Макс', + 'Гарфилд', + 'Феликс', + 'Том', + 'Тиша', + 'Тишка', + 'Цезарь', + 'Мася', + 'Абакан', + 'Лакки', + 'Васька', + 'Марсель', + 'Адольф', + 'Вася', + 'Бабасик', + 'Зевс', + 'Вольт', + 'Лео', + 'Адидас', + 'Зефир', + 'Максик', + 'Вайс', + 'Барс', + 'Кокос', + 'Рыжик', + 'Мартин', + 'Айс-Крим', + 'Томас', + 'Филя', + 'Нафаня', + 'Дарсик', + 'Марс', + 'Валера', + 'Абориген', + 'Тошка', + 'Базиль', + 'Сосисыч', + 'Абрико', + 'Масик', + 'Абус', + 'Абсент', + 'Умка', + 'Жужа', + 'Веня', + 'Каспер', + 'Грей', + 'Живчик', + 'Убийца мышей', + 'Глюк', + 'Патрик', + 'Оптимус Прайм', + 'Виски', + 'Акакий', + 'Симка', + 'Тёма', + 'Баффи', + 'Аватар', + 'Гаврик', + 'Жан батист Гренуй', + 'Ганс', + 'Вегас', + 'Гаврюша', + 'Авдон', + 'Вин Дизель', + 'Вафлик', + 'Бонни', + 'Снежок', + 'Люцифер', + 'Базилио', + 'Тима', + 'Байрон' +]; + +export const MONTHS = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec' +]; diff --git a/src/app/main/mailbox/footer/footer.module.css b/src/app/main/mailbox/footer/footer.module.css new file mode 100644 index 0000000..1de51e4 --- /dev/null +++ b/src/app/main/mailbox/footer/footer.module.css @@ -0,0 +1,22 @@ +.footer { + position: absolute; + bottom: 0; + + width: 100%; + height: 35px; + + border-top: 1px solid #e2e2e2; + color: #9b9b9b; + font-size: 11px; + line-height: 35px; +} + +.footer__inline-element { + margin-right: 20px; + float: right; +} + +.footer__link { + color: #9b9b9b; + text-decoration: none; +} diff --git a/src/app/main/mailbox/footer/footer.tsx b/src/app/main/mailbox/footer/footer.tsx new file mode 100644 index 0000000..869fc51 --- /dev/null +++ b/src/app/main/mailbox/footer/footer.tsx @@ -0,0 +1,27 @@ +import React from 'react'; + +import styles from './footer.module.css'; + +function Footer() { + return ( +
+
© 2019 – 2019, Ямдекс
+
+ + Реклама + +
+
+ + Помощь и обратная связь + +
+
+ ); +} + +export default Footer; diff --git a/src/app/main/mailbox/helper.ts b/src/app/main/mailbox/helper.ts new file mode 100644 index 0000000..86a8b9e --- /dev/null +++ b/src/app/main/mailbox/helper.ts @@ -0,0 +1,66 @@ +import { Mail, CAT_NAMES, MONTHS } from './data'; + +function getRandomInt(min: number, max: number) { + return Math.floor(Math.random() * (max - min)) + min; +} + +function getAuthor() { + // Cat names + const names = CAT_NAMES; + return names[getRandomInt(0, names.length)]; +} + +function getCurrentTime() { + return new Date().getTime(); +} + +function getDate() { + const date = new Date(); + const months = MONTHS; + const day = date.getDate(); + const monthIndex = date.getMonth(); + return `${months[monthIndex]} ${day}`; +} + +function getImg() { + const size = 100 + (getCurrentTime() % 200); + return `http://placekitten.com/${size}/${size}`; +} + +function sendRequest(link: string) { + const xhttp = new XMLHttpRequest(); + let res = ''; + xhttp.onreadystatechange = () => { + if (xhttp.readyState === 4 && xhttp.status === 200) { + res = xhttp.responseText; + } + }; + xhttp.open('GET', link, false); + xhttp.send(); + return res; +} + +function getTitle() { + return sendRequest( + 'https://baconipsum.com/api/?type=all-meat&sentences=1&start-with-lorem=0&format=text' + ); +} + +function getText() { + return sendRequest( + 'https://baconipsum.com/api/?type=all-meat¶graphs=5&start-with-lorem=1&format=text' + ); +} + +function generateMail() { + return new Mail({ + img: getImg(), + author: getAuthor(), + title: getTitle(), + date: getDate(), + text: getText(), + old: false, + }); +} + +export { generateMail, getCurrentTime, getRandomInt }; diff --git a/src/app/main/mailbox/mail/mail.module.css b/src/app/main/mailbox/mail/mail.module.css new file mode 100644 index 0000000..19a5a3e --- /dev/null +++ b/src/app/main/mailbox/mail/mail.module.css @@ -0,0 +1,128 @@ +.mailbox__mail { + width: 100%; + height: 40px; + + border-bottom: 1px solid #e2e2e2; + color: #cccccc; + font-size: 13px; + line-height: 40px; + overflow-y: hidden; +} + +.mailbox__mail-element { + display: inline-block; + overflow: hidden; + vertical-align: middle; +} + +.checkbox { + display: inline-block; + margin: 0px 10px 0px 20px; + vertical-align: middle; +} + +.checkbox__input { + position: relative; + + display: none; + float: left; +} + +.checkbox__span { + width: 16px; + height: 16px; + + border: 1px solid; + border-radius: 3px; + float: left; +} + +.checkbox__input:checked + .checkbox__span:before { + content: '✓'; + float: left; + font-size: 16px; + font-weight: bold; + line-height: 16px; +} + +.mail__pic { + margin-right: 10px; +} + +.pic__img { + width: 30px; + height: 30px; + vertical-align: middle; +} + +.mail__author { + width: 155px; + color: black; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mail__title { + width: calc(100% - 355px); + box-sizing: border-box; + padding-left: 10px; + color: black; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mail__new { + font-weight: 700; +} + +.mail__dot { + width: 10px; + height: 10px; + background-color: #6287bd; + border-radius: 50%; + visibility: hidden; +} + +.mail__new .mail__dot { + visibility: visible; +} + +.mail__time { + width: 50px; + margin-right: 20px; + color: #969799; + float: right; + font-weight: 500; + text-align: right; +} + +.mailbox__mail[data-state='collapsed'] { + height: 0px; + + border: none; + transition: height 0.4s; +} + +.mailbox__mail[data-state='init'] { + height: 0px; + + border-width: 0px; + + animation: appearance 0.4s 1 ease-out forwards; +} + +@keyframes appearance { + from { + height: 0px; + background-color: #6287bd; + } + to { + height: 40px; + background-color: white; + } +} + +.mailbox__mail[data-state='showed'] { + height: 40px; + transition: height 0.4s; +} diff --git a/src/app/main/mailbox/mail/mail.tsx b/src/app/main/mailbox/mail/mail.tsx new file mode 100644 index 0000000..dd7322a --- /dev/null +++ b/src/app/main/mailbox/mail/mail.tsx @@ -0,0 +1,70 @@ +import React, { Component } from 'react'; + +import { Mail as MailType } from '../data'; +import { MailBoxState } from '../mailbox' + +import styles from './mail.module.css'; + +interface MailProps { + mail: MailType; + onClick: () => void; + onAnimationEnd: () => void; +} + +export class Mail extends Component { + trigger: React.RefObject; + + constructor(props: Readonly) { + super(props); + this.trigger = React.createRef(); + } + + render() { + const { mail, onClick, onAnimationEnd } = this.props; + const checkboxId = `checkbox_${mail.id}`; + + return ( +