From c778806150f2610254e283e083f69bc9d4f17642 Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Sun, 22 Jul 2018 21:56:52 +0300 Subject: [PATCH 01/14] PREVIOUS COMMITS --- .gitignore | 5 + phone-book/.gitignore | 2 + phone-book/.vscode/settings.json | 3 + phone-book/build/bundle.js | 173 +++++++ phone-book/img/icon.ico | Bin 0 -> 169959 bytes phone-book/index.html | 20 + phone-book/package.json | 22 + phone-book/src/add-user/add-user.js | 118 +++++ .../mobile-operators-identifiers.js | 25 + phone-book/src/components/users.js | 6 + phone-book/src/contact/contact.js | 181 +++++++ phone-book/src/index.js | 196 ++++++++ phone-book/src/keypad/keypad.js | 446 ++++++++++++++++++ phone-book/src/url/url.js | 33 ++ phone-book/src/user-page/user-page.js | 57 +++ phone-book/style/add-user.css | 8 + phone-book/style/keypad.css | 261 ++++++++++ phone-book/style/main.css | 100 ++++ phone-book/style/user-page.css | 19 + phone-book/webpack.config.js | 15 + 20 files changed, 1690 insertions(+) create mode 100644 phone-book/.gitignore create mode 100644 phone-book/.vscode/settings.json create mode 100644 phone-book/build/bundle.js create mode 100644 phone-book/img/icon.ico create mode 100644 phone-book/index.html create mode 100644 phone-book/package.json create mode 100644 phone-book/src/add-user/add-user.js create mode 100644 phone-book/src/components/mobile-operators-identifiers.js create mode 100644 phone-book/src/components/users.js create mode 100644 phone-book/src/contact/contact.js create mode 100644 phone-book/src/index.js create mode 100644 phone-book/src/keypad/keypad.js create mode 100644 phone-book/src/url/url.js create mode 100644 phone-book/src/user-page/user-page.js create mode 100644 phone-book/style/add-user.css create mode 100644 phone-book/style/keypad.css create mode 100644 phone-book/style/main.css create mode 100644 phone-book/style/user-page.css create mode 100644 phone-book/webpack.config.js diff --git a/.gitignore b/.gitignore index 0088af8..55ce77f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +phone-book/node_modules +phone-book/img +phone-book/package-lock.json + # Logs logs *.log @@ -62,3 +66,4 @@ typings/ # IDE .idea + diff --git a/phone-book/.gitignore b/phone-book/.gitignore new file mode 100644 index 0000000..ad060b9 --- /dev/null +++ b/phone-book/.gitignore @@ -0,0 +1,2 @@ +package-lock.json +img \ No newline at end of file diff --git a/phone-book/.vscode/settings.json b/phone-book/.vscode/settings.json new file mode 100644 index 0000000..3b66410 --- /dev/null +++ b/phone-book/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "git.ignoreLimitWarning": true +} \ No newline at end of file diff --git a/phone-book/build/bundle.js b/phone-book/build/bundle.js new file mode 100644 index 0000000..9157a0b --- /dev/null +++ b/phone-book/build/bundle.js @@ -0,0 +1,173 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = "/build/"; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "./src/add-user/add-user.js": +/*!**********************************!*\ + !*** ./src/add-user/add-user.js ***! + \**********************************/ +/*! exports provided: AddUserPage */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AddUserPage\", function() { return AddUserPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nclass AddUserPage {\n constructor(store) {\n this.setStateContact = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'ADD USER',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.serverSide = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"]();\n }\n\n render() {\n return (/*html*/`\n
\n\n
\n
\n Add new user\n
\n
\n\n
\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n \n
\n \n \n ex: https://cloud-drive/photo123456.\n
\n\n
\n \n
\n \n
\n
\n\n
\n `\n );\n }\n\n applyListenersForAddUserPage() {\n // const fullNameInput = document.querySelector('#fullName-input');\n // const emailInput = document.querySelector('#email-input');\n // const phoneNumberInput = document.querySelector('#phoneNumber-input');\n // const birthDateInput = document.querySelector('#birthDate-input');\n // const addressInput = document.querySelector('#address-input');\n // const genderInput = document.querySelector('#gender-selection');\n // const avatarUrlInput = document.querySelector('#avatarUrl-input');\n\n const addUserForm = document.querySelector('form');\n const inputs = [...addUserForm.elements].filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT');\n\n addUserForm.addEventListener('submit', e => {\n\n const user = inputs.reduce((newUser, input) => {\n const KEY = input.name;\n const VALUE = input.value;\n\n if (VALUE.lenght !== 0) {\n newUser[KEY] = VALUE;\n }\n if (VALUE === 'Male' || VALUE === 'Female') {\n const firstChar = input.value[0];\n newUser[KEY] = firstChar;\n }\n return newUser;\n }, {});\n\n this.serverSide.postUser(user);\n });\n }\n\n isValid() {}\n}\n\n\n\n//# sourceURL=webpack:///./src/add-user/add-user.js?"); + +/***/ }), + +/***/ "./src/components/mobile-operators-identifiers.js": +/*!********************************************************!*\ + !*** ./src/components/mobile-operators-identifiers.js ***! + \********************************************************/ +/*! exports provided: MOBILE_OPERATORS_IDENTIFICATORS */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MOBILE_OPERATORS_IDENTIFICATORS\", function() { return MOBILE_OPERATORS_IDENTIFICATORS; });\nconst MOBILE_OPERATORS_IDENTIFICATORS = {\n kuivstar: ['067', '096', '097', '098', '068'],\n vodafone: ['050', '066', '095', '099'],\n life: ['063', '093', '073']\n};\n\n\n\n//# sourceURL=webpack:///./src/components/mobile-operators-identifiers.js?"); + +/***/ }), + +/***/ "./src/components/users.js": +/*!*********************************!*\ + !*** ./src/components/users.js ***! + \*********************************/ +/*! exports provided: users */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"users\", function() { return users; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nconst serverSide = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"]();\nconst users = serverSide.getUsersFromServer();\n\n\n\n//# sourceURL=webpack:///./src/components/users.js?"); + +/***/ }), + +/***/ "./src/contact/contact.js": +/*!********************************!*\ + !*** ./src/contact/contact.js ***! + \********************************/ +/*! exports provided: ContactPage */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ContactPage\", function() { return ContactPage; });\n/* harmony import */ var _components_users__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/users */ \"./src/components/users.js\");\n\n\n/* ================== CONTACT START================== */\n\nclass ContactPage {\n constructor(store) {\n this.setStateContact = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'CONTACT',\n activePage: this.render()\n };\n setState(initializeState);\n };\n }\n\n render() {\n const contactTempalte = /*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n
\n\n
\n \n\n \n \n \n \n \n \n \n\n \n ${this.contactListComponent(_components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"])}\n \n\n
NameLast NameEmail
\n
\n
\n `;\n\n return contactTempalte;\n }\n\n contactListComponent(userList) {\n return userList.reduce((listStructure, user) => {\n const splitedFullName = user.fullName.split(' ');\n const userFirstName = splitedFullName[0];\n const userLastName = splitedFullName[1];\n const userEmail = user.email;\n\n const userComponent = /*html*/`\n \n ${userFirstName} \n ${userLastName} \n ${userEmail} \n \n `;\n\n listStructure += userComponent;\n return listStructure;\n }, ``);\n }\n\n applyListenerForContactPage() {\n const wraperForTh = document.getElementById('wraper-for-th');\n wraperForTh.addEventListener('click', e => {\n const TH_ELEM_CONTAINS = e.target.textContent.trim();\n const PREDICT_TEXT_CONTENT = {\n firstName: 'Name',\n lastName: 'Last Name',\n email: 'Email'\n };\n\n const listOfContacts = document.getElementById('list-of-contacts');\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.firstName) {\n const firstName = 0;\n const sortedListByFirsName = this.mergeSort(_components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"], firstName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByFirsName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.lastName) {\n const lastName = 1;\n const sortedListByLastName = this.mergeSort(_components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"], lastName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByLastName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.email) {\n const sortedListByEmail = this.sortUsersByValue('email', _components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"]);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByEmail);\n return;\n }\n });\n\n /* SORT USERS BY INPUTED LETTERS OF NAME */\n const contactSearchField = document.querySelector('#search');\n\n contactSearchField.addEventListener('input', () => {\n const VALUE = contactSearchField.value;\n const filteredUsers = this.filterUsersByInputValueByName(VALUE);\n const listOfContacts = document.getElementById('list-of-contacts');\n\n filteredUsers.length === 0 ? listOfContacts.innerHTML = /*html*/`

No such users

` : listOfContacts.innerHTML = this.contactListComponent(filteredUsers);\n });\n }\n\n sortUsersByValue(key, users) {\n const sortFunction = function (value, nextValue) {\n if (value[key] > nextValue[key]) return 1;\n if (value[key] < nextValue[key]) return -1;\n };\n\n return [...users].sort(sortFunction);\n }\n\n mergeSort(arr, index) {\n\n const len = arr.length;\n if (len < 2) return arr;\n const mid = Math.floor(len / 2),\n left = arr.slice(0, mid),\n right = arr.slice(mid);\n\n return this.merge(this.mergeSort(left, index), this.mergeSort(right, index), index);\n }\n\n merge(left, right, index) {\n let result = [],\n lLen = left.length,\n rLen = right.length,\n l = 0,\n r = 0;\n while (l < lLen && r < rLen) {\n const leftWord = left[l].fullName.split(' ')[index];\n const rightWord = right[r].fullName.split(' ')[index];\n if (leftWord < rightWord) {\n result.push(left[l++]);\n } else {\n result.push(right[r++]);\n }\n }\n\n return result.concat(left.slice(l)).concat(right.slice(r));\n }\n\n filterUsersByInputValueByName(inputValue) {\n return _components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"].reduce((newUsers, user) => {\n const firstName = user.fullName.split(' ')[0].toLowerCase();\n\n const comparedPartOfName = firstName.slice(0, inputValue.length);\n\n if (inputValue.toLowerCase() === comparedPartOfName) {\n newUsers.push(user);\n }\n\n return newUsers;\n }, []);\n }\n}\n\n/* ================== CONTACT END================== */\n\n\n\n//# sourceURL=webpack:///./src/contact/contact.js?"); + +/***/ }), + +/***/ "./src/index.js": +/*!**********************!*\ + !*** ./src/index.js ***! + \**********************/ +/*! no exports provided */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _contact_contact__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./contact/contact */ \"./src/contact/contact.js\");\n/* harmony import */ var _keypad_keypad__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./keypad/keypad */ \"./src/keypad/keypad.js\");\n/* harmony import */ var _add_user_add_user__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./add-user/add-user */ \"./src/add-user/add-user.js\");\n\n\n\n\n\nclass App {\n constructor() {\n this.store = this.createStore();\n this.pages = {\n 'contacts': new _contact_contact__WEBPACK_IMPORTED_MODULE_0__[\"ContactPage\"](this.store),\n 'keypad': new _keypad_keypad__WEBPACK_IMPORTED_MODULE_1__[\"KeypadPage\"](this.store),\n 'addUser': new _add_user_add_user__WEBPACK_IMPORTED_MODULE_2__[\"AddUserPage\"](this.store),\n 'footer': new FooterNavigationBar()\n };\n this.pages.contacts.setStateContact();\n this.render();\n this.pages.contacts.applyListenerForContactPage();\n this.applyListenerForNavigation();\n }\n\n createStore() {\n let state;\n\n return {\n getState() {\n return state;\n },\n setState(newState) {\n state = newState;\n }\n };\n }\n\n reducer(action) {\n const currentState = this.store.getState();\n const mainWraper = document.getElementById('main-wraper');\n const switchBetweenPages = () => {\n mainWraper.firstElementChild.outerHTML = currentState.activePage;\n };\n\n if (action.type === 'MOVE_TO_KEYPAD_PAGE') {\n this.pages.keypad.setStateKeypad();\n switchBetweenPages();\n this.pages.keypad.applyListenerForKeypadPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_CONTACT_PAGE') {\n this.pages.contacts.setStateContact();\n switchBetweenPages();\n this.pages.contacts.applyListenerForContactPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_ADD_USER_PAGE') {\n this.pages.addUser.setStateContact();\n switchBetweenPages();\n this.pages.addUser.applyListenersForAddUserPage();\n return;\n }\n }\n\n render() {\n const currentState = this.store.getState();\n const FOOTER = this.pages.footer.render();\n\n const appTemplate = /*html*/`\n
\n ${currentState.activePage}\n ${FOOTER}\n
\n `;\n\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = appTemplate;\n }\n\n applyListenerForNavigation() {\n\n const _MOVE_TO_KEYPAD_PAGE = {\n type: 'MOVE_TO_KEYPAD_PAGE'\n };\n\n const _MOVE_TO_CONTACT_PAGE = {\n type: 'MOVE_TO_CONTACT_PAGE'\n };\n\n const _MOVE_TO_ADD_USER_PAGE = {\n type: 'MOVE_TO_ADD_USER_PAGE'\n };\n\n const wraperForFooter = document.getElementById('wraper-for-footer');\n wraperForFooter.addEventListener('click', e => {\n const currentState = this.store.getState();\n\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'to-keypad-page' || BUTTON_ID_FROM_SVG === 'to-keypad-page' || BUTTON_ID_FROM_PATH === 'to-keypad-page') {\n\n if (currentState.stateName !== 'KEYPAD') {\n this.pages.keypad.setStateKeypad();\n return this.reducer(_MOVE_TO_KEYPAD_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-contact-page' || BUTTON_ID_FROM_SVG === 'to-contact-page' || BUTTON_ID_FROM_PATH === 'to-contact-page') {\n\n if (currentState.stateName !== 'CONTACT') {\n this.pages.contacts.setStateContact();\n return this.reducer(_MOVE_TO_CONTACT_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-addUser-page' || BUTTON_ID_FROM_SVG === 'to-addUser-page' || BUTTON_ID_FROM_PATH === 'to-addUser-page') {\n\n if (currentState.stateName !== 'ADD USER') {\n this.pages.addUser.setStateContact();\n return this.reducer(_MOVE_TO_ADD_USER_PAGE);\n }\n return;\n }\n });\n }\n}\n\n/* ================== FOOTER START================== */\n\nclass FooterNavigationBar {\n constructor() {\n this.icons = {\n contactIcon: {\n id: 'to-contact-page',\n class: 'far fa-address-book'\n },\n keypadIcon: {\n id: 'to-keypad-page',\n class: 'fas fa-tty'\n },\n addUserIcon: {\n id: 'to-addUser-page',\n class: 'fas fa-user-plus'\n }\n };\n }\n\n render() {\n const navigationBar = /*html*/`\n \n `;\n\n return navigationBar;\n }\n\n createIcon(iconPattern) {\n const ID = iconPattern.id;\n const CLASS = iconPattern.class;\n\n const icon = /*html*/`\n
\n \n
\n `;\n\n return icon;\n }\n\n}\n\n/* ================== FOOTER END================== */\n\nconst APPLICATION = new App();\n\n//# sourceURL=webpack:///./src/index.js?"); + +/***/ }), + +/***/ "./src/keypad/keypad.js": +/*!******************************!*\ + !*** ./src/keypad/keypad.js ***! + \******************************/ +/*! exports provided: KeypadPage */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"KeypadPage\", function() { return KeypadPage; });\n/* harmony import */ var _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/mobile-operators-identifiers */ \"./src/components/mobile-operators-identifiers.js\");\n\n\n/* ================== KEYPAD START================== */\n\nclass KeypadPage {\n constructor(store) {\n this.setStateKeypad = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'KEYPAD',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.callMode = new CallMode();\n }\n\n render() {\n const buttons = {\n ONE: '1',\n TWO: '2',\n THREE: '3',\n FOUR: '4',\n FIVE: '5',\n SIX: '6',\n SEVEN: '7',\n EIGHT: '8',\n NINE: '9',\n ZERO: '0',\n ASTERISK: '*',\n HASH: '#'\n };\n\n return (/*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n \n
\n
\n
\n\n
\n \n
\n
\n ${this.createButton(buttons.ONE)}\n ${this.createButton(buttons.TWO)}\n ${this.createButton(buttons.THREE)}\n
\n
\n ${this.createButton(buttons.FOUR)}\n ${this.createButton(buttons.FIVE)}\n ${this.createButton(buttons.SIX)}\n
\n
\n ${this.createButton(buttons.SEVEN)}\n ${this.createButton(buttons.EIGHT)}\n ${this.createButton(buttons.NINE)}\n
\n
\n ${this.createButton(buttons.ASTERISK)}\n ${this.createButton(buttons.ZERO)}\n ${this.createButton(buttons.HASH)}\n
\n
\n\n
\n
\n
\n \n\n
\n\n
\n `\n );\n }\n\n createButton(value) {\n const button = /*html*/`\n
${value}
\n `;\n\n return button;\n }\n\n applyListenerForKeypadPage() {\n\n /* ADD NUMBER */\n const keypadButtons = document.getElementById('wraper-for-buttons');\n const fieldForNumber = document.getElementById('number');\n const fieldForOperator = document.getElementById('operator');\n\n const toFormateNumberFieldForAdding = () => {\n const numbersFromField = fieldForNumber.textContent.replace(/\\D/gm, '');\n let finalConstructions = null;\n\n if (numbersFromField.length === 1) {\n finalConstructions = numbersFromField.replace(/(.{1})/g, '($1');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 3) {\n finalConstructions = numbersFromField.replace(/(.{3})/g, '($1)');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 4) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{1})/g, '($1) $2');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 7) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{1})/g, '($1) $2-$3');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 9) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{2})(.{1})/g, '($1) $2-$3-$4');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n };\n\n keypadButtons.addEventListener('click', e => {\n const TARGET_CLASS_NAME = e.target.className;\n\n if (TARGET_CLASS_NAME === 'number-btn') {\n const BUTTON_VALUE = e.target.textContent;\n fieldForNumber.textContent += BUTTON_VALUE;\n\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n }\n });\n\n /* REMOVE NUMBER */\n const deleteButton = document.getElementById('delete');\n\n deleteButton.addEventListener('click', e => {\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'delete' || BUTTON_ID_FROM_SVG === 'delete' || BUTTON_ID_FROM_PATH === 'delete') {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n\n return;\n }\n });\n\n /* TO CALL BUTTON */\n const mainWraper = document.getElementById('main-wraper');\n\n const toCallButton = document.getElementById('call-btn');\n toCallButton.addEventListener('click', () => {\n const ERROR_BLOCK = document.getElementById('error-block');\n\n if (fieldForNumber.textContent.length < 3) {\n ERROR_BLOCK.textContent = `ERROR you've typed incorrect number`;\n setTimeout(() => {\n ERROR_BLOCK.textContent = '';\n }, 3000);\n return;\n }\n\n const NUMBER_FOR_CALL_MODE = this.callMode.getNumber();\n const OPERATOR_FOR_CALL_MODE = this.callMode.getOperator();\n\n mainWraper.classList.add('call-mode');\n mainWraper.innerHTML = this.callMode.render(NUMBER_FOR_CALL_MODE, OPERATOR_FOR_CALL_MODE);\n this.callMode.applyListenerForCallMode();\n });\n\n /* WRITING NUMBER BY KEYBOARD */\n\n const keyCodes = {\n ONE: 49,\n TWO: 50,\n THREE: 51,\n FOUR: 52,\n FIVE: 53,\n SIX: 54,\n SEVEN: 55,\n EIGHT: 56,\n NINE: 57,\n ZERO: 48,\n ASTERISK: 42,\n HASH: 35,\n DELETE: 8\n };\n\n const SINGLE_TAPS = e => {\n\n if (e.keyCode === keyCodes.ONE) {\n const ONE = '1';\n fieldForNumber.textContent += ONE;\n }\n if (e.keyCode === keyCodes.TWO) {\n const TWO = '2';\n fieldForNumber.textContent += TWO;\n }\n if (e.keyCode === keyCodes.THREE) {\n const THREE = '3';\n fieldForNumber.textContent += THREE;\n }\n if (e.keyCode === keyCodes.FOUR) {\n const FOUR = '4';\n fieldForNumber.textContent += FOUR;\n }\n if (e.keyCode === keyCodes.FIVE) {\n const FIVE = '5';\n fieldForNumber.textContent += FIVE;\n }\n if (e.keyCode === keyCodes.SIX) {\n const SIX = '6';\n fieldForNumber.textContent += SIX;\n }\n if (e.keyCode === keyCodes.SEVEN) {\n const SEVEN = '7';\n fieldForNumber.textContent += SEVEN;\n }\n if (e.keyCode === keyCodes.EIGHT) {\n const EIGHT = '8';\n fieldForNumber.textContent += EIGHT;\n }\n if (e.keyCode === keyCodes.NINE) {\n const NINE = '9';\n fieldForNumber.textContent += NINE;\n }\n if (e.keyCode === keyCodes.ZERO) {\n const ZERO = '0';\n fieldForNumber.textContent += ZERO;\n }\n if (e.keyCode === keyCodes.HASH) {\n const HASH = '#';\n fieldForNumber.textContent += HASH;\n }\n if (e.keyCode === keyCodes.ASTERISK) {\n const ASTERISK = '*';\n fieldForNumber.textContent += ASTERISK;\n }\n\n /* IDENTIFICATION FUNCTIONAL */\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n };\n\n const DELETE_FUNCTIONAL = e => {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n\n if (e.keyCode === keyCodes.DELETE) {\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n return;\n }\n };\n\n window.addEventListener('keypress', SINGLE_TAPS);\n window.addEventListener('keydown', DELETE_FUNCTIONAL);\n }\n\n indentifyMobileOperator(firstThreeNumbers) {\n let operator;\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].kuivstar.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Kuivstar';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].life.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Life';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].vodafone.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Vodafone';\n }\n });\n\n return operator;\n }\n}\n\n/* ================== KEYPAD END================== */\n\n/* ================== CALL MODE START================== */\nclass CallMode {\n constructor() {}\n\n render(number, operator) {\n return (/*html*/`\n
\n
\n\n
\n ${number}\n ${operator}\n
\n\n
\n \n \n \n \n \n
\n\n
\n\n
\n\n
\n\n
\n\n
\n
\n \n
\n mute\n
\n\n
\n
\n \n
\n keypad\n
\n \n
\n
\n \n
\n volume\n
\n \n
\n\n
\n
\n
\n \n
\n add\n
\n \n
\n
\n \n
\n video\n
\n\n
\n
\n \n
\n contacts\n
\n
\n\n
\n\n
\n
\n \n
\n
\n\n
\n
\n `\n );\n }\n\n getNumber() {\n const phoneNumber = document.getElementById('number');\n return phoneNumber.textContent;\n }\n\n getOperator() {\n const phoneOperator = document.getElementById('operator');\n return phoneOperator.textContent;\n }\n\n applyListenerForCallMode() {}\n\n setSavedKeypadPage(page) {\n this.savedKeypadPage = page;\n }\n}\n\n/* ================== CALL MODE END================== */\n\n\n\n//# sourceURL=webpack:///./src/keypad/keypad.js?"); + +/***/ }), + +/***/ "./src/url/url.js": +/*!************************!*\ + !*** ./src/url/url.js ***! + \************************/ +/*! exports provided: Url */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Url\", function() { return Url; });\nclass Url {\n constructor() {\n this.url = 'http://easycode-js.herokuapp.com/myba/users';\n }\n\n getUsersFromServer() {\n return (async () => {\n const data = await fetch(this.url);\n return this.users = await data.json();\n })();\n }\n\n obtainUsers() {\n this.getUsersFromServer();\n return this.users;\n }\n\n postUser(user) {\n const xhr = new XMLHttpRequest();\n xhr.open('POST', this.url, true);\n xhr.setRequestHeader('Content-type', 'application/json');\n xhr.send(JSON.stringify(user));\n }\n\n deleteUserById(id) {\n const xhr = new XMLHttpRequest();\n xhr.open('DELETE', `${this.url}/${id}`, true);\n xhr.setRequestHeader('Content-type', 'application/json');\n xhr.send();\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/url/url.js?"); + +/***/ }) + +/******/ }); \ No newline at end of file diff --git a/phone-book/img/icon.ico b/phone-book/img/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..12f63f7c89fe8b381fe67151431a239507493a39 GIT binary patch literal 169959 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

s}%TWXTKBK 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 + + + + + Phone Book + + + + + + + + +

+ + + + + \ No newline at end of file diff --git a/phone-book/package.json b/phone-book/package.json new file mode 100644 index 0000000..92c2c22 --- /dev/null +++ b/phone-book/package.json @@ -0,0 +1,22 @@ +{ + "name": "phone-book", + "version": "1.0.0", + "description": "", + "main": "index.js", + "presets": ["env"], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "dev": "webpack --mode development", + "build": "webpack --mode production" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "babel-core": "^6.26.3", + "babel-loader": "^7.1.5", + "babel-preset-env": "^1.7.0", + "webpack": "^4.16.3", + "webpack-cli": "^3.1.0" + } +} diff --git a/phone-book/src/add-user/add-user.js b/phone-book/src/add-user/add-user.js new file mode 100644 index 0000000..870fc94 --- /dev/null +++ b/phone-book/src/add-user/add-user.js @@ -0,0 +1,118 @@ +import {Url} from '../url/url'; + +class AddUserPage { + constructor(store) { + this.setStateContact = () => { + const {setState} = store; + const initializeState = { + stateName: 'ADD USER', + activePage: this.render(), + }; + setState(initializeState); + } + + this.serverSide = new Url(); + } + + render() { + return /*html*/` +
+ +
+
+ Add new user +
+
+ +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + ex: https://cloud-drive/photo123456. +
+ +
+ +
+ +
+
+ +
+ `; + } + + applyListenersForAddUserPage() { + // const fullNameInput = document.querySelector('#fullName-input'); + // const emailInput = document.querySelector('#email-input'); + // const phoneNumberInput = document.querySelector('#phoneNumber-input'); + // const birthDateInput = document.querySelector('#birthDate-input'); + // const addressInput = document.querySelector('#address-input'); + // const genderInput = document.querySelector('#gender-selection'); + // const avatarUrlInput = document.querySelector('#avatarUrl-input'); + + const addUserForm = document.querySelector('form'); + const inputs = [...addUserForm.elements] + .filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT'); + + addUserForm.addEventListener('submit', (e) => { + + const user = inputs.reduce((newUser, input) => { + const KEY = input.name; + const VALUE = input.value; + + if(VALUE.lenght !== 0) { + newUser[KEY] = VALUE; + } + if(VALUE === 'Male' || VALUE === 'Female') { + const firstChar = input.value[0]; + newUser[KEY] = firstChar; + } + return newUser; + }, {}); + + this.serverSide.postUser(user); + }) + } + + isValid() { + + } +} + +export {AddUserPage}; diff --git a/phone-book/src/components/mobile-operators-identifiers.js b/phone-book/src/components/mobile-operators-identifiers.js new file mode 100644 index 0000000..9f41efd --- /dev/null +++ b/phone-book/src/components/mobile-operators-identifiers.js @@ -0,0 +1,25 @@ +const MOBILE_OPERATORS_IDENTIFICATORS = { + kuivstar: [ + '067', + '096', + '097', + '098', + '068' + ], + vodafone: [ + '050', + '066', + '095', + '099' + ], + life: [ + '063', + '093', + '073' + ] +}; + + +export { + MOBILE_OPERATORS_IDENTIFICATORS +}; \ No newline at end of file diff --git a/phone-book/src/components/users.js b/phone-book/src/components/users.js new file mode 100644 index 0000000..25774c2 --- /dev/null +++ b/phone-book/src/components/users.js @@ -0,0 +1,6 @@ +import {Url} from '../url/url'; + +const serverSide = new Url(); +const users = serverSide.getUsersFromServer(); + +export {users}; \ No newline at end of file diff --git a/phone-book/src/contact/contact.js b/phone-book/src/contact/contact.js new file mode 100644 index 0000000..81c689c --- /dev/null +++ b/phone-book/src/contact/contact.js @@ -0,0 +1,181 @@ +import {users} from '../components/users'; + +/* ================== CONTACT START================== */ + +class ContactPage { + constructor(store) { + this.setStateContact = () => { + const {setState} = store; + const initializeState = { + stateName: 'CONTACT', + activePage: this.render(), + }; + setState(initializeState); + } + + } + + render() { + const contactTempalte = /*html*/` +
+ +
+
+
+ + +
+
+
+ +
+ + + + + + + + + + + + ${this.contactListComponent(users)} + + +
NameLast NameEmail
+
+
+ `; + + return contactTempalte; + } + + contactListComponent(userList) { + return userList.reduce((listStructure, user) => { + const splitedFullName = user.fullName.split(' '); + const userFirstName = splitedFullName[0]; + const userLastName = splitedFullName[1]; + const userEmail = user.email; + + const userComponent = /*html*/` + + ${userFirstName} + ${userLastName} + ${userEmail} + + `; + + listStructure += userComponent; + return listStructure; + }, ``) + } + + applyListenerForContactPage() { + const wraperForTh = document.getElementById('wraper-for-th'); + wraperForTh.addEventListener('click', (e) => { + const TH_ELEM_CONTAINS = e.target.textContent.trim(); + const PREDICT_TEXT_CONTENT = { + firstName: 'Name', + lastName: 'Last Name', + email: 'Email' + }; + + const listOfContacts = document.getElementById('list-of-contacts'); + + if(TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.firstName) { + const firstName = 0; + const sortedListByFirsName = this.mergeSort(users, firstName); + listOfContacts.innerHTML = this.contactListComponent(sortedListByFirsName); + return; + } + + if(TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.lastName) { + const lastName = 1; + const sortedListByLastName = this.mergeSort(users, lastName); + listOfContacts.innerHTML = this.contactListComponent(sortedListByLastName); + return; + } + + if(TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.email) { + const sortedListByEmail = this.sortUsersByValue('email', users); + listOfContacts.innerHTML = this.contactListComponent(sortedListByEmail); + return; + } + }) + + /* SORT USERS BY INPUTED LETTERS OF NAME */ + const contactSearchField = document.querySelector('#search'); + + contactSearchField.addEventListener('input', () => { + const VALUE = contactSearchField.value; + const filteredUsers = this.filterUsersByInputValueByName(VALUE); + const listOfContacts = document.getElementById('list-of-contacts'); + + filteredUsers.length === 0 + ? listOfContacts.innerHTML = /*html*/`

No such users

` + : listOfContacts.innerHTML = this.contactListComponent(filteredUsers); + + + }) + } + + sortUsersByValue(key, users) { + const sortFunction = function(value, nextValue) { + if(value[key] > nextValue[key]) return 1; + if(value[key] < nextValue[key]) return -1; + } + + return [...users].sort(sortFunction); + } + + mergeSort(arr, index) { + + const len = arr.length; + if(len < 2) return arr; + const mid = Math.floor(len / 2), + left = arr.slice(0, mid), + right =arr.slice(mid); + + return this.merge(this.mergeSort(left, index), this.mergeSort(right, index), index); + } + + merge(left, right, index) { + let result = [], + lLen = left.length, + rLen = right.length, + l = 0, + r = 0; + while(l < lLen && r < rLen){ + const leftWord = left[l].fullName.split(' ')[index]; + const rightWord = right[r].fullName.split(' ')[index]; + if(leftWord < rightWord){ + result.push(left[l++]); + } + else{ + result.push(right[r++]); + } + } + + return result.concat(left.slice(l)).concat(right.slice(r)); + } + + filterUsersByInputValueByName(inputValue) { + return users.reduce((newUsers, user) => { + const firstName = user.fullName.split(' ')[0].toLowerCase(); + + const comparedPartOfName = firstName.slice(0, inputValue.length); + + if(inputValue.toLowerCase() === comparedPartOfName) { + newUsers.push(user); + } + + return newUsers; + }, []); + + } +} + +/* ================== CONTACT END================== */ + +export {ContactPage}; \ No newline at end of file diff --git a/phone-book/src/index.js b/phone-book/src/index.js new file mode 100644 index 0000000..9650524 --- /dev/null +++ b/phone-book/src/index.js @@ -0,0 +1,196 @@ + +import {ContactPage} from './contact/contact'; +import {KeypadPage} from './keypad/keypad'; +import {AddUserPage} from './add-user/add-user'; + +class App { + constructor() { + this.store = this.createStore(); + this.pages = { + 'contacts': new ContactPage(this.store), + 'keypad': new KeypadPage(this.store), + 'addUser': new AddUserPage(this.store), + 'footer': new FooterNavigationBar() + } + this.pages.contacts.setStateContact(); + this.render(); + this.pages.contacts.applyListenerForContactPage(); + this.applyListenerForNavigation(); + } + + createStore() { + let state; + + return { + getState() { + return state; + }, + setState(newState) { + state = newState; + } + } + } + + reducer(action) { + const currentState = this.store.getState(); + const mainWraper = document.getElementById('main-wraper'); + const switchBetweenPages = () => { + mainWraper.firstElementChild.outerHTML = currentState.activePage; + }; + + if(action.type === 'MOVE_TO_KEYPAD_PAGE') { + this.pages.keypad.setStateKeypad(); + switchBetweenPages(); + this.pages.keypad.applyListenerForKeypadPage(); + return; + } + + if(action.type === 'MOVE_TO_CONTACT_PAGE') { + this.pages.contacts.setStateContact(); + switchBetweenPages(); + this.pages.contacts.applyListenerForContactPage(); + return; + } + + if(action.type === 'MOVE_TO_ADD_USER_PAGE') { + this.pages.addUser.setStateContact(); + switchBetweenPages(); + this.pages.addUser.applyListenersForAddUserPage(); + return; + } + + } + + render() { + const currentState = this.store.getState(); + const FOOTER = this.pages.footer.render(); + + const appTemplate = /*html*/` +
+ ${currentState.activePage} + ${FOOTER} +
+ `; + + const mountMode = document.getElementById('mountMode'); + mountMode.innerHTML = appTemplate; + } + + applyListenerForNavigation() { + + const _MOVE_TO_KEYPAD_PAGE = { + type: 'MOVE_TO_KEYPAD_PAGE' + } + + const _MOVE_TO_CONTACT_PAGE = { + type: 'MOVE_TO_CONTACT_PAGE' + } + + const _MOVE_TO_ADD_USER_PAGE = { + type: 'MOVE_TO_ADD_USER_PAGE' + } + + const wraperForFooter = document.getElementById('wraper-for-footer'); + wraperForFooter.addEventListener('click', (e) => { + const currentState = this.store.getState(); + + const BUTTON_ID = e.target.id; + const BUTTON_ID_FROM_SVG = e.target.parentElement.id; + const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id; + + if( + BUTTON_ID === 'to-keypad-page' + || BUTTON_ID_FROM_SVG === 'to-keypad-page' + || BUTTON_ID_FROM_PATH === 'to-keypad-page' + ) { + + if(currentState.stateName !== 'KEYPAD') { + this.pages.keypad.setStateKeypad(); + return this.reducer(_MOVE_TO_KEYPAD_PAGE); + } + return; + } + + if( + BUTTON_ID === 'to-contact-page' + || BUTTON_ID_FROM_SVG === 'to-contact-page' + || BUTTON_ID_FROM_PATH === 'to-contact-page' + ) { + + if(currentState.stateName !== 'CONTACT') { + this.pages.contacts.setStateContact(); + return this.reducer(_MOVE_TO_CONTACT_PAGE); + } + return; + } + + if( + BUTTON_ID === 'to-addUser-page' + || BUTTON_ID_FROM_SVG === 'to-addUser-page' + || BUTTON_ID_FROM_PATH === 'to-addUser-page' + ) { + + if(currentState.stateName !== 'ADD USER') { + this.pages.addUser.setStateContact(); + return this.reducer(_MOVE_TO_ADD_USER_PAGE); + } + return; + } + }) + } +} + +/* ================== FOOTER START================== */ + +class FooterNavigationBar { + constructor() { + this.icons = { + contactIcon: { + id: 'to-contact-page', + class: 'far fa-address-book', + }, + keypadIcon: { + id: 'to-keypad-page', + class: 'fas fa-tty', + }, + addUserIcon: { + id: 'to-addUser-page', + class: 'fas fa-user-plus', + } + } + } + + render() { + const navigationBar = /*html*/` +
+ +
+ `; + + return navigationBar; + } + + createIcon(iconPattern) { + const ID = iconPattern.id; + const CLASS = iconPattern.class; + + const icon = /*html*/` +
+ +
+ `; + + return icon; + } + +} + +/* ================== FOOTER END================== */ + +const APPLICATION = new App(); \ No newline at end of file diff --git a/phone-book/src/keypad/keypad.js b/phone-book/src/keypad/keypad.js new file mode 100644 index 0000000..d15c058 --- /dev/null +++ b/phone-book/src/keypad/keypad.js @@ -0,0 +1,446 @@ +import {MOBILE_OPERATORS_IDENTIFICATORS} from '../components/mobile-operators-identifiers'; + +/* ================== KEYPAD START================== */ + +class KeypadPage { + constructor(store) { + this.setStateKeypad = () => { + const {setState} = store; + const initializeState = { + stateName: 'KEYPAD', + activePage: this.render(), + }; + setState(initializeState); + } + + this.callMode = new CallMode(); + } + + render() { + const buttons = { + ONE: '1', + TWO: '2', + THREE: '3', + FOUR: '4', + FIVE: '5', + SIX: '6', + SEVEN: '7', + EIGHT: '8', + NINE: '9', + ZERO: '0', + ASTERISK: '*', + HASH: '#' + } + + return /*html*/` +
+ +
+
+
+ + +
+
+ +
+
+
+ +
+ +
+
+ ${this.createButton(buttons.ONE)} + ${this.createButton(buttons.TWO)} + ${this.createButton(buttons.THREE)} +
+
+ ${this.createButton(buttons.FOUR)} + ${this.createButton(buttons.FIVE)} + ${this.createButton(buttons.SIX)} +
+
+ ${this.createButton(buttons.SEVEN)} + ${this.createButton(buttons.EIGHT)} + ${this.createButton(buttons.NINE)} +
+
+ ${this.createButton(buttons.ASTERISK)} + ${this.createButton(buttons.ZERO)} + ${this.createButton(buttons.HASH)} +
+
+ +
+
+
+ + +
+ +
+ `; + } + + createButton(value) { + const button = /*html*/` +
${value}
+ `; + + return button; + } + + applyListenerForKeypadPage() { + + /* ADD NUMBER */ + const keypadButtons = document.getElementById('wraper-for-buttons'); + const fieldForNumber = document.getElementById('number'); + const fieldForOperator = document.getElementById('operator'); + + const toFormateNumberFieldForAdding = () => { + const numbersFromField = fieldForNumber.textContent.replace(/\D/gm, ''); + let finalConstructions = null; + + if(numbersFromField.length === 1) { + finalConstructions = numbersFromField.replace(/(.{1})/g, '($1'); + fieldForNumber.textContent = finalConstructions; + return; + } + + if(numbersFromField.length === 3) { + finalConstructions = numbersFromField.replace(/(.{3})/g, '($1)'); + fieldForNumber.textContent = finalConstructions; + return; + } + + if(numbersFromField.length === 4) { + finalConstructions = numbersFromField.replace(/(.{3})(.{1})/g, '($1) $2'); + fieldForNumber.textContent = finalConstructions; + return; + } + + if(numbersFromField.length === 7) { + finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{1})/g, '($1) $2-$3'); + fieldForNumber.textContent = finalConstructions; + return; + } + + if(numbersFromField.length === 9) { + finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{2})(.{1})/g, '($1) $2-$3-$4'); + fieldForNumber.textContent = finalConstructions; + return; + } + + }; + + keypadButtons.addEventListener('click', (e) => { + const TARGET_CLASS_NAME = e.target.className; + + if(TARGET_CLASS_NAME === 'number-btn') { + const BUTTON_VALUE = e.target.textContent; + fieldForNumber.textContent += BUTTON_VALUE; + + const MATCH_NUMBERS = fieldForNumber.textContent.match(/\d+/gm); + const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0]; + const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length; + + if(LENGTH_OF_FIRST_NUMBERS === 3) { + fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS) + } + + toFormateNumberFieldForAdding(); + } + }); + + /* REMOVE NUMBER */ + const deleteButton = document.getElementById('delete'); + + deleteButton.addEventListener('click', (e) => { + const BUTTON_ID = e.target.id; + const BUTTON_ID_FROM_SVG = e.target.parentElement.id; + const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id; + + if( + BUTTON_ID === 'delete' + || BUTTON_ID_FROM_SVG === 'delete' + || BUTTON_ID_FROM_PATH === 'delete' + ) { + const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length; + const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1; + const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE) + fieldForNumber.textContent = strWithDeletedOneNumber; + + if(LENGTH_OF_NUMBERS <= 3) { + fieldForOperator.textContent = ''; + } + + return; + } + }); + + /* TO CALL BUTTON */ + const mainWraper = document.getElementById('main-wraper'); + + const toCallButton = document.getElementById('call-btn'); + toCallButton.addEventListener('click', () => { + const ERROR_BLOCK = document.getElementById('error-block'); + + if(fieldForNumber.textContent.length < 3) { + ERROR_BLOCK.textContent = `ERROR you've typed incorrect number`; + setTimeout(() => { + ERROR_BLOCK.textContent = ''; + }, 3000); + return; + } + + const NUMBER_FOR_CALL_MODE = this.callMode.getNumber(); + const OPERATOR_FOR_CALL_MODE = this.callMode.getOperator(); + + mainWraper.classList.add('call-mode'); + mainWraper.innerHTML = this.callMode.render(NUMBER_FOR_CALL_MODE, OPERATOR_FOR_CALL_MODE); + this.callMode.applyListenerForCallMode(); + }) + + /* WRITING NUMBER BY KEYBOARD */ + + const keyCodes = { + ONE: 49, + TWO: 50, + THREE: 51, + FOUR: 52, + FIVE: 53, + SIX: 54, + SEVEN: 55, + EIGHT: 56, + NINE: 57, + ZERO: 48, + ASTERISK: 42, + HASH: 35, + DELETE: 8 + }; + + const SINGLE_TAPS = (e) => { + + if(e.keyCode === keyCodes.ONE) { + const ONE = '1'; + fieldForNumber.textContent += ONE; + } + if(e.keyCode === keyCodes.TWO) { + const TWO = '2'; + fieldForNumber.textContent += TWO; + } + if(e.keyCode === keyCodes.THREE) { + const THREE = '3'; + fieldForNumber.textContent += THREE; + } + if(e.keyCode === keyCodes.FOUR) { + const FOUR = '4'; + fieldForNumber.textContent += FOUR; + } + if(e.keyCode === keyCodes.FIVE) { + const FIVE = '5'; + fieldForNumber.textContent += FIVE; + } + if(e.keyCode === keyCodes.SIX) { + const SIX = '6'; + fieldForNumber.textContent += SIX; + } + if(e.keyCode === keyCodes.SEVEN) { + const SEVEN = '7'; + fieldForNumber.textContent += SEVEN; + } + if(e.keyCode === keyCodes.EIGHT) { + const EIGHT = '8'; + fieldForNumber.textContent += EIGHT; + } + if(e.keyCode === keyCodes.NINE) { + const NINE = '9'; + fieldForNumber.textContent += NINE; + } + if(e.keyCode === keyCodes.ZERO) { + const ZERO = '0'; + fieldForNumber.textContent += ZERO; + } + if(e.keyCode === keyCodes.HASH) { + const HASH = '#'; + fieldForNumber.textContent += HASH; + } + if(e.keyCode === keyCodes.ASTERISK) { + const ASTERISK = '*'; + fieldForNumber.textContent += ASTERISK; + } + + + + /* IDENTIFICATION FUNCTIONAL */ + const MATCH_NUMBERS = fieldForNumber.textContent.match(/\d+/gm); + const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0]; + const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length; + + if(LENGTH_OF_FIRST_NUMBERS === 3) { + fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS) + } + + toFormateNumberFieldForAdding(); + + }; + + const DELETE_FUNCTIONAL = (e) => { + const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length; + + if(e.keyCode === keyCodes.DELETE) { + const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1; + const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE) + fieldForNumber.textContent = strWithDeletedOneNumber; + + if(LENGTH_OF_NUMBERS <= 3) { + fieldForOperator.textContent = ''; + } + return; + } + } + + window.addEventListener('keypress', SINGLE_TAPS); + window.addEventListener('keydown', DELETE_FUNCTIONAL); + + } + + indentifyMobileOperator(firstThreeNumbers) { + let operator; + + MOBILE_OPERATORS_IDENTIFICATORS.kuivstar.forEach(identicationNumber => { + if(identicationNumber === firstThreeNumbers) { + operator = 'Kuivstar' + } + }) + + MOBILE_OPERATORS_IDENTIFICATORS.life.forEach(identicationNumber => { + if(identicationNumber === firstThreeNumbers) { + operator = 'Life' + } + }) + + MOBILE_OPERATORS_IDENTIFICATORS.vodafone.forEach(identicationNumber => { + if(identicationNumber === firstThreeNumbers) { + operator = 'Vodafone' + } + }) + + return operator; + } +} + +/* ================== KEYPAD END================== */ + +/* ================== CALL MODE START================== */ +class CallMode{ + constructor() {} + + render(number, operator) { + return /*html*/` +
+
+ +
+ ${number} + ${operator} +
+ +
+ + + + + +
+ +
+ +
+ +
+ +
+ +
+
+ +
+ mute +
+ +
+
+ +
+ keypad +
+ +
+
+ +
+ volume +
+ +
+ +
+
+
+ +
+ add +
+ +
+
+ +
+ video +
+ +
+
+ +
+ contacts +
+
+ +
+ +
+
+ +
+
+ +
+
+ `; + } + + getNumber() { + const phoneNumber = document.getElementById('number'); + return phoneNumber.textContent; + } + + getOperator() { + const phoneOperator = document.getElementById('operator'); + return phoneOperator.textContent; + } + + applyListenerForCallMode() { + + } + + setSavedKeypadPage(page) { + this.savedKeypadPage = page; + } +} + +/* ================== CALL MODE END================== */ + +export {KeypadPage}; \ No newline at end of file diff --git a/phone-book/src/url/url.js b/phone-book/src/url/url.js new file mode 100644 index 0000000..129a4cd --- /dev/null +++ b/phone-book/src/url/url.js @@ -0,0 +1,33 @@ +class Url{ + constructor() { + this.url = 'http://easycode-js.herokuapp.com/myba/users'; + } + + getUsersFromServer() { + return (async () => { + const data = await fetch(this.url); + return this.users = await data.json(); + })(); + } + + obtainUsers() { + this.getUsersFromServer(); + return this.users; + } + + postUser(user) { + const xhr = new XMLHttpRequest(); + xhr.open('POST', this.url, true); + xhr.setRequestHeader('Content-type', 'application/json'); + xhr.send(JSON.stringify(user)); + } + + deleteUserById(id) { + const xhr = new XMLHttpRequest(); + xhr.open('DELETE', `${this.url}/${id}`, true); + xhr.setRequestHeader('Content-type', 'application/json'); + xhr.send(); + } +} + +export {Url}; \ No newline at end of file diff --git a/phone-book/src/user-page/user-page.js b/phone-book/src/user-page/user-page.js new file mode 100644 index 0000000..45d00be --- /dev/null +++ b/phone-book/src/user-page/user-page.js @@ -0,0 +1,57 @@ +class UserPage{ + constructor(store) { + + } + + render() { + return /*html*/` +
+ +
+
+ User page +
+
+ +
+ +
+ avatar +
+ +
+

Full Name:

+

???????????

+
+
+

Email:

+

??????@??????.???

+
+
+

Phone number:

+

(???) ???-??-??

+
+
+

Birth date:

+

????/??/??

+
+
+

Address:

+

????? ??????

+
+
+

Gender:

+

?????

+
+ +
+ + +
+ +
+ +
+ `; + } +} \ No newline at end of file diff --git a/phone-book/style/add-user.css b/phone-book/style/add-user.css new file mode 100644 index 0000000..dbe02f8 --- /dev/null +++ b/phone-book/style/add-user.css @@ -0,0 +1,8 @@ +.add-user-header{ + font-size: 26px; + border-bottom: 2px solid black; +} + +.add-user-block{ + padding: 10px 0; +} \ No newline at end of file diff --git a/phone-book/style/keypad.css b/phone-book/style/keypad.css new file mode 100644 index 0000000..8345305 --- /dev/null +++ b/phone-book/style/keypad.css @@ -0,0 +1,261 @@ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; +} + +.number-field{ + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: center; + padding: 10px 0; +} + +#phone-number{ + display: flex; + justify-content: space-between; + border: 1px solid gray; + border-radius: 3rem; + min-width: 200px; + width: 420px; + height: 35px; + padding: 0 10px; +} + +.keypad-header-wraper{ + margin: 10px 20px; +} + +.for-sort{ + cursor: pointer; +} + +.keypad-block{ + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 470px; +} + +.borders{ + border-top: 3px solid black; +} + +.number-btn{ + height: 50px; + width: 50px; + border: 2px solid black; + border-radius: 50%; + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + transition: .2s ease 0s; + margin: 10px 40px; + background-color: transparent; +} + +.number-btn:hover{ + background-color: lightgray; +} + +.call:hover{ + background-color: lawngreen; + opacity: 0.8; +} + +.delete-number{ + margin-left: 10px; + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: center; + align-items: center; + border: 2px solid black; + border-radius: 0.2rem; + height: 32px; + width: 45px; + font-size: 20px; + cursor: pointer; + transition: 0.2s ease 0s; +} + +.delete-number:hover{ + background-color: firebrick; + color: white; + opacity: 0.8; +} + +#error-block{ + font-size: 12px; + color: firebrick; +} + +#number{ + display: flex; + align-items: center; + font-size: 120%; +} + +#operator{ + display: flex; + align-items: center; +} + +/*PNONE MODE*/ + +@keyframes load-animation{ + 0%{ + transform: translateY(0); + } + 50%{ + transform: translateY(-10px); + } + 100%{ + transform: translateY(0); + } +} + +.call-mode{ + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + background-color: black; + opacity: 0.9; +} + +.call-target{ + color: white; + border-bottom: 2px solid white; + margin-bottom: 20px; +} + +.phone-code{ + color: white; + margin-left: 10px; +} + +.load-point{ + font-size: 12px; + color: white; + margin: 10px; +} + +#load-point-1{ + animation-name: load-animation; + animation-duration: 1.6s; + animation-timing-function: ease; + animation-iteration-count: infinite; + animation-delay: 0s; +} + +#load-point-2{ + animation-name: load-animation; + animation-duration: 1.6s; + animation-timing-function: ease; + animation-iteration-count: infinite; + animation-delay: .5s; +} + +#load-point-3{ + animation-name: load-animation; + animation-duration: 1.6s; + animation-timing-function: ease; + animation-iteration-count: infinite; + animation-delay: 1s; +} + +#load-point-4{ + animation-name: load-animation; + animation-duration: 1.6s; + animation-timing-function: ease; + animation-iteration-count: infinite; + animation-delay: 1.5s; +} + +#load-point-5{ + animation-name: load-animation; + animation-duration: 1.6s; + animation-timing-function: ease; + animation-iteration-count: infinite; + animation-delay: 2s; +} + +.call-mode-keypad-block{ + margin-top: 50px; + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.call-mode-btn{ + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: center; + align-items: center; + height: 50px; + width: 50px; + border: 2px solid white; + border-radius: 50%; + color: white; + font-size: 120%; + cursor: pointer; + transition: .2s ease 0s; + background-color: transparent; +} + +.wraper-for-call-mode-btn{ + text-align: center; + margin: 10px 40px; +} + +.wraper-for-call-mode-buttons{ + margin-top: 30px; +} + +.call-btn-description{ + color: white; + font-size: 10px; +} + +.call-mode-btn:hover{ + background-color: white; + color: black; +} + +.call-off:hover{ + border-color: red; + background-color: red; + color: white; +} + +.call-mode-btn-active{ + background-color: white; + color: black; +} \ No newline at end of file diff --git a/phone-book/style/main.css b/phone-book/style/main.css new file mode 100644 index 0000000..4c24252 --- /dev/null +++ b/phone-book/style/main.css @@ -0,0 +1,100 @@ +*{ + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 0; +} + +#main-wraper{ + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.app-block{ + margin: 40px auto; + width: 600px; + min-height: 600px; + border: 3px solid black; + border-radius: 2rem; +} + +#search{ + border-radius: 3rem; + width: 500px; + min-width: 200px; +} + +.search-form{ + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: center; + padding: 10px 0; + border-bottom: 3px solid black; +} + +.user{ + cursor: pointer; +} + +.contact-list{ + max-height: 470px; + overflow: hidden; + overflow-y: auto; +} + +footer{ + border-top: 3px solid black; +} + +.navigation-panel{ + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + padding: 10px 0; + justify-content: space-around; +} + +.navigation-button{ + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: center; + align-items: center; + border: 2px solid black; + border-radius: 50%; + height: 50px; + width: 50px; + transition: .3s ease 0s; +} + +.icon{ + color: black; + font-size: 24px; + transition: .3s ease 0s; +} + +.active{ + border-color: gray; + color: gray; + cursor: default; +} + +.navigation-button:hover{ + border-color: gray; +} + +.navigation-button:hover > .icon{ + color: gray; +} + +.contact-list-titles, .navigation-button{ + cursor: pointer; +} \ No newline at end of file diff --git a/phone-book/style/user-page.css b/phone-book/style/user-page.css new file mode 100644 index 0000000..83dcfc2 --- /dev/null +++ b/phone-book/style/user-page.css @@ -0,0 +1,19 @@ +.user-header{ + font-size: 26px; + border-bottom: 2px solid black; +} + +#user-page-avatar{ + border: 2px solid black; + border-radius: 50%; + width: 200px; + height: 200px; +} + +.user-page-key{ + margin-left: 50px; +} + +.user-page-value{ + margin-right: 50px; +} \ No newline at end of file diff --git a/phone-book/webpack.config.js b/phone-book/webpack.config.js new file mode 100644 index 0000000..ec4a8eb --- /dev/null +++ b/phone-book/webpack.config.js @@ -0,0 +1,15 @@ +const path = require('path'); + +module.exports = { + entry: './src/index.js', + output: { + path: path.join(__dirname, 'build'), + filename: 'bundle.js', + publicPath: '/build/' + }, + module: { + rules: [ + { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" } + ] + } +} \ No newline at end of file From 91b66ce28473a663ff61a39bea443df69ef2e56e Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:09:35 +0300 Subject: [PATCH 02/14] edit-user-page --- .../src/edit-user-page/edit-user-page.js | 275 ++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 phone-book/src/edit-user-page/edit-user-page.js diff --git a/phone-book/src/edit-user-page/edit-user-page.js b/phone-book/src/edit-user-page/edit-user-page.js new file mode 100644 index 0000000..1cc2085 --- /dev/null +++ b/phone-book/src/edit-user-page/edit-user-page.js @@ -0,0 +1,275 @@ +import {Url} from '../url/url'; + +class EditUserPage { + constructor(store, accountName) { + this.setStateEditUser = () => { + const {setState} = store; + const initializeState = { + stateName: 'EDIT USER', + }; + setState(initializeState); + } + + this.url = new Url(accountName); + } + + render(user) { + this.user = user; + + return /*html*/` +
+ +
+
+ Edit user ${user.fullName} +
+
+ +
+
+ +
+ + +
+ +
+ + +
+ +
+ + + Length of your phone number should be more than 9 +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + ex: https://cloud-drive/photo123456. +
+ +
+ +
+ +
+
+ +
+ `; + } + + applyListenersForEditUserPage() { + + const editUserForm = document.querySelector('form'); + + const handlerForInputs = (e) => { + if(e.target.name === 'fullName') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('wrong') + e.target.classList.remove('correct') + return; + } + + if(this.isValidFullName(VALUE)) { + e.target.classList.add('correct') + e.target.classList.remove('wrong') + } else { + e.target.classList.add('wrong') + e.target.classList.remove('correct') + } + + } + + if(e.target.name === 'email') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('wrong') + e.target.classList.remove('correct') + return; + } + + if(this.isValidEmail(VALUE)) { + e.target.classList.add('correct') + e.target.classList.remove('wrong') + } else { + e.target.classList.add('wrong') + e.target.classList.remove('correct') + } + } + + if(e.target.name === 'phone') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('wrong') + e.target.classList.remove('correct') + return; + } + + if(VALUE.length > 9) { + e.target.classList.add('correct') + e.target.classList.remove('wrong') + } else { + e.target.classList.add('wrong') + e.target.classList.remove('correct') + } + } + + if(e.target.name === 'birthdate') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('correct') + return; + } + + if(VALUE.length > 9) { + e.target.classList.add('correct') + } + } + + if(e.target.name === 'address') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('correct') + return; + } + + if(VALUE.length > 0) { + e.target.classList.add('correct') + } + } + + if(e.target.name === "avatarUrl") { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('wrong') + e.target.classList.remove('correct') + return; + } + + if(this.isValidURL(VALUE)) { + e.target.classList.add('correct') + e.target.classList.remove('wrong') + } else { + e.target.classList.add('wrong') + e.target.classList.remove('correct') + } + } + + }; + + editUserForm.addEventListener('input', handlerForInputs); + const inputs = [...editUserForm.elements] + .filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT'); + + const handlerForSubmit = (e) => { + e.preventDefault(); + + const infoToEdit = inputs.reduce((editedUser, input) => { + if(input.classList.contains('wrong')) { + alert(`${input.name} is incorrect!`); + return; + }; + if(input.value.length !== 0 + && input.name !== 'phone' + && input.name !== 'gender' + && input.name !== 'fullName' + ) { + editedUser[input.name] = input.value; + } + if(input.value.length !== 0 && input.name === 'phone') { + editedUser[input.name] = input.value.replace(/(.{3})(.{3})(.{2})/g, '($1) $2-$3-'); + } + if(input.name === 'gender') { + input.value === "Male" + ? editedUser[input.name] = "M" + : editedUser[input.name] = "F" + } + if(input.value.length !== 0 && input.name === 'fullName') { + const formatedFullName = input.value.split(' ').reduce((output, word, index) => { + const splitedWord = word.toLowerCase().split(''); + const firstLetter = splitedWord[0].toUpperCase(); + splitedWord[0] = firstLetter; + output += splitedWord.join(''); + + if(index === 0) { + output += ' '; + } + + return output; + }, ''); + + editedUser[input.name] = formatedFullName; + } + return editedUser; + }, {}); + + if(infoToEdit) { + this.url.editUser(infoToEdit, this.user._id); + + inputs.forEach(input => { + if(input.tagName !== "SELECT") { + input.value = ""; + input.classList.remove('correct'); + } + }); + } else { + alert('Something is incorrect!'); + } + + } + + editUserForm.addEventListener('submit', handlerForSubmit); + } + + isValidFullName(value) { + const splitedValue = value.split(' '); + + return splitedValue.length === 2 && splitedValue[0].length > 0 && splitedValue[1].length > 0; + } + + isValidEmail(value) { + const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(String(value).toLowerCase()); + } + + isValidURL(value) { + const re = new RegExp('^(https?:\\/\\/)?'+ // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|'+ // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string + '(\\#[-a-z\\d_]*)?$','i'); // fragment locator + return re.test(String(value).toLowerCase()); + } + +} + +export {EditUserPage}; \ No newline at end of file From faef93a9101737292bca980c48bf4dde5131e1e2 Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:10:23 +0300 Subject: [PATCH 03/14] authorization-page --- .../authorization-page/authorization-page.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 phone-book/src/authorization-page/authorization-page.js diff --git a/phone-book/src/authorization-page/authorization-page.js b/phone-book/src/authorization-page/authorization-page.js new file mode 100644 index 0000000..e0e933b --- /dev/null +++ b/phone-book/src/authorization-page/authorization-page.js @@ -0,0 +1,26 @@ +class AuthorizationPage{ + constructor() { + this.setStateAuthorization = () => { + const {setState} = store; + const initializeState = { + stateName: 'AUTHORIZATION', + activePage: this.render(), + }; + setState(initializeState); + } + } + + render() { + return /*html*/` +
+

Authorization

+
+ + +
+
+ `; + } +} + +export {AuthorizationPage}; \ No newline at end of file From 09551478fde4f2dcc963eb84d6280f7a321de9bd Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:11:08 +0300 Subject: [PATCH 04/14] webpack config --- phone-book/webpack.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/phone-book/webpack.config.js b/phone-book/webpack.config.js index ec4a8eb..90bc2f2 100644 --- a/phone-book/webpack.config.js +++ b/phone-book/webpack.config.js @@ -7,6 +7,7 @@ module.exports = { filename: 'bundle.js', publicPath: '/build/' }, + watch: true, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" } From 516113245b190234f91bd5f904b75a333f20859d Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:11:43 +0300 Subject: [PATCH 05/14] styles --- phone-book/style/add-user.css | 18 ++++++++++++++++++ phone-book/style/main.css | 30 ++++++++++++++++++++++++++++++ phone-book/style/user-page.css | 4 ++++ 3 files changed, 52 insertions(+) diff --git a/phone-book/style/add-user.css b/phone-book/style/add-user.css index dbe02f8..8bdf126 100644 --- a/phone-book/style/add-user.css +++ b/phone-book/style/add-user.css @@ -5,4 +5,22 @@ .add-user-block{ padding: 10px 0; +} + +.correct{ + background-color: rgba(10, 194, 56, 0.3) !important; +} + +.wrong{ + background-color: rgba(194, 10, 10, 0.3) !important; +} + +.required{ + color: brown; +} + +.respond-after-delete{ + color: brown; + text-align: center; + margin-top: 20px; } \ No newline at end of file diff --git a/phone-book/style/main.css b/phone-book/style/main.css index 4c24252..00eadcb 100644 --- a/phone-book/style/main.css +++ b/phone-book/style/main.css @@ -5,6 +5,36 @@ margin: 0; } +.authorization-block{ + margin-top: 100px; + margin-left: auto; + margin-right: auto; + width: 600px; + min-height: 200px; + border: 3px solid black; + border-radius: 2rem; +} + +.au-title{ + text-align: center; + border-bottom: 2px solid black; +} + +.wraper-for-authorization-inputs{ + display: flex; + flex-direction: column; + align-items: center; +} + +.au-input{ + margin-top: 15px; + margin-bottom: 15px; + border: 1px solid black; + border-radius: 2rem; + padding: 5px 5px 5px 15px; + width: 400px; +} + #main-wraper{ display: flex; flex-direction: column; diff --git a/phone-book/style/user-page.css b/phone-book/style/user-page.css index 83dcfc2..23a37c9 100644 --- a/phone-book/style/user-page.css +++ b/phone-book/style/user-page.css @@ -16,4 +16,8 @@ .user-page-value{ margin-right: 50px; +} + +#usp-wraper-for-btns{ + margin-bottom: 20px; } \ No newline at end of file From 935afc5d7750a1f6911a02c8fd1c5209c5af31b0 Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:12:31 +0300 Subject: [PATCH 06/14] URL (requests to server side) --- phone-book/src/url/url.js | 40 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/phone-book/src/url/url.js b/phone-book/src/url/url.js index 129a4cd..ea5d53a 100644 --- a/phone-book/src/url/url.js +++ b/phone-book/src/url/url.js @@ -1,32 +1,36 @@ class Url{ - constructor() { - this.url = 'http://easycode-js.herokuapp.com/myba/users'; + constructor(accountName) { + this.url = `https://easycode-js.herokuapp.com/${accountName}/users`; } getUsersFromServer() { - return (async () => { - const data = await fetch(this.url); - return this.users = await data.json(); - })(); + return fetch(this.url) } - obtainUsers() { - this.getUsersFromServer(); - return this.users; + postUser(user) { + fetch(this.url, { + method: 'POST', + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify(user) + }) } - postUser(user) { - const xhr = new XMLHttpRequest(); - xhr.open('POST', this.url, true); - xhr.setRequestHeader('Content-type', 'application/json'); - xhr.send(JSON.stringify(user)); + editUser(infoToEdit, id) { + fetch(this.url + '/' + id, { + method: 'PATCH', + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify(infoToEdit) + }) } deleteUserById(id) { - const xhr = new XMLHttpRequest(); - xhr.open('DELETE', `${this.url}/${id}`, true); - xhr.setRequestHeader('Content-type', 'application/json'); - xhr.send(); + fetch(this.url + '/' + id, { + method: 'DELETE' + }) } } From ad4a8573dad81a40938be1b465ede654516d09ff Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:12:53 +0300 Subject: [PATCH 07/14] keypad-page --- phone-book/src/keypad/keypad.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phone-book/src/keypad/keypad.js b/phone-book/src/keypad/keypad.js index d15c058..3e7ee6b 100644 --- a/phone-book/src/keypad/keypad.js +++ b/phone-book/src/keypad/keypad.js @@ -3,7 +3,7 @@ import {MOBILE_OPERATORS_IDENTIFICATORS} from '../components/mobile-operators-id /* ================== KEYPAD START================== */ class KeypadPage { - constructor(store) { + constructor(store, accountName) { this.setStateKeypad = () => { const {setState} = store; const initializeState = { From 99fab096df49f509df46b660d7391596e6af9776 Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:13:13 +0300 Subject: [PATCH 08/14] user-page --- phone-book/src/user-page/user-page.js | 67 ++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/phone-book/src/user-page/user-page.js b/phone-book/src/user-page/user-page.js index 45d00be..238b612 100644 --- a/phone-book/src/user-page/user-page.js +++ b/phone-book/src/user-page/user-page.js @@ -1,9 +1,23 @@ +import {EditUserPage} from '../edit-user-page/edit-user-page'; +import {Url} from '../url/url'; + class UserPage{ - constructor(store) { + constructor(store, accountName) { + this.setStateUserPage = () => { + const {setState} = store; + const initializeState = { + stateName: 'USER_PAGE', + }; + setState(initializeState); + } + this.editUserPage = new EditUserPage(store, accountName); + this.url = new Url(accountName); } - render() { + render(user) { + this.user = user; + return /*html*/`
@@ -13,38 +27,38 @@ class UserPage{
-
+
- avatar + avatar

Full Name:

-

???????????

+

${user.fullName}

Email:

-

??????@??????.???

+

${user.email}

Phone number:

-

(???) ???-??-??

+

${user.phone}

Birth date:

-

????/??/??

+

${user.birthdate ? user.birthdate.slice(0, 10) : '__________'}

Address:

-

????? ??????

+

${user.address ? user.address : '__________'}

Gender:

-

?????

+

${user.gender === "M" ? 'Male' : 'Female'}

-
+
@@ -54,4 +68,33 @@ class UserPage{
`; } -} \ No newline at end of file + + applyListenersForUserPage() { + const wraperForButtons = document.getElementById('usp-wraper-for-btns'); + + const handlerForButtons = (e) => { + if(e.target.textContent.trim() === 'Edit') { + this.editUserPage.setStateEditUser(); + const EDIT_USER_PAGE = this.editUserPage.render(this.user); + + const MAIN_WRAPER = document.getElementById('main-wraper'); + MAIN_WRAPER.firstElementChild.outerHTML = EDIT_USER_PAGE; + this.editUserPage.applyListenersForEditUserPage() + } + + if(e.target.textContent.trim() === 'Delete') { + const requestForDelete = confirm('Are you sure?'); + if(requestForDelete) { + this.url.deleteUserById(this.user._id); + + const USER_PAGE = document.getElementById('user-info'); + USER_PAGE.innerHTML = /*html*/`

This user was deleted

`; + } + } + }; + + wraperForButtons.addEventListener('click', handlerForButtons) + } +} + +export {UserPage}; \ No newline at end of file From f1747a94bb728a1cca4bfc94c914998705909a7f Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:13:57 +0300 Subject: [PATCH 09/14] entry point(root of app) --- phone-book/src/index.js | 67 +++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/phone-book/src/index.js b/phone-book/src/index.js index 9650524..7d8a1a0 100644 --- a/phone-book/src/index.js +++ b/phone-book/src/index.js @@ -1,4 +1,4 @@ - +import {AuthorizationPage} from './authorization-page/authorization-page'; import {ContactPage} from './contact/contact'; import {KeypadPage} from './keypad/keypad'; import {AddUserPage} from './add-user/add-user'; @@ -6,16 +6,8 @@ import {AddUserPage} from './add-user/add-user'; class App { constructor() { this.store = this.createStore(); - this.pages = { - 'contacts': new ContactPage(this.store), - 'keypad': new KeypadPage(this.store), - 'addUser': new AddUserPage(this.store), - 'footer': new FooterNavigationBar() - } - this.pages.contacts.setStateContact(); - this.render(); - this.pages.contacts.applyListenerForContactPage(); - this.applyListenerForNavigation(); + this.authorizationPage = new AuthorizationPage(); + this.renderAuthorizationPage(); } createStore() { @@ -27,7 +19,7 @@ class App { }, setState(newState) { state = newState; - } + } } } @@ -48,6 +40,7 @@ class App { if(action.type === 'MOVE_TO_CONTACT_PAGE') { this.pages.contacts.setStateContact(); switchBetweenPages(); + this.pages.contacts.renderUsers(); this.pages.contacts.applyListenerForContactPage(); return; } @@ -61,6 +54,54 @@ class App { } + renderAuthorizationPage() { + const authorizationPage = this.authorizationPage.render(); + const mountMode = document.getElementById('mountMode'); + mountMode.innerHTML = authorizationPage; + this.applyListenerForAuthorizationPage(); + } + + applyListenerForAuthorizationPage() { + const input = document.querySelector('.au-input'); + const logInButton = document.getElementById('log-in'); + const switchBetweenPages = () => { + this.accountName = input.value; + + this.pages = { + 'contacts': new ContactPage(this.store, this.accountName), + 'keypad': new KeypadPage(this.store, this.accountName), + 'addUser': new AddUserPage(this.store, this.accountName), + 'footer': new FooterNavigationBar() + } + + this.pages.contacts.setStateContact(); + this.render(); + this.pages.contacts.applyListenerForContactPage(); + this.applyListenerForNavigation(); + } + + const handlerForLogInBtn = () => { + if(input.value.length > 3) { + switchBetweenPages(); + } else { + alert('So short login'); + } + }; + + const handlerForLogInInput = (e) => { + if(e.keyCode === 13) { + if(input.value.length > 3) { + switchBetweenPages(); + } else { + alert('So short login'); + } + } + }; + + logInButton.addEventListener('click', handlerForLogInBtn); + input.addEventListener('keydown', handlerForLogInInput); + } + render() { const currentState = this.store.getState(); const FOOTER = this.pages.footer.render(); @@ -74,6 +115,8 @@ class App { const mountMode = document.getElementById('mountMode'); mountMode.innerHTML = appTemplate; + + this.pages.contacts.renderUsers(); } applyListenerForNavigation() { From ae3b5d0c04282719f99f22ceb5be02aaaa07dba9 Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:14:26 +0300 Subject: [PATCH 10/14] contact-page --- phone-book/src/contact/contact.js | 53 +++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/phone-book/src/contact/contact.js b/phone-book/src/contact/contact.js index 81c689c..ef29ca5 100644 --- a/phone-book/src/contact/contact.js +++ b/phone-book/src/contact/contact.js @@ -1,9 +1,10 @@ -import {users} from '../components/users'; +import {Url} from '../url/url'; +import {UserPage} from '../user-page/user-page'; /* ================== CONTACT START================== */ class ContactPage { - constructor(store) { + constructor(store, accountName) { this.setStateContact = () => { const {setState} = store; const initializeState = { @@ -13,6 +14,8 @@ class ContactPage { setState(initializeState); } + this.url = new Url(accountName); + this.userPage = new UserPage(store, accountName); } render() { @@ -40,7 +43,7 @@ class ContactPage { - ${this.contactListComponent(users)} + @@ -57,9 +60,10 @@ class ContactPage { const userFirstName = splitedFullName[0]; const userLastName = splitedFullName[1]; const userEmail = user.email; + const id = user._id; const userComponent = /*html*/` - + ${userFirstName} ${userLastName} ${userEmail} @@ -71,6 +75,19 @@ class ContactPage { }, ``) } + renderUsers() { + this.url.getUsersFromServer() + .then(data => { + return data.json() + }) + .then(users => { + this.users = users; + const listStructure = this.contactListComponent(users); + const listOfContacts = document.getElementById('list-of-contacts'); + listOfContacts.innerHTML = listStructure; + }) + } + applyListenerForContactPage() { const wraperForTh = document.getElementById('wraper-for-th'); wraperForTh.addEventListener('click', (e) => { @@ -85,20 +102,20 @@ class ContactPage { if(TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.firstName) { const firstName = 0; - const sortedListByFirsName = this.mergeSort(users, firstName); + const sortedListByFirsName = this.mergeSort(this.users, firstName); listOfContacts.innerHTML = this.contactListComponent(sortedListByFirsName); return; } if(TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.lastName) { const lastName = 1; - const sortedListByLastName = this.mergeSort(users, lastName); + const sortedListByLastName = this.mergeSort(this.users, lastName); listOfContacts.innerHTML = this.contactListComponent(sortedListByLastName); return; } if(TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.email) { - const sortedListByEmail = this.sortUsersByValue('email', users); + const sortedListByEmail = this.sortUsersByValue('email', this.users); listOfContacts.innerHTML = this.contactListComponent(sortedListByEmail); return; } @@ -117,7 +134,25 @@ class ContactPage { : listOfContacts.innerHTML = this.contactListComponent(filteredUsers); - }) + }); + + /* DEFINE USER */ + + const listOfContacts = document.getElementById('list-of-contacts'); + const handlerForListOfContacts = (e) => { + if(e.target.parentElement.tagName === "TR") { + const id = e.target.parentElement.id; + const user = this.users.filter(user => user._id === id)[0]; + this.userPage.setStateUserPage(); + const userPage = this.userPage.render(user); + + const MAIN_WRAPER = document.getElementById('main-wraper'); + MAIN_WRAPER.firstElementChild.outerHTML = userPage; + this.userPage.applyListenersForUserPage(); + } + } + + listOfContacts.addEventListener('click', handlerForListOfContacts); } sortUsersByValue(key, users) { @@ -161,7 +196,7 @@ class ContactPage { } filterUsersByInputValueByName(inputValue) { - return users.reduce((newUsers, user) => { + return this.users.reduce((newUsers, user) => { const firstName = user.fullName.split(' ')[0].toLowerCase(); const comparedPartOfName = firstName.slice(0, inputValue.length); From c525e3ae47b5fb1d4acb4668a2391de8cb44ef8b Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:15:06 +0300 Subject: [PATCH 11/14] add-user-page --- phone-book/src/add-user/add-user.js | 205 ++++++++++++++++++++++++---- 1 file changed, 179 insertions(+), 26 deletions(-) diff --git a/phone-book/src/add-user/add-user.js b/phone-book/src/add-user/add-user.js index 870fc94..b3d2d9d 100644 --- a/phone-book/src/add-user/add-user.js +++ b/phone-book/src/add-user/add-user.js @@ -1,7 +1,7 @@ import {Url} from '../url/url'; class AddUserPage { - constructor(store) { + constructor(store, accountName) { this.setStateContact = () => { const {setState} = store; const initializeState = { @@ -11,7 +11,7 @@ class AddUserPage { setState(initializeState); } - this.serverSide = new Url(); + this.url = new Url(accountName); } render() { @@ -28,17 +28,17 @@ class AddUserPage {
- +
- +
- +
@@ -78,40 +78,193 @@ class AddUserPage { } applyListenersForAddUserPage() { - // const fullNameInput = document.querySelector('#fullName-input'); - // const emailInput = document.querySelector('#email-input'); - // const phoneNumberInput = document.querySelector('#phoneNumber-input'); - // const birthDateInput = document.querySelector('#birthDate-input'); - // const addressInput = document.querySelector('#address-input'); - // const genderInput = document.querySelector('#gender-selection'); - // const avatarUrlInput = document.querySelector('#avatarUrl-input'); const addUserForm = document.querySelector('form'); + + const handlerForInputs = (e) => { + if(e.target.name === 'fullName') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('wrong') + e.target.classList.remove('correct') + return; + } + + if(this.isValidFullName(VALUE)) { + e.target.classList.add('correct') + e.target.classList.remove('wrong') + } else { + e.target.classList.add('wrong') + e.target.classList.remove('correct') + } + } + + if(e.target.name === 'email') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('wrong') + e.target.classList.remove('correct') + return; + } + + if(this.isValidEmail(VALUE)) { + e.target.classList.add('correct') + e.target.classList.remove('wrong') + } else { + e.target.classList.add('wrong') + e.target.classList.remove('correct') + } + } + + if(e.target.name === 'phone') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('wrong') + e.target.classList.remove('correct') + return; + } + + if(VALUE.length > 9) { + e.target.classList.add('correct') + e.target.classList.remove('wrong') + } else { + e.target.classList.add('wrong') + e.target.classList.remove('correct') + } + } + + if(e.target.name === 'birthdate') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('correct') + return; + } + + if(VALUE.length > 9) { + e.target.classList.add('correct') + } + } + + if(e.target.name === 'address') { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('correct') + return; + } + + if(VALUE.length > 0) { + e.target.classList.add('correct') + } + } + + if(e.target.name === "avatarUrl") { + const VALUE = e.target.value; + + if(VALUE.length === 0) { + e.target.classList.remove('wrong') + e.target.classList.remove('correct') + return; + } + + if(this.isValidURL(VALUE)) { + e.target.classList.add('correct') + e.target.classList.remove('wrong') + } else { + e.target.classList.add('wrong') + e.target.classList.remove('correct') + } + } + + }; + + addUserForm.addEventListener('input', handlerForInputs) + const inputs = [...addUserForm.elements] .filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT'); - addUserForm.addEventListener('submit', (e) => { + const handlerForSubmit = (e) => { + e.preventDefault(); const user = inputs.reduce((newUser, input) => { - const KEY = input.name; - const VALUE = input.value; - - if(VALUE.lenght !== 0) { - newUser[KEY] = VALUE; + if(input.classList.contains('wrong')) { + alert(`${input.name} is incorrect!`); + return; + }; + if(input.value.length !== 0 + && input.name !== 'phone' + && input.name !== 'gender' + && input.name !== 'fullName' + ) { + newUser[input.name] = input.value; } - if(VALUE === 'Male' || VALUE === 'Female') { - const firstChar = input.value[0]; - newUser[KEY] = firstChar; + if(input.value.length !== 0 && input.name === 'phone') { + newUser[input.name] = input.value.replace(/(.{3})(.{3})(.{2})/g, '($1) $2-$3-'); + } + if(input.name === 'gender') { + input.value === "Male" + ? newUser[input.name] = "M" + : newUser[input.name] = "F" + } + if(input.value.length !== 0 && input.name === 'fullName') { + const formatedFullName = input.value.split(' ').reduce((output, word, index) => { + const splitedWord = word.toLowerCase().split(''); + const firstLetter = splitedWord[0].toUpperCase(); + splitedWord[0] = firstLetter; + output += splitedWord.join(''); + + if(index === 0) { + output += ' '; + } + + return output; + }, ''); + + newUser[input.name] = formatedFullName; } return newUser; - }, {}); - - this.serverSide.postUser(user); - }) + }, {}) + + if(user) { + this.url.postUser(user); + + inputs.forEach(input => { + if(input.tagName !== "SELECT") { + input.value = ""; + input.classList.remove('correct'); + } + }) + } else { + alert('Something is incorrect!') + } + } + + addUserForm.addEventListener('submit', handlerForSubmit) } - isValid() { + isValidFullName(value) { + const splitedValue = value.split(' '); + + return splitedValue.length === 2 && splitedValue[0].length > 0 && splitedValue[1].length > 0; + } + + isValidEmail(value) { + const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(String(value).toLowerCase()); + } + isValidURL(value) { + const re = new RegExp('^(https?:\\/\\/)?'+ // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|'+ // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string + '(\\#[-a-z\\d_]*)?$','i'); // fragment locator + return re.test(String(value).toLowerCase()); } } From 4e730cec0fe138568549e0de1a55af679154e9c7 Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Mon, 20 Aug 2018 20:15:50 +0300 Subject: [PATCH 12/14] bundle.js index.html deleted users.js(dont need anymore) --- phone-book/build/bundle.js | 56 +++++++++++++++++++++--------- phone-book/index.html | 1 + phone-book/src/components/users.js | 6 ---- 3 files changed, 41 insertions(+), 22 deletions(-) delete mode 100644 phone-book/src/components/users.js diff --git a/phone-book/build/bundle.js b/phone-book/build/bundle.js index 9157a0b..f7426da 100644 --- a/phone-book/build/bundle.js +++ b/phone-book/build/bundle.js @@ -94,7 +94,19 @@ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AddUserPage\", function() { return AddUserPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nclass AddUserPage {\n constructor(store) {\n this.setStateContact = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'ADD USER',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.serverSide = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"]();\n }\n\n render() {\n return (/*html*/`\n
\n\n
\n
\n Add new user\n
\n
\n\n
\n \n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n \n
\n \n \n ex: https://cloud-drive/photo123456.\n
\n\n
\n \n
\n \n \n
\n\n
\n `\n );\n }\n\n applyListenersForAddUserPage() {\n // const fullNameInput = document.querySelector('#fullName-input');\n // const emailInput = document.querySelector('#email-input');\n // const phoneNumberInput = document.querySelector('#phoneNumber-input');\n // const birthDateInput = document.querySelector('#birthDate-input');\n // const addressInput = document.querySelector('#address-input');\n // const genderInput = document.querySelector('#gender-selection');\n // const avatarUrlInput = document.querySelector('#avatarUrl-input');\n\n const addUserForm = document.querySelector('form');\n const inputs = [...addUserForm.elements].filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT');\n\n addUserForm.addEventListener('submit', e => {\n\n const user = inputs.reduce((newUser, input) => {\n const KEY = input.name;\n const VALUE = input.value;\n\n if (VALUE.lenght !== 0) {\n newUser[KEY] = VALUE;\n }\n if (VALUE === 'Male' || VALUE === 'Female') {\n const firstChar = input.value[0];\n newUser[KEY] = firstChar;\n }\n return newUser;\n }, {});\n\n this.serverSide.postUser(user);\n });\n }\n\n isValid() {}\n}\n\n\n\n//# sourceURL=webpack:///./src/add-user/add-user.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AddUserPage\", function() { return AddUserPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nclass AddUserPage {\n constructor(store, accountName) {\n this.setStateContact = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'ADD USER',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"](accountName);\n }\n\n render() {\n return (/*html*/`\n
\n\n
\n
\n Add new user\n
\n
\n\n
\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n \n
\n \n \n ex: https://cloud-drive/photo123456.\n
\n\n
\n \n
\n \n
\n
\n\n
\n `\n );\n }\n\n applyListenersForAddUserPage() {\n\n const addUserForm = document.querySelector('form');\n\n const handlerForInputs = e => {\n if (e.target.name === 'fullName') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidFullName(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'email') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidEmail(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'phone') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'birthdate') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === 'address') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 0) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === \"avatarUrl\") {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidURL(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n };\n\n addUserForm.addEventListener('input', handlerForInputs);\n\n const inputs = [...addUserForm.elements].filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT');\n\n const handlerForSubmit = e => {\n e.preventDefault();\n\n const user = inputs.reduce((newUser, input) => {\n if (input.classList.contains('wrong')) {\n alert(`${input.name} is incorrect!`);\n return;\n };\n if (input.value.length !== 0 && input.name !== 'phone' && input.name !== 'gender' && input.name !== 'fullName') {\n newUser[input.name] = input.value;\n }\n if (input.value.length !== 0 && input.name === 'phone') {\n newUser[input.name] = input.value.replace(/(.{3})(.{3})(.{2})/g, '($1) $2-$3-');\n }\n if (input.name === 'gender') {\n input.value === \"Male\" ? newUser[input.name] = \"M\" : newUser[input.name] = \"F\";\n }\n if (input.value.length !== 0 && input.name === 'fullName') {\n const formatedFullName = input.value.split(' ').reduce((output, word, index) => {\n const splitedWord = word.toLowerCase().split('');\n const firstLetter = splitedWord[0].toUpperCase();\n splitedWord[0] = firstLetter;\n output += splitedWord.join('');\n\n if (index === 0) {\n output += ' ';\n }\n\n return output;\n }, '');\n\n newUser[input.name] = formatedFullName;\n }\n return newUser;\n }, {});\n\n if (user) {\n this.url.postUser(user);\n\n inputs.forEach(input => {\n if (input.tagName !== \"SELECT\") {\n input.value = \"\";\n input.classList.remove('correct');\n }\n });\n } else {\n alert('Something is incorrect!');\n }\n };\n\n addUserForm.addEventListener('submit', handlerForSubmit);\n }\n\n isValidFullName(value) {\n const splitedValue = value.split(' ');\n\n return splitedValue.length === 2 && splitedValue[0].length > 0 && splitedValue[1].length > 0;\n }\n\n isValidEmail(value) {\n const re = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n return re.test(String(value).toLowerCase());\n }\n\n isValidURL(value) {\n const re = new RegExp('^(https?:\\\\/\\\\/)?' + // protocol\n '((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.?)+[a-z]{2,}|' + // domain name\n '((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))' + // OR ip (v4) address\n '(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*' + // port and path\n '(\\\\?[;&a-z\\\\d%_.~+=-]*)?' + // query string\n '(\\\\#[-a-z\\\\d_]*)?$', 'i'); // fragment locator\n return re.test(String(value).toLowerCase());\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/add-user/add-user.js?"); + +/***/ }), + +/***/ "./src/authorization-page/authorization-page.js": +/*!******************************************************!*\ + !*** ./src/authorization-page/authorization-page.js ***! + \******************************************************/ +/*! exports provided: AuthorizationPage */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AuthorizationPage\", function() { return AuthorizationPage; });\nclass AuthorizationPage {\n constructor() {\n this.setStateAuthorization = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'AUTHORIZATION',\n activePage: this.render()\n };\n setState(initializeState);\n };\n }\n\n render() {\n return (/*html*/`\n
\n

Authorization

\n
\n \n \n
\n
\n `\n );\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/authorization-page/authorization-page.js?"); /***/ }), @@ -110,27 +122,27 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ }), -/***/ "./src/components/users.js": -/*!*********************************!*\ - !*** ./src/components/users.js ***! - \*********************************/ -/*! exports provided: users */ +/***/ "./src/contact/contact.js": +/*!********************************!*\ + !*** ./src/contact/contact.js ***! + \********************************/ +/*! exports provided: ContactPage */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"users\", function() { return users; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nconst serverSide = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"]();\nconst users = serverSide.getUsersFromServer();\n\n\n\n//# sourceURL=webpack:///./src/components/users.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ContactPage\", function() { return ContactPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n/* harmony import */ var _user_page_user_page__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../user-page/user-page */ \"./src/user-page/user-page.js\");\n\n\n\n/* ================== CONTACT START================== */\n\nclass ContactPage {\n constructor(store, accountName) {\n this.setStateContact = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'CONTACT',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"](accountName);\n this.userPage = new _user_page_user_page__WEBPACK_IMPORTED_MODULE_1__[\"UserPage\"](store, accountName);\n }\n\n render() {\n const contactTempalte = /*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n
\n\n
\n \n\n \n \n \n \n \n \n \n\n \n \n \n\n
NameLast NameEmail
\n
\n
\n `;\n\n return contactTempalte;\n }\n\n contactListComponent(userList) {\n return userList.reduce((listStructure, user) => {\n const splitedFullName = user.fullName.split(' ');\n const userFirstName = splitedFullName[0];\n const userLastName = splitedFullName[1];\n const userEmail = user.email;\n const id = user._id;\n\n const userComponent = /*html*/`\n \n ${userFirstName} \n ${userLastName} \n ${userEmail} \n \n `;\n\n listStructure += userComponent;\n return listStructure;\n }, ``);\n }\n\n renderUsers() {\n this.url.getUsersFromServer().then(data => {\n return data.json();\n }).then(users => {\n this.users = users;\n const listStructure = this.contactListComponent(users);\n const listOfContacts = document.getElementById('list-of-contacts');\n listOfContacts.innerHTML = listStructure;\n });\n }\n\n applyListenerForContactPage() {\n const wraperForTh = document.getElementById('wraper-for-th');\n wraperForTh.addEventListener('click', e => {\n const TH_ELEM_CONTAINS = e.target.textContent.trim();\n const PREDICT_TEXT_CONTENT = {\n firstName: 'Name',\n lastName: 'Last Name',\n email: 'Email'\n };\n\n const listOfContacts = document.getElementById('list-of-contacts');\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.firstName) {\n const firstName = 0;\n const sortedListByFirsName = this.mergeSort(this.users, firstName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByFirsName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.lastName) {\n const lastName = 1;\n const sortedListByLastName = this.mergeSort(this.users, lastName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByLastName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.email) {\n const sortedListByEmail = this.sortUsersByValue('email', this.users);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByEmail);\n return;\n }\n });\n\n /* SORT USERS BY INPUTED LETTERS OF NAME */\n const contactSearchField = document.querySelector('#search');\n\n contactSearchField.addEventListener('input', () => {\n const VALUE = contactSearchField.value;\n const filteredUsers = this.filterUsersByInputValueByName(VALUE);\n const listOfContacts = document.getElementById('list-of-contacts');\n\n filteredUsers.length === 0 ? listOfContacts.innerHTML = /*html*/`

No such users

` : listOfContacts.innerHTML = this.contactListComponent(filteredUsers);\n });\n\n /* DEFINE USER */\n\n const listOfContacts = document.getElementById('list-of-contacts');\n const handlerForListOfContacts = e => {\n if (e.target.parentElement.tagName === \"TR\") {\n const id = e.target.parentElement.id;\n const user = this.users.filter(user => user._id === id)[0];\n this.userPage.setStateUserPage();\n const userPage = this.userPage.render(user);\n\n const MAIN_WRAPER = document.getElementById('main-wraper');\n MAIN_WRAPER.firstElementChild.outerHTML = userPage;\n this.userPage.applyListenersForUserPage();\n }\n };\n\n listOfContacts.addEventListener('click', handlerForListOfContacts);\n }\n\n sortUsersByValue(key, users) {\n const sortFunction = function (value, nextValue) {\n if (value[key] > nextValue[key]) return 1;\n if (value[key] < nextValue[key]) return -1;\n };\n\n return [...users].sort(sortFunction);\n }\n\n mergeSort(arr, index) {\n\n const len = arr.length;\n if (len < 2) return arr;\n const mid = Math.floor(len / 2),\n left = arr.slice(0, mid),\n right = arr.slice(mid);\n\n return this.merge(this.mergeSort(left, index), this.mergeSort(right, index), index);\n }\n\n merge(left, right, index) {\n let result = [],\n lLen = left.length,\n rLen = right.length,\n l = 0,\n r = 0;\n while (l < lLen && r < rLen) {\n const leftWord = left[l].fullName.split(' ')[index];\n const rightWord = right[r].fullName.split(' ')[index];\n if (leftWord < rightWord) {\n result.push(left[l++]);\n } else {\n result.push(right[r++]);\n }\n }\n\n return result.concat(left.slice(l)).concat(right.slice(r));\n }\n\n filterUsersByInputValueByName(inputValue) {\n return this.users.reduce((newUsers, user) => {\n const firstName = user.fullName.split(' ')[0].toLowerCase();\n\n const comparedPartOfName = firstName.slice(0, inputValue.length);\n\n if (inputValue.toLowerCase() === comparedPartOfName) {\n newUsers.push(user);\n }\n\n return newUsers;\n }, []);\n }\n}\n\n/* ================== CONTACT END================== */\n\n\n\n//# sourceURL=webpack:///./src/contact/contact.js?"); /***/ }), -/***/ "./src/contact/contact.js": -/*!********************************!*\ - !*** ./src/contact/contact.js ***! - \********************************/ -/*! exports provided: ContactPage */ +/***/ "./src/edit-user-page/edit-user-page.js": +/*!**********************************************!*\ + !*** ./src/edit-user-page/edit-user-page.js ***! + \**********************************************/ +/*! exports provided: EditUserPage */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ContactPage\", function() { return ContactPage; });\n/* harmony import */ var _components_users__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/users */ \"./src/components/users.js\");\n\n\n/* ================== CONTACT START================== */\n\nclass ContactPage {\n constructor(store) {\n this.setStateContact = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'CONTACT',\n activePage: this.render()\n };\n setState(initializeState);\n };\n }\n\n render() {\n const contactTempalte = /*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n
\n\n
\n \n\n \n \n \n \n \n \n \n\n \n ${this.contactListComponent(_components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"])}\n \n\n
NameLast NameEmail
\n
\n
\n `;\n\n return contactTempalte;\n }\n\n contactListComponent(userList) {\n return userList.reduce((listStructure, user) => {\n const splitedFullName = user.fullName.split(' ');\n const userFirstName = splitedFullName[0];\n const userLastName = splitedFullName[1];\n const userEmail = user.email;\n\n const userComponent = /*html*/`\n \n ${userFirstName} \n ${userLastName} \n ${userEmail} \n \n `;\n\n listStructure += userComponent;\n return listStructure;\n }, ``);\n }\n\n applyListenerForContactPage() {\n const wraperForTh = document.getElementById('wraper-for-th');\n wraperForTh.addEventListener('click', e => {\n const TH_ELEM_CONTAINS = e.target.textContent.trim();\n const PREDICT_TEXT_CONTENT = {\n firstName: 'Name',\n lastName: 'Last Name',\n email: 'Email'\n };\n\n const listOfContacts = document.getElementById('list-of-contacts');\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.firstName) {\n const firstName = 0;\n const sortedListByFirsName = this.mergeSort(_components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"], firstName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByFirsName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.lastName) {\n const lastName = 1;\n const sortedListByLastName = this.mergeSort(_components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"], lastName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByLastName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.email) {\n const sortedListByEmail = this.sortUsersByValue('email', _components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"]);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByEmail);\n return;\n }\n });\n\n /* SORT USERS BY INPUTED LETTERS OF NAME */\n const contactSearchField = document.querySelector('#search');\n\n contactSearchField.addEventListener('input', () => {\n const VALUE = contactSearchField.value;\n const filteredUsers = this.filterUsersByInputValueByName(VALUE);\n const listOfContacts = document.getElementById('list-of-contacts');\n\n filteredUsers.length === 0 ? listOfContacts.innerHTML = /*html*/`

No such users

` : listOfContacts.innerHTML = this.contactListComponent(filteredUsers);\n });\n }\n\n sortUsersByValue(key, users) {\n const sortFunction = function (value, nextValue) {\n if (value[key] > nextValue[key]) return 1;\n if (value[key] < nextValue[key]) return -1;\n };\n\n return [...users].sort(sortFunction);\n }\n\n mergeSort(arr, index) {\n\n const len = arr.length;\n if (len < 2) return arr;\n const mid = Math.floor(len / 2),\n left = arr.slice(0, mid),\n right = arr.slice(mid);\n\n return this.merge(this.mergeSort(left, index), this.mergeSort(right, index), index);\n }\n\n merge(left, right, index) {\n let result = [],\n lLen = left.length,\n rLen = right.length,\n l = 0,\n r = 0;\n while (l < lLen && r < rLen) {\n const leftWord = left[l].fullName.split(' ')[index];\n const rightWord = right[r].fullName.split(' ')[index];\n if (leftWord < rightWord) {\n result.push(left[l++]);\n } else {\n result.push(right[r++]);\n }\n }\n\n return result.concat(left.slice(l)).concat(right.slice(r));\n }\n\n filterUsersByInputValueByName(inputValue) {\n return _components_users__WEBPACK_IMPORTED_MODULE_0__[\"users\"].reduce((newUsers, user) => {\n const firstName = user.fullName.split(' ')[0].toLowerCase();\n\n const comparedPartOfName = firstName.slice(0, inputValue.length);\n\n if (inputValue.toLowerCase() === comparedPartOfName) {\n newUsers.push(user);\n }\n\n return newUsers;\n }, []);\n }\n}\n\n/* ================== CONTACT END================== */\n\n\n\n//# sourceURL=webpack:///./src/contact/contact.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"EditUserPage\", function() { return EditUserPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nclass EditUserPage {\n constructor(store, accountName) {\n this.setStateEditUser = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'EDIT USER'\n };\n setState(initializeState);\n };\n\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"](accountName);\n }\n\n render(user) {\n this.user = user;\n\n return (/*html*/`\n
\n\n
\n
\n Edit user ${user.fullName}\n
\n
\n\n
\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n Length of your phone number should be more than 9\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n \n
\n \n \n ex: https://cloud-drive/photo123456.\n
\n\n
\n \n
\n \n
\n
\n\n
\n `\n );\n }\n\n applyListenersForEditUserPage() {\n\n const editUserForm = document.querySelector('form');\n\n const handlerForInputs = e => {\n if (e.target.name === 'fullName') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidFullName(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'email') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidEmail(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'phone') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'birthdate') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === 'address') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 0) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === \"avatarUrl\") {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidURL(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n };\n\n editUserForm.addEventListener('input', handlerForInputs);\n const inputs = [...editUserForm.elements].filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT');\n\n const handlerForSubmit = e => {\n e.preventDefault();\n\n const infoToEdit = inputs.reduce((editedUser, input) => {\n if (input.classList.contains('wrong')) {\n alert(`${input.name} is incorrect!`);\n return;\n };\n if (input.value.length !== 0 && input.name !== 'phone' && input.name !== 'gender' && input.name !== 'fullName') {\n editedUser[input.name] = input.value;\n }\n if (input.value.length !== 0 && input.name === 'phone') {\n editedUser[input.name] = input.value.replace(/(.{3})(.{3})(.{2})/g, '($1) $2-$3-');\n }\n if (input.name === 'gender') {\n input.value === \"Male\" ? editedUser[input.name] = \"M\" : editedUser[input.name] = \"F\";\n }\n if (input.value.length !== 0 && input.name === 'fullName') {\n const formatedFullName = input.value.split(' ').reduce((output, word, index) => {\n const splitedWord = word.toLowerCase().split('');\n const firstLetter = splitedWord[0].toUpperCase();\n splitedWord[0] = firstLetter;\n output += splitedWord.join('');\n\n if (index === 0) {\n output += ' ';\n }\n\n return output;\n }, '');\n\n editedUser[input.name] = formatedFullName;\n }\n return editedUser;\n }, {});\n\n if (infoToEdit) {\n this.url.editUser(infoToEdit, this.user._id);\n\n inputs.forEach(input => {\n if (input.tagName !== \"SELECT\") {\n input.value = \"\";\n input.classList.remove('correct');\n }\n });\n } else {\n alert('Something is incorrect!');\n }\n };\n\n editUserForm.addEventListener('submit', handlerForSubmit);\n }\n\n isValidFullName(value) {\n const splitedValue = value.split(' ');\n\n return splitedValue.length === 2 && splitedValue[0].length > 0 && splitedValue[1].length > 0;\n }\n\n isValidEmail(value) {\n const re = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n return re.test(String(value).toLowerCase());\n }\n\n isValidURL(value) {\n const re = new RegExp('^(https?:\\\\/\\\\/)?' + // protocol\n '((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.?)+[a-z]{2,}|' + // domain name\n '((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))' + // OR ip (v4) address\n '(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*' + // port and path\n '(\\\\?[;&a-z\\\\d%_.~+=-]*)?' + // query string\n '(\\\\#[-a-z\\\\d_]*)?$', 'i'); // fragment locator\n return re.test(String(value).toLowerCase());\n }\n\n}\n\n\n\n//# sourceURL=webpack:///./src/edit-user-page/edit-user-page.js?"); /***/ }), @@ -142,7 +154,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _contact_contact__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./contact/contact */ \"./src/contact/contact.js\");\n/* harmony import */ var _keypad_keypad__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./keypad/keypad */ \"./src/keypad/keypad.js\");\n/* harmony import */ var _add_user_add_user__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./add-user/add-user */ \"./src/add-user/add-user.js\");\n\n\n\n\n\nclass App {\n constructor() {\n this.store = this.createStore();\n this.pages = {\n 'contacts': new _contact_contact__WEBPACK_IMPORTED_MODULE_0__[\"ContactPage\"](this.store),\n 'keypad': new _keypad_keypad__WEBPACK_IMPORTED_MODULE_1__[\"KeypadPage\"](this.store),\n 'addUser': new _add_user_add_user__WEBPACK_IMPORTED_MODULE_2__[\"AddUserPage\"](this.store),\n 'footer': new FooterNavigationBar()\n };\n this.pages.contacts.setStateContact();\n this.render();\n this.pages.contacts.applyListenerForContactPage();\n this.applyListenerForNavigation();\n }\n\n createStore() {\n let state;\n\n return {\n getState() {\n return state;\n },\n setState(newState) {\n state = newState;\n }\n };\n }\n\n reducer(action) {\n const currentState = this.store.getState();\n const mainWraper = document.getElementById('main-wraper');\n const switchBetweenPages = () => {\n mainWraper.firstElementChild.outerHTML = currentState.activePage;\n };\n\n if (action.type === 'MOVE_TO_KEYPAD_PAGE') {\n this.pages.keypad.setStateKeypad();\n switchBetweenPages();\n this.pages.keypad.applyListenerForKeypadPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_CONTACT_PAGE') {\n this.pages.contacts.setStateContact();\n switchBetweenPages();\n this.pages.contacts.applyListenerForContactPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_ADD_USER_PAGE') {\n this.pages.addUser.setStateContact();\n switchBetweenPages();\n this.pages.addUser.applyListenersForAddUserPage();\n return;\n }\n }\n\n render() {\n const currentState = this.store.getState();\n const FOOTER = this.pages.footer.render();\n\n const appTemplate = /*html*/`\n
\n ${currentState.activePage}\n ${FOOTER}\n
\n `;\n\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = appTemplate;\n }\n\n applyListenerForNavigation() {\n\n const _MOVE_TO_KEYPAD_PAGE = {\n type: 'MOVE_TO_KEYPAD_PAGE'\n };\n\n const _MOVE_TO_CONTACT_PAGE = {\n type: 'MOVE_TO_CONTACT_PAGE'\n };\n\n const _MOVE_TO_ADD_USER_PAGE = {\n type: 'MOVE_TO_ADD_USER_PAGE'\n };\n\n const wraperForFooter = document.getElementById('wraper-for-footer');\n wraperForFooter.addEventListener('click', e => {\n const currentState = this.store.getState();\n\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'to-keypad-page' || BUTTON_ID_FROM_SVG === 'to-keypad-page' || BUTTON_ID_FROM_PATH === 'to-keypad-page') {\n\n if (currentState.stateName !== 'KEYPAD') {\n this.pages.keypad.setStateKeypad();\n return this.reducer(_MOVE_TO_KEYPAD_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-contact-page' || BUTTON_ID_FROM_SVG === 'to-contact-page' || BUTTON_ID_FROM_PATH === 'to-contact-page') {\n\n if (currentState.stateName !== 'CONTACT') {\n this.pages.contacts.setStateContact();\n return this.reducer(_MOVE_TO_CONTACT_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-addUser-page' || BUTTON_ID_FROM_SVG === 'to-addUser-page' || BUTTON_ID_FROM_PATH === 'to-addUser-page') {\n\n if (currentState.stateName !== 'ADD USER') {\n this.pages.addUser.setStateContact();\n return this.reducer(_MOVE_TO_ADD_USER_PAGE);\n }\n return;\n }\n });\n }\n}\n\n/* ================== FOOTER START================== */\n\nclass FooterNavigationBar {\n constructor() {\n this.icons = {\n contactIcon: {\n id: 'to-contact-page',\n class: 'far fa-address-book'\n },\n keypadIcon: {\n id: 'to-keypad-page',\n class: 'fas fa-tty'\n },\n addUserIcon: {\n id: 'to-addUser-page',\n class: 'fas fa-user-plus'\n }\n };\n }\n\n render() {\n const navigationBar = /*html*/`\n
\n
\n ${this.createIcon(this.icons.contactIcon)}\n ${this.createIcon(this.icons.keypadIcon)}\n ${this.createIcon(this.icons.addUserIcon)}\n
\n
\n `;\n\n return navigationBar;\n }\n\n createIcon(iconPattern) {\n const ID = iconPattern.id;\n const CLASS = iconPattern.class;\n\n const icon = /*html*/`\n
\n \n
\n `;\n\n return icon;\n }\n\n}\n\n/* ================== FOOTER END================== */\n\nconst APPLICATION = new App();\n\n//# sourceURL=webpack:///./src/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./authorization-page/authorization-page */ \"./src/authorization-page/authorization-page.js\");\n/* harmony import */ var _contact_contact__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./contact/contact */ \"./src/contact/contact.js\");\n/* harmony import */ var _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./keypad/keypad */ \"./src/keypad/keypad.js\");\n/* harmony import */ var _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./add-user/add-user */ \"./src/add-user/add-user.js\");\n\n\n\n\n\nclass App {\n constructor() {\n this.store = this.createStore();\n this.authorizationPage = new _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__[\"AuthorizationPage\"]();\n this.renderAuthorizationPage();\n }\n\n createStore() {\n let state;\n\n return {\n getState() {\n return state;\n },\n setState(newState) {\n state = newState;\n }\n };\n }\n\n reducer(action) {\n const currentState = this.store.getState();\n const mainWraper = document.getElementById('main-wraper');\n const switchBetweenPages = () => {\n mainWraper.firstElementChild.outerHTML = currentState.activePage;\n };\n\n if (action.type === 'MOVE_TO_KEYPAD_PAGE') {\n this.pages.keypad.setStateKeypad();\n switchBetweenPages();\n this.pages.keypad.applyListenerForKeypadPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_CONTACT_PAGE') {\n this.pages.contacts.setStateContact();\n switchBetweenPages();\n this.pages.contacts.renderUsers();\n this.pages.contacts.applyListenerForContactPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_ADD_USER_PAGE') {\n this.pages.addUser.setStateContact();\n switchBetweenPages();\n this.pages.addUser.applyListenersForAddUserPage();\n return;\n }\n }\n\n renderAuthorizationPage() {\n const authorizationPage = this.authorizationPage.render();\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = authorizationPage;\n this.applyListenerForAuthorizationPage();\n }\n\n applyListenerForAuthorizationPage() {\n const input = document.querySelector('.au-input');\n const logInButton = document.getElementById('log-in');\n const switchBetweenPages = () => {\n this.accountName = input.value;\n\n this.pages = {\n 'contacts': new _contact_contact__WEBPACK_IMPORTED_MODULE_1__[\"ContactPage\"](this.store, this.accountName),\n 'keypad': new _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__[\"KeypadPage\"](this.store, this.accountName),\n 'addUser': new _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__[\"AddUserPage\"](this.store, this.accountName),\n 'footer': new FooterNavigationBar()\n };\n\n this.pages.contacts.setStateContact();\n this.render();\n this.pages.contacts.applyListenerForContactPage();\n this.applyListenerForNavigation();\n };\n\n const handlerForLogInBtn = () => {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n };\n\n const handlerForLogInInput = e => {\n if (e.keyCode === 13) {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n }\n };\n\n logInButton.addEventListener('click', handlerForLogInBtn);\n input.addEventListener('keydown', handlerForLogInInput);\n }\n\n render() {\n const currentState = this.store.getState();\n const FOOTER = this.pages.footer.render();\n\n const appTemplate = /*html*/`\n
\n ${currentState.activePage}\n ${FOOTER}\n
\n `;\n\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = appTemplate;\n\n this.pages.contacts.renderUsers();\n }\n\n applyListenerForNavigation() {\n\n const _MOVE_TO_KEYPAD_PAGE = {\n type: 'MOVE_TO_KEYPAD_PAGE'\n };\n\n const _MOVE_TO_CONTACT_PAGE = {\n type: 'MOVE_TO_CONTACT_PAGE'\n };\n\n const _MOVE_TO_ADD_USER_PAGE = {\n type: 'MOVE_TO_ADD_USER_PAGE'\n };\n\n const wraperForFooter = document.getElementById('wraper-for-footer');\n wraperForFooter.addEventListener('click', e => {\n const currentState = this.store.getState();\n\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'to-keypad-page' || BUTTON_ID_FROM_SVG === 'to-keypad-page' || BUTTON_ID_FROM_PATH === 'to-keypad-page') {\n\n if (currentState.stateName !== 'KEYPAD') {\n this.pages.keypad.setStateKeypad();\n return this.reducer(_MOVE_TO_KEYPAD_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-contact-page' || BUTTON_ID_FROM_SVG === 'to-contact-page' || BUTTON_ID_FROM_PATH === 'to-contact-page') {\n\n if (currentState.stateName !== 'CONTACT') {\n this.pages.contacts.setStateContact();\n return this.reducer(_MOVE_TO_CONTACT_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-addUser-page' || BUTTON_ID_FROM_SVG === 'to-addUser-page' || BUTTON_ID_FROM_PATH === 'to-addUser-page') {\n\n if (currentState.stateName !== 'ADD USER') {\n this.pages.addUser.setStateContact();\n return this.reducer(_MOVE_TO_ADD_USER_PAGE);\n }\n return;\n }\n });\n }\n}\n\n/* ================== FOOTER START================== */\n\nclass FooterNavigationBar {\n constructor() {\n this.icons = {\n contactIcon: {\n id: 'to-contact-page',\n class: 'far fa-address-book'\n },\n keypadIcon: {\n id: 'to-keypad-page',\n class: 'fas fa-tty'\n },\n addUserIcon: {\n id: 'to-addUser-page',\n class: 'fas fa-user-plus'\n }\n };\n }\n\n render() {\n const navigationBar = /*html*/`\n
\n
\n ${this.createIcon(this.icons.contactIcon)}\n ${this.createIcon(this.icons.keypadIcon)}\n ${this.createIcon(this.icons.addUserIcon)}\n
\n
\n `;\n\n return navigationBar;\n }\n\n createIcon(iconPattern) {\n const ID = iconPattern.id;\n const CLASS = iconPattern.class;\n\n const icon = /*html*/`\n
\n \n
\n `;\n\n return icon;\n }\n\n}\n\n/* ================== FOOTER END================== */\n\nconst APPLICATION = new App();\n\n//# sourceURL=webpack:///./src/index.js?"); /***/ }), @@ -154,7 +166,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _con /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"KeypadPage\", function() { return KeypadPage; });\n/* harmony import */ var _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/mobile-operators-identifiers */ \"./src/components/mobile-operators-identifiers.js\");\n\n\n/* ================== KEYPAD START================== */\n\nclass KeypadPage {\n constructor(store) {\n this.setStateKeypad = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'KEYPAD',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.callMode = new CallMode();\n }\n\n render() {\n const buttons = {\n ONE: '1',\n TWO: '2',\n THREE: '3',\n FOUR: '4',\n FIVE: '5',\n SIX: '6',\n SEVEN: '7',\n EIGHT: '8',\n NINE: '9',\n ZERO: '0',\n ASTERISK: '*',\n HASH: '#'\n };\n\n return (/*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n \n
\n
\n
\n\n
\n \n
\n
\n ${this.createButton(buttons.ONE)}\n ${this.createButton(buttons.TWO)}\n ${this.createButton(buttons.THREE)}\n
\n
\n ${this.createButton(buttons.FOUR)}\n ${this.createButton(buttons.FIVE)}\n ${this.createButton(buttons.SIX)}\n
\n
\n ${this.createButton(buttons.SEVEN)}\n ${this.createButton(buttons.EIGHT)}\n ${this.createButton(buttons.NINE)}\n
\n
\n ${this.createButton(buttons.ASTERISK)}\n ${this.createButton(buttons.ZERO)}\n ${this.createButton(buttons.HASH)}\n
\n
\n\n
\n
\n
\n \n\n
\n\n
\n `\n );\n }\n\n createButton(value) {\n const button = /*html*/`\n
${value}
\n `;\n\n return button;\n }\n\n applyListenerForKeypadPage() {\n\n /* ADD NUMBER */\n const keypadButtons = document.getElementById('wraper-for-buttons');\n const fieldForNumber = document.getElementById('number');\n const fieldForOperator = document.getElementById('operator');\n\n const toFormateNumberFieldForAdding = () => {\n const numbersFromField = fieldForNumber.textContent.replace(/\\D/gm, '');\n let finalConstructions = null;\n\n if (numbersFromField.length === 1) {\n finalConstructions = numbersFromField.replace(/(.{1})/g, '($1');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 3) {\n finalConstructions = numbersFromField.replace(/(.{3})/g, '($1)');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 4) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{1})/g, '($1) $2');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 7) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{1})/g, '($1) $2-$3');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 9) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{2})(.{1})/g, '($1) $2-$3-$4');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n };\n\n keypadButtons.addEventListener('click', e => {\n const TARGET_CLASS_NAME = e.target.className;\n\n if (TARGET_CLASS_NAME === 'number-btn') {\n const BUTTON_VALUE = e.target.textContent;\n fieldForNumber.textContent += BUTTON_VALUE;\n\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n }\n });\n\n /* REMOVE NUMBER */\n const deleteButton = document.getElementById('delete');\n\n deleteButton.addEventListener('click', e => {\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'delete' || BUTTON_ID_FROM_SVG === 'delete' || BUTTON_ID_FROM_PATH === 'delete') {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n\n return;\n }\n });\n\n /* TO CALL BUTTON */\n const mainWraper = document.getElementById('main-wraper');\n\n const toCallButton = document.getElementById('call-btn');\n toCallButton.addEventListener('click', () => {\n const ERROR_BLOCK = document.getElementById('error-block');\n\n if (fieldForNumber.textContent.length < 3) {\n ERROR_BLOCK.textContent = `ERROR you've typed incorrect number`;\n setTimeout(() => {\n ERROR_BLOCK.textContent = '';\n }, 3000);\n return;\n }\n\n const NUMBER_FOR_CALL_MODE = this.callMode.getNumber();\n const OPERATOR_FOR_CALL_MODE = this.callMode.getOperator();\n\n mainWraper.classList.add('call-mode');\n mainWraper.innerHTML = this.callMode.render(NUMBER_FOR_CALL_MODE, OPERATOR_FOR_CALL_MODE);\n this.callMode.applyListenerForCallMode();\n });\n\n /* WRITING NUMBER BY KEYBOARD */\n\n const keyCodes = {\n ONE: 49,\n TWO: 50,\n THREE: 51,\n FOUR: 52,\n FIVE: 53,\n SIX: 54,\n SEVEN: 55,\n EIGHT: 56,\n NINE: 57,\n ZERO: 48,\n ASTERISK: 42,\n HASH: 35,\n DELETE: 8\n };\n\n const SINGLE_TAPS = e => {\n\n if (e.keyCode === keyCodes.ONE) {\n const ONE = '1';\n fieldForNumber.textContent += ONE;\n }\n if (e.keyCode === keyCodes.TWO) {\n const TWO = '2';\n fieldForNumber.textContent += TWO;\n }\n if (e.keyCode === keyCodes.THREE) {\n const THREE = '3';\n fieldForNumber.textContent += THREE;\n }\n if (e.keyCode === keyCodes.FOUR) {\n const FOUR = '4';\n fieldForNumber.textContent += FOUR;\n }\n if (e.keyCode === keyCodes.FIVE) {\n const FIVE = '5';\n fieldForNumber.textContent += FIVE;\n }\n if (e.keyCode === keyCodes.SIX) {\n const SIX = '6';\n fieldForNumber.textContent += SIX;\n }\n if (e.keyCode === keyCodes.SEVEN) {\n const SEVEN = '7';\n fieldForNumber.textContent += SEVEN;\n }\n if (e.keyCode === keyCodes.EIGHT) {\n const EIGHT = '8';\n fieldForNumber.textContent += EIGHT;\n }\n if (e.keyCode === keyCodes.NINE) {\n const NINE = '9';\n fieldForNumber.textContent += NINE;\n }\n if (e.keyCode === keyCodes.ZERO) {\n const ZERO = '0';\n fieldForNumber.textContent += ZERO;\n }\n if (e.keyCode === keyCodes.HASH) {\n const HASH = '#';\n fieldForNumber.textContent += HASH;\n }\n if (e.keyCode === keyCodes.ASTERISK) {\n const ASTERISK = '*';\n fieldForNumber.textContent += ASTERISK;\n }\n\n /* IDENTIFICATION FUNCTIONAL */\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n };\n\n const DELETE_FUNCTIONAL = e => {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n\n if (e.keyCode === keyCodes.DELETE) {\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n return;\n }\n };\n\n window.addEventListener('keypress', SINGLE_TAPS);\n window.addEventListener('keydown', DELETE_FUNCTIONAL);\n }\n\n indentifyMobileOperator(firstThreeNumbers) {\n let operator;\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].kuivstar.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Kuivstar';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].life.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Life';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].vodafone.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Vodafone';\n }\n });\n\n return operator;\n }\n}\n\n/* ================== KEYPAD END================== */\n\n/* ================== CALL MODE START================== */\nclass CallMode {\n constructor() {}\n\n render(number, operator) {\n return (/*html*/`\n
\n
\n\n
\n ${number}\n ${operator}\n
\n\n
\n \n \n \n \n \n
\n\n
\n\n
\n\n
\n\n
\n\n
\n
\n \n
\n mute\n
\n\n
\n
\n \n
\n keypad\n
\n \n
\n
\n \n
\n volume\n
\n \n
\n\n
\n
\n
\n \n
\n add\n
\n \n
\n
\n \n
\n video\n
\n\n
\n
\n \n
\n contacts\n
\n
\n\n
\n\n
\n
\n \n
\n
\n\n
\n
\n `\n );\n }\n\n getNumber() {\n const phoneNumber = document.getElementById('number');\n return phoneNumber.textContent;\n }\n\n getOperator() {\n const phoneOperator = document.getElementById('operator');\n return phoneOperator.textContent;\n }\n\n applyListenerForCallMode() {}\n\n setSavedKeypadPage(page) {\n this.savedKeypadPage = page;\n }\n}\n\n/* ================== CALL MODE END================== */\n\n\n\n//# sourceURL=webpack:///./src/keypad/keypad.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"KeypadPage\", function() { return KeypadPage; });\n/* harmony import */ var _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/mobile-operators-identifiers */ \"./src/components/mobile-operators-identifiers.js\");\n\n\n/* ================== KEYPAD START================== */\n\nclass KeypadPage {\n constructor(store, accountName) {\n this.setStateKeypad = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'KEYPAD',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.callMode = new CallMode();\n }\n\n render() {\n const buttons = {\n ONE: '1',\n TWO: '2',\n THREE: '3',\n FOUR: '4',\n FIVE: '5',\n SIX: '6',\n SEVEN: '7',\n EIGHT: '8',\n NINE: '9',\n ZERO: '0',\n ASTERISK: '*',\n HASH: '#'\n };\n\n return (/*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n \n
\n
\n
\n\n
\n \n
\n
\n ${this.createButton(buttons.ONE)}\n ${this.createButton(buttons.TWO)}\n ${this.createButton(buttons.THREE)}\n
\n
\n ${this.createButton(buttons.FOUR)}\n ${this.createButton(buttons.FIVE)}\n ${this.createButton(buttons.SIX)}\n
\n
\n ${this.createButton(buttons.SEVEN)}\n ${this.createButton(buttons.EIGHT)}\n ${this.createButton(buttons.NINE)}\n
\n
\n ${this.createButton(buttons.ASTERISK)}\n ${this.createButton(buttons.ZERO)}\n ${this.createButton(buttons.HASH)}\n
\n
\n\n
\n
\n
\n \n\n
\n\n
\n `\n );\n }\n\n createButton(value) {\n const button = /*html*/`\n
${value}
\n `;\n\n return button;\n }\n\n applyListenerForKeypadPage() {\n\n /* ADD NUMBER */\n const keypadButtons = document.getElementById('wraper-for-buttons');\n const fieldForNumber = document.getElementById('number');\n const fieldForOperator = document.getElementById('operator');\n\n const toFormateNumberFieldForAdding = () => {\n const numbersFromField = fieldForNumber.textContent.replace(/\\D/gm, '');\n let finalConstructions = null;\n\n if (numbersFromField.length === 1) {\n finalConstructions = numbersFromField.replace(/(.{1})/g, '($1');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 3) {\n finalConstructions = numbersFromField.replace(/(.{3})/g, '($1)');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 4) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{1})/g, '($1) $2');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 7) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{1})/g, '($1) $2-$3');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 9) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{2})(.{1})/g, '($1) $2-$3-$4');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n };\n\n keypadButtons.addEventListener('click', e => {\n const TARGET_CLASS_NAME = e.target.className;\n\n if (TARGET_CLASS_NAME === 'number-btn') {\n const BUTTON_VALUE = e.target.textContent;\n fieldForNumber.textContent += BUTTON_VALUE;\n\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n }\n });\n\n /* REMOVE NUMBER */\n const deleteButton = document.getElementById('delete');\n\n deleteButton.addEventListener('click', e => {\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'delete' || BUTTON_ID_FROM_SVG === 'delete' || BUTTON_ID_FROM_PATH === 'delete') {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n\n return;\n }\n });\n\n /* TO CALL BUTTON */\n const mainWraper = document.getElementById('main-wraper');\n\n const toCallButton = document.getElementById('call-btn');\n toCallButton.addEventListener('click', () => {\n const ERROR_BLOCK = document.getElementById('error-block');\n\n if (fieldForNumber.textContent.length < 3) {\n ERROR_BLOCK.textContent = `ERROR you've typed incorrect number`;\n setTimeout(() => {\n ERROR_BLOCK.textContent = '';\n }, 3000);\n return;\n }\n\n const NUMBER_FOR_CALL_MODE = this.callMode.getNumber();\n const OPERATOR_FOR_CALL_MODE = this.callMode.getOperator();\n\n mainWraper.classList.add('call-mode');\n mainWraper.innerHTML = this.callMode.render(NUMBER_FOR_CALL_MODE, OPERATOR_FOR_CALL_MODE);\n this.callMode.applyListenerForCallMode();\n });\n\n /* WRITING NUMBER BY KEYBOARD */\n\n const keyCodes = {\n ONE: 49,\n TWO: 50,\n THREE: 51,\n FOUR: 52,\n FIVE: 53,\n SIX: 54,\n SEVEN: 55,\n EIGHT: 56,\n NINE: 57,\n ZERO: 48,\n ASTERISK: 42,\n HASH: 35,\n DELETE: 8\n };\n\n const SINGLE_TAPS = e => {\n\n if (e.keyCode === keyCodes.ONE) {\n const ONE = '1';\n fieldForNumber.textContent += ONE;\n }\n if (e.keyCode === keyCodes.TWO) {\n const TWO = '2';\n fieldForNumber.textContent += TWO;\n }\n if (e.keyCode === keyCodes.THREE) {\n const THREE = '3';\n fieldForNumber.textContent += THREE;\n }\n if (e.keyCode === keyCodes.FOUR) {\n const FOUR = '4';\n fieldForNumber.textContent += FOUR;\n }\n if (e.keyCode === keyCodes.FIVE) {\n const FIVE = '5';\n fieldForNumber.textContent += FIVE;\n }\n if (e.keyCode === keyCodes.SIX) {\n const SIX = '6';\n fieldForNumber.textContent += SIX;\n }\n if (e.keyCode === keyCodes.SEVEN) {\n const SEVEN = '7';\n fieldForNumber.textContent += SEVEN;\n }\n if (e.keyCode === keyCodes.EIGHT) {\n const EIGHT = '8';\n fieldForNumber.textContent += EIGHT;\n }\n if (e.keyCode === keyCodes.NINE) {\n const NINE = '9';\n fieldForNumber.textContent += NINE;\n }\n if (e.keyCode === keyCodes.ZERO) {\n const ZERO = '0';\n fieldForNumber.textContent += ZERO;\n }\n if (e.keyCode === keyCodes.HASH) {\n const HASH = '#';\n fieldForNumber.textContent += HASH;\n }\n if (e.keyCode === keyCodes.ASTERISK) {\n const ASTERISK = '*';\n fieldForNumber.textContent += ASTERISK;\n }\n\n /* IDENTIFICATION FUNCTIONAL */\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n };\n\n const DELETE_FUNCTIONAL = e => {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n\n if (e.keyCode === keyCodes.DELETE) {\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n return;\n }\n };\n\n window.addEventListener('keypress', SINGLE_TAPS);\n window.addEventListener('keydown', DELETE_FUNCTIONAL);\n }\n\n indentifyMobileOperator(firstThreeNumbers) {\n let operator;\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].kuivstar.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Kuivstar';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].life.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Life';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].vodafone.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Vodafone';\n }\n });\n\n return operator;\n }\n}\n\n/* ================== KEYPAD END================== */\n\n/* ================== CALL MODE START================== */\nclass CallMode {\n constructor() {}\n\n render(number, operator) {\n return (/*html*/`\n
\n
\n\n
\n ${number}\n ${operator}\n
\n\n
\n \n \n \n \n \n
\n\n
\n\n
\n\n
\n\n
\n\n
\n
\n \n
\n mute\n
\n\n
\n
\n \n
\n keypad\n
\n \n
\n
\n \n
\n volume\n
\n \n
\n\n
\n
\n
\n \n
\n add\n
\n \n
\n
\n \n
\n video\n
\n\n
\n
\n \n
\n contacts\n
\n
\n\n
\n\n
\n
\n \n
\n
\n\n
\n
\n `\n );\n }\n\n getNumber() {\n const phoneNumber = document.getElementById('number');\n return phoneNumber.textContent;\n }\n\n getOperator() {\n const phoneOperator = document.getElementById('operator');\n return phoneOperator.textContent;\n }\n\n applyListenerForCallMode() {}\n\n setSavedKeypadPage(page) {\n this.savedKeypadPage = page;\n }\n}\n\n/* ================== CALL MODE END================== */\n\n\n\n//# sourceURL=webpack:///./src/keypad/keypad.js?"); /***/ }), @@ -166,7 +178,19 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Url\", function() { return Url; });\nclass Url {\n constructor() {\n this.url = 'http://easycode-js.herokuapp.com/myba/users';\n }\n\n getUsersFromServer() {\n return (async () => {\n const data = await fetch(this.url);\n return this.users = await data.json();\n })();\n }\n\n obtainUsers() {\n this.getUsersFromServer();\n return this.users;\n }\n\n postUser(user) {\n const xhr = new XMLHttpRequest();\n xhr.open('POST', this.url, true);\n xhr.setRequestHeader('Content-type', 'application/json');\n xhr.send(JSON.stringify(user));\n }\n\n deleteUserById(id) {\n const xhr = new XMLHttpRequest();\n xhr.open('DELETE', `${this.url}/${id}`, true);\n xhr.setRequestHeader('Content-type', 'application/json');\n xhr.send();\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/url/url.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Url\", function() { return Url; });\nclass Url {\n constructor(accountName) {\n this.url = `https://easycode-js.herokuapp.com/${accountName}/users`;\n }\n\n getUsersFromServer() {\n return fetch(this.url);\n }\n\n postUser(user) {\n fetch(this.url, {\n method: 'POST',\n headers: {\n 'Content-type': 'application/json'\n },\n body: JSON.stringify(user)\n });\n }\n\n editUser(infoToEdit, id) {\n fetch(this.url + '/' + id, {\n method: 'PATCH',\n headers: {\n 'Content-type': 'application/json'\n },\n body: JSON.stringify(infoToEdit)\n });\n }\n\n deleteUserById(id) {\n fetch(this.url + '/' + id, {\n method: 'DELETE'\n });\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/url/url.js?"); + +/***/ }), + +/***/ "./src/user-page/user-page.js": +/*!************************************!*\ + !*** ./src/user-page/user-page.js ***! + \************************************/ +/*! exports provided: UserPage */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UserPage\", function() { return UserPage; });\n/* harmony import */ var _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../edit-user-page/edit-user-page */ \"./src/edit-user-page/edit-user-page.js\");\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\n\nclass UserPage {\n constructor(store, accountName) {\n this.setStateUserPage = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'USER_PAGE'\n };\n setState(initializeState);\n };\n\n this.editUserPage = new _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_0__[\"EditUserPage\"](store, accountName);\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_1__[\"Url\"](accountName);\n }\n\n render(user) {\n this.user = user;\n\n return (/*html*/`\n
\n\n
\n
\n User page\n
\n
\n\n
\n \n
\n \"avatar\"\n
\n\n
\n

Full Name:

\n

${user.fullName}

\n
\n
\n

Email:

\n

${user.email}

\n
\n
\n

Phone number:

\n

${user.phone}

\n
\n
\n

Birth date:

\n

${user.birthdate ? user.birthdate.slice(0, 10) : '__________'}

\n
\n
\n

Address:

\n

${user.address ? user.address : '__________'}

\n
\n
\n

Gender:

\n

${user.gender === \"M\" ? 'Male' : 'Female'}

\n
\n\n
\n \n \n
\n\n
\n\n
\n `\n );\n }\n\n applyListenersForUserPage() {\n const wraperForButtons = document.getElementById('usp-wraper-for-btns');\n\n const handlerForButtons = e => {\n if (e.target.textContent.trim() === 'Edit') {\n this.editUserPage.setStateEditUser();\n const EDIT_USER_PAGE = this.editUserPage.render(this.user);\n\n const MAIN_WRAPER = document.getElementById('main-wraper');\n MAIN_WRAPER.firstElementChild.outerHTML = EDIT_USER_PAGE;\n this.editUserPage.applyListenersForEditUserPage();\n }\n\n if (e.target.textContent.trim() === 'Delete') {\n const requestForDelete = confirm('Are you sure?');\n if (requestForDelete) {\n this.url.deleteUserById(this.user._id);\n\n const USER_PAGE = document.getElementById('user-info');\n USER_PAGE.innerHTML = /*html*/`

This user was deleted

`;\n }\n }\n };\n\n wraperForButtons.addEventListener('click', handlerForButtons);\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/user-page/user-page.js?"); /***/ }) diff --git a/phone-book/index.html b/phone-book/index.html index a4baae7..3be67fe 100644 --- a/phone-book/index.html +++ b/phone-book/index.html @@ -1,6 +1,7 @@ + Phone Book diff --git a/phone-book/src/components/users.js b/phone-book/src/components/users.js deleted file mode 100644 index 25774c2..0000000 --- a/phone-book/src/components/users.js +++ /dev/null @@ -1,6 +0,0 @@ -import {Url} from '../url/url'; - -const serverSide = new Url(); -const users = serverSide.getUsersFromServer(); - -export {users}; \ No newline at end of file From c53d5b513ec1865b6bb1edec3f88c8059fd3ceff Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Thu, 23 Aug 2018 21:52:40 +0300 Subject: [PATCH 13/14] fixes and router --- phone-book/build/bundle.js | 14 +++--- phone-book/src/add-user/add-user.js | 3 +- .../authorization-page/authorization-page.js | 7 +-- phone-book/src/contact/contact.js | 9 ++-- .../src/edit-user-page/edit-user-page.js | 10 ++-- phone-book/src/index.js | 47 ++++++++++++++++--- phone-book/src/keypad/keypad.js | 1 + phone-book/src/user-page/user-page.js | 12 +++-- 8 files changed, 73 insertions(+), 30 deletions(-) diff --git a/phone-book/build/bundle.js b/phone-book/build/bundle.js index f7426da..a43cfee 100644 --- a/phone-book/build/bundle.js +++ b/phone-book/build/bundle.js @@ -94,7 +94,7 @@ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AddUserPage\", function() { return AddUserPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nclass AddUserPage {\n constructor(store, accountName) {\n this.setStateContact = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'ADD USER',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"](accountName);\n }\n\n render() {\n return (/*html*/`\n
\n\n
\n
\n Add new user\n
\n
\n\n
\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n \n
\n \n \n ex: https://cloud-drive/photo123456.\n
\n\n
\n \n
\n \n
\n
\n\n
\n `\n );\n }\n\n applyListenersForAddUserPage() {\n\n const addUserForm = document.querySelector('form');\n\n const handlerForInputs = e => {\n if (e.target.name === 'fullName') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidFullName(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'email') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidEmail(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'phone') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'birthdate') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === 'address') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 0) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === \"avatarUrl\") {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidURL(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n };\n\n addUserForm.addEventListener('input', handlerForInputs);\n\n const inputs = [...addUserForm.elements].filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT');\n\n const handlerForSubmit = e => {\n e.preventDefault();\n\n const user = inputs.reduce((newUser, input) => {\n if (input.classList.contains('wrong')) {\n alert(`${input.name} is incorrect!`);\n return;\n };\n if (input.value.length !== 0 && input.name !== 'phone' && input.name !== 'gender' && input.name !== 'fullName') {\n newUser[input.name] = input.value;\n }\n if (input.value.length !== 0 && input.name === 'phone') {\n newUser[input.name] = input.value.replace(/(.{3})(.{3})(.{2})/g, '($1) $2-$3-');\n }\n if (input.name === 'gender') {\n input.value === \"Male\" ? newUser[input.name] = \"M\" : newUser[input.name] = \"F\";\n }\n if (input.value.length !== 0 && input.name === 'fullName') {\n const formatedFullName = input.value.split(' ').reduce((output, word, index) => {\n const splitedWord = word.toLowerCase().split('');\n const firstLetter = splitedWord[0].toUpperCase();\n splitedWord[0] = firstLetter;\n output += splitedWord.join('');\n\n if (index === 0) {\n output += ' ';\n }\n\n return output;\n }, '');\n\n newUser[input.name] = formatedFullName;\n }\n return newUser;\n }, {});\n\n if (user) {\n this.url.postUser(user);\n\n inputs.forEach(input => {\n if (input.tagName !== \"SELECT\") {\n input.value = \"\";\n input.classList.remove('correct');\n }\n });\n } else {\n alert('Something is incorrect!');\n }\n };\n\n addUserForm.addEventListener('submit', handlerForSubmit);\n }\n\n isValidFullName(value) {\n const splitedValue = value.split(' ');\n\n return splitedValue.length === 2 && splitedValue[0].length > 0 && splitedValue[1].length > 0;\n }\n\n isValidEmail(value) {\n const re = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n return re.test(String(value).toLowerCase());\n }\n\n isValidURL(value) {\n const re = new RegExp('^(https?:\\\\/\\\\/)?' + // protocol\n '((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.?)+[a-z]{2,}|' + // domain name\n '((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))' + // OR ip (v4) address\n '(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*' + // port and path\n '(\\\\?[;&a-z\\\\d%_.~+=-]*)?' + // query string\n '(\\\\#[-a-z\\\\d_]*)?$', 'i'); // fragment locator\n return re.test(String(value).toLowerCase());\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/add-user/add-user.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AddUserPage\", function() { return AddUserPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nclass AddUserPage {\n constructor(store, accountName) {\n this.setStateAddUser = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'ADD USER',\n activePage: this.render()\n };\n setState(initializeState);\n window.history.pushState(initializeState.activePage, initializeState.stateName);\n };\n\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"](accountName);\n }\n\n render() {\n return (/*html*/`\n
\n\n
\n
\n Add new user\n
\n
\n\n
\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n \n
\n \n \n ex: https://cloud-drive/photo123456.\n
\n\n
\n \n
\n \n
\n
\n\n
\n `\n );\n }\n\n applyListenersForAddUserPage() {\n\n const addUserForm = document.querySelector('form');\n\n const handlerForInputs = e => {\n if (e.target.name === 'fullName') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidFullName(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'email') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidEmail(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'phone') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'birthdate') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === 'address') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 0) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === \"avatarUrl\") {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidURL(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n };\n\n addUserForm.addEventListener('input', handlerForInputs);\n\n const inputs = [...addUserForm.elements].filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT');\n\n const handlerForSubmit = e => {\n e.preventDefault();\n\n const user = inputs.reduce((newUser, input) => {\n if (input.classList.contains('wrong')) {\n alert(`${input.name} is incorrect!`);\n return;\n };\n if (input.value.length !== 0 && input.name !== 'phone' && input.name !== 'gender' && input.name !== 'fullName') {\n newUser[input.name] = input.value;\n }\n if (input.value.length !== 0 && input.name === 'phone') {\n newUser[input.name] = input.value.replace(/(.{3})(.{3})(.{2})/g, '($1) $2-$3-');\n }\n if (input.name === 'gender') {\n input.value === \"Male\" ? newUser[input.name] = \"M\" : newUser[input.name] = \"F\";\n }\n if (input.value.length !== 0 && input.name === 'fullName') {\n const formatedFullName = input.value.split(' ').reduce((output, word, index) => {\n const splitedWord = word.toLowerCase().split('');\n const firstLetter = splitedWord[0].toUpperCase();\n splitedWord[0] = firstLetter;\n output += splitedWord.join('');\n\n if (index === 0) {\n output += ' ';\n }\n\n return output;\n }, '');\n\n newUser[input.name] = formatedFullName;\n }\n return newUser;\n }, {});\n\n if (user) {\n this.url.postUser(user);\n\n inputs.forEach(input => {\n if (input.tagName !== \"SELECT\") {\n input.value = \"\";\n input.classList.remove('correct');\n }\n });\n } else {\n alert('Something is incorrect!');\n }\n };\n\n addUserForm.addEventListener('submit', handlerForSubmit);\n }\n\n isValidFullName(value) {\n const splitedValue = value.split(' ');\n\n return splitedValue.length === 2 && splitedValue[0].length > 0 && splitedValue[1].length > 0;\n }\n\n isValidEmail(value) {\n const re = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n return re.test(String(value).toLowerCase());\n }\n\n isValidURL(value) {\n const re = new RegExp('^(https?:\\\\/\\\\/)?' + // protocol\n '((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.?)+[a-z]{2,}|' + // domain name\n '((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))' + // OR ip (v4) address\n '(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*' + // port and path\n '(\\\\?[;&a-z\\\\d%_.~+=-]*)?' + // query string\n '(\\\\#[-a-z\\\\d_]*)?$', 'i'); // fragment locator\n return re.test(String(value).toLowerCase());\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/add-user/add-user.js?"); /***/ }), @@ -106,7 +106,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AuthorizationPage\", function() { return AuthorizationPage; });\nclass AuthorizationPage {\n constructor() {\n this.setStateAuthorization = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'AUTHORIZATION',\n activePage: this.render()\n };\n setState(initializeState);\n };\n }\n\n render() {\n return (/*html*/`\n
\n

Authorization

\n
\n \n \n
\n
\n `\n );\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/authorization-page/authorization-page.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AuthorizationPage\", function() { return AuthorizationPage; });\nclass AuthorizationPage {\n constructor(store) {\n this.setStateAuthorization = listeners => {\n const { setState } = store;\n const initializeState = {\n stateName: 'AUTHORIZATION',\n activePage: this.render()\n };\n setState(initializeState);\n window.history.pushState(initializeState.activePage, initializeState.stateName);\n };\n }\n\n render() {\n return (/*html*/`\n
\n

Authorization

\n
\n \n \n
\n
\n `\n );\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/authorization-page/authorization-page.js?"); /***/ }), @@ -130,7 +130,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ContactPage\", function() { return ContactPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n/* harmony import */ var _user_page_user_page__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../user-page/user-page */ \"./src/user-page/user-page.js\");\n\n\n\n/* ================== CONTACT START================== */\n\nclass ContactPage {\n constructor(store, accountName) {\n this.setStateContact = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'CONTACT',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"](accountName);\n this.userPage = new _user_page_user_page__WEBPACK_IMPORTED_MODULE_1__[\"UserPage\"](store, accountName);\n }\n\n render() {\n const contactTempalte = /*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n
\n\n
\n \n\n \n \n \n \n \n \n \n\n \n \n \n\n
NameLast NameEmail
\n
\n
\n `;\n\n return contactTempalte;\n }\n\n contactListComponent(userList) {\n return userList.reduce((listStructure, user) => {\n const splitedFullName = user.fullName.split(' ');\n const userFirstName = splitedFullName[0];\n const userLastName = splitedFullName[1];\n const userEmail = user.email;\n const id = user._id;\n\n const userComponent = /*html*/`\n \n ${userFirstName} \n ${userLastName} \n ${userEmail} \n \n `;\n\n listStructure += userComponent;\n return listStructure;\n }, ``);\n }\n\n renderUsers() {\n this.url.getUsersFromServer().then(data => {\n return data.json();\n }).then(users => {\n this.users = users;\n const listStructure = this.contactListComponent(users);\n const listOfContacts = document.getElementById('list-of-contacts');\n listOfContacts.innerHTML = listStructure;\n });\n }\n\n applyListenerForContactPage() {\n const wraperForTh = document.getElementById('wraper-for-th');\n wraperForTh.addEventListener('click', e => {\n const TH_ELEM_CONTAINS = e.target.textContent.trim();\n const PREDICT_TEXT_CONTENT = {\n firstName: 'Name',\n lastName: 'Last Name',\n email: 'Email'\n };\n\n const listOfContacts = document.getElementById('list-of-contacts');\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.firstName) {\n const firstName = 0;\n const sortedListByFirsName = this.mergeSort(this.users, firstName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByFirsName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.lastName) {\n const lastName = 1;\n const sortedListByLastName = this.mergeSort(this.users, lastName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByLastName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.email) {\n const sortedListByEmail = this.sortUsersByValue('email', this.users);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByEmail);\n return;\n }\n });\n\n /* SORT USERS BY INPUTED LETTERS OF NAME */\n const contactSearchField = document.querySelector('#search');\n\n contactSearchField.addEventListener('input', () => {\n const VALUE = contactSearchField.value;\n const filteredUsers = this.filterUsersByInputValueByName(VALUE);\n const listOfContacts = document.getElementById('list-of-contacts');\n\n filteredUsers.length === 0 ? listOfContacts.innerHTML = /*html*/`

No such users

` : listOfContacts.innerHTML = this.contactListComponent(filteredUsers);\n });\n\n /* DEFINE USER */\n\n const listOfContacts = document.getElementById('list-of-contacts');\n const handlerForListOfContacts = e => {\n if (e.target.parentElement.tagName === \"TR\") {\n const id = e.target.parentElement.id;\n const user = this.users.filter(user => user._id === id)[0];\n this.userPage.setStateUserPage();\n const userPage = this.userPage.render(user);\n\n const MAIN_WRAPER = document.getElementById('main-wraper');\n MAIN_WRAPER.firstElementChild.outerHTML = userPage;\n this.userPage.applyListenersForUserPage();\n }\n };\n\n listOfContacts.addEventListener('click', handlerForListOfContacts);\n }\n\n sortUsersByValue(key, users) {\n const sortFunction = function (value, nextValue) {\n if (value[key] > nextValue[key]) return 1;\n if (value[key] < nextValue[key]) return -1;\n };\n\n return [...users].sort(sortFunction);\n }\n\n mergeSort(arr, index) {\n\n const len = arr.length;\n if (len < 2) return arr;\n const mid = Math.floor(len / 2),\n left = arr.slice(0, mid),\n right = arr.slice(mid);\n\n return this.merge(this.mergeSort(left, index), this.mergeSort(right, index), index);\n }\n\n merge(left, right, index) {\n let result = [],\n lLen = left.length,\n rLen = right.length,\n l = 0,\n r = 0;\n while (l < lLen && r < rLen) {\n const leftWord = left[l].fullName.split(' ')[index];\n const rightWord = right[r].fullName.split(' ')[index];\n if (leftWord < rightWord) {\n result.push(left[l++]);\n } else {\n result.push(right[r++]);\n }\n }\n\n return result.concat(left.slice(l)).concat(right.slice(r));\n }\n\n filterUsersByInputValueByName(inputValue) {\n return this.users.reduce((newUsers, user) => {\n const firstName = user.fullName.split(' ')[0].toLowerCase();\n\n const comparedPartOfName = firstName.slice(0, inputValue.length);\n\n if (inputValue.toLowerCase() === comparedPartOfName) {\n newUsers.push(user);\n }\n\n return newUsers;\n }, []);\n }\n}\n\n/* ================== CONTACT END================== */\n\n\n\n//# sourceURL=webpack:///./src/contact/contact.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ContactPage\", function() { return ContactPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n/* harmony import */ var _user_page_user_page__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../user-page/user-page */ \"./src/user-page/user-page.js\");\n\n\n\n/* ================== CONTACT START================== */\n\nclass ContactPage {\n constructor(store, accountName) {\n this.setStateContact = () => {\n const { setState, getState } = store;\n const initializeState = {\n stateName: 'CONTACT',\n activePage: this.render()\n };\n setState(initializeState);\n window.history.pushState(initializeState.activePage, initializeState.stateName);\n };\n\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"](accountName);\n this.userPage = new _user_page_user_page__WEBPACK_IMPORTED_MODULE_1__[\"UserPage\"](store, accountName);\n }\n\n render() {\n const contactTempalte = /*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n
\n\n
\n \n\n \n \n \n \n \n \n \n\n \n \n \n\n
NameLast NameEmail
\n
\n
\n `;\n\n return contactTempalte;\n }\n\n contactListComponent(userList) {\n return userList.reduce((listStructure, user) => {\n const splitedFullName = user.fullName.split(' ');\n const userFirstName = splitedFullName[0];\n const userLastName = splitedFullName[1];\n const userEmail = user.email;\n const id = user._id;\n\n const userComponent = /*html*/`\n \n ${userFirstName} \n ${userLastName} \n ${userEmail} \n \n `;\n\n listStructure += userComponent;\n return listStructure;\n }, ``);\n }\n\n renderUsers() {\n this.url.getUsersFromServer().then(data => {\n return data.json();\n }).then(users => {\n this.users = users;\n const listStructure = this.contactListComponent(users);\n const listOfContacts = document.getElementById('list-of-contacts');\n listOfContacts.innerHTML = listStructure;\n });\n }\n\n applyListenerForContactPage() {\n const wraperForTh = document.getElementById('wraper-for-th');\n wraperForTh.addEventListener('click', e => {\n const TH_ELEM_CONTAINS = e.target.textContent.trim();\n const PREDICT_TEXT_CONTENT = {\n firstName: 'Name',\n lastName: 'Last Name',\n email: 'Email'\n };\n\n const listOfContacts = document.getElementById('list-of-contacts');\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.firstName) {\n const firstName = 0;\n const sortedListByFirsName = this.mergeSort(this.users, firstName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByFirsName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.lastName) {\n const lastName = 1;\n const sortedListByLastName = this.mergeSort(this.users, lastName);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByLastName);\n return;\n }\n\n if (TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.email) {\n const sortedListByEmail = this.sortUsersByValue('email', this.users);\n listOfContacts.innerHTML = this.contactListComponent(sortedListByEmail);\n return;\n }\n });\n\n /* SORT USERS BY INPUTED LETTERS OF NAME */\n const contactSearchField = document.querySelector('#search');\n\n contactSearchField.addEventListener('input', () => {\n const VALUE = contactSearchField.value;\n const filteredUsers = this.filterUsersByInputValueByName(VALUE);\n const listOfContacts = document.getElementById('list-of-contacts');\n\n filteredUsers.length === 0 ? listOfContacts.innerHTML = /*html*/`

No such users

` : listOfContacts.innerHTML = this.contactListComponent(filteredUsers);\n });\n\n /* DEFINE USER */\n\n const listOfContacts = document.getElementById('list-of-contacts');\n const handlerForListOfContacts = e => {\n if (e.target.parentElement.tagName === \"TR\") {\n const id = e.target.parentElement.id;\n const user = this.users.filter(user => user._id === id)[0];\n this.userPage.setStateUserPage(user);\n const userPage = this.userPage.render(user);\n\n const MAIN_WRAPER = document.getElementById('main-wraper');\n MAIN_WRAPER.firstElementChild.outerHTML = userPage;\n this.userPage.applyListenersForUserPage();\n\n window.user = user;\n }\n };\n\n listOfContacts.addEventListener('click', handlerForListOfContacts);\n }\n\n sortUsersByValue(key, users) {\n const sortFunction = function (value, nextValue) {\n if (value[key] > nextValue[key]) return 1;\n if (value[key] < nextValue[key]) return -1;\n };\n\n return [...users].sort(sortFunction);\n }\n\n mergeSort(arr, index) {\n\n const len = arr.length;\n if (len < 2) return arr;\n const mid = Math.floor(len / 2),\n left = arr.slice(0, mid),\n right = arr.slice(mid);\n\n return this.merge(this.mergeSort(left, index), this.mergeSort(right, index), index);\n }\n\n merge(left, right, index) {\n let result = [],\n lLen = left.length,\n rLen = right.length,\n l = 0,\n r = 0;\n while (l < lLen && r < rLen) {\n const leftWord = left[l].fullName.split(' ')[index];\n const rightWord = right[r].fullName.split(' ')[index];\n if (leftWord < rightWord) {\n result.push(left[l++]);\n } else {\n result.push(right[r++]);\n }\n }\n\n return result.concat(left.slice(l)).concat(right.slice(r));\n }\n\n filterUsersByInputValueByName(inputValue) {\n return this.users.reduce((newUsers, user) => {\n const firstName = user.fullName.split(' ')[0].toLowerCase();\n\n const comparedPartOfName = firstName.slice(0, inputValue.length);\n\n if (inputValue.toLowerCase() === comparedPartOfName) {\n newUsers.push(user);\n }\n\n return newUsers;\n }, []);\n }\n}\n\n/* ================== CONTACT END================== */\n\n\n\n//# sourceURL=webpack:///./src/contact/contact.js?"); /***/ }), @@ -142,7 +142,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"EditUserPage\", function() { return EditUserPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nclass EditUserPage {\n constructor(store, accountName) {\n this.setStateEditUser = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'EDIT USER'\n };\n setState(initializeState);\n };\n\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"](accountName);\n }\n\n render(user) {\n this.user = user;\n\n return (/*html*/`\n
\n\n
\n
\n Edit user ${user.fullName}\n
\n
\n\n
\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n Length of your phone number should be more than 9\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n \n
\n \n \n ex: https://cloud-drive/photo123456.\n
\n\n
\n \n
\n \n
\n
\n\n
\n `\n );\n }\n\n applyListenersForEditUserPage() {\n\n const editUserForm = document.querySelector('form');\n\n const handlerForInputs = e => {\n if (e.target.name === 'fullName') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidFullName(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'email') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidEmail(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'phone') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'birthdate') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === 'address') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 0) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === \"avatarUrl\") {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidURL(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n };\n\n editUserForm.addEventListener('input', handlerForInputs);\n const inputs = [...editUserForm.elements].filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT');\n\n const handlerForSubmit = e => {\n e.preventDefault();\n\n const infoToEdit = inputs.reduce((editedUser, input) => {\n if (input.classList.contains('wrong')) {\n alert(`${input.name} is incorrect!`);\n return;\n };\n if (input.value.length !== 0 && input.name !== 'phone' && input.name !== 'gender' && input.name !== 'fullName') {\n editedUser[input.name] = input.value;\n }\n if (input.value.length !== 0 && input.name === 'phone') {\n editedUser[input.name] = input.value.replace(/(.{3})(.{3})(.{2})/g, '($1) $2-$3-');\n }\n if (input.name === 'gender') {\n input.value === \"Male\" ? editedUser[input.name] = \"M\" : editedUser[input.name] = \"F\";\n }\n if (input.value.length !== 0 && input.name === 'fullName') {\n const formatedFullName = input.value.split(' ').reduce((output, word, index) => {\n const splitedWord = word.toLowerCase().split('');\n const firstLetter = splitedWord[0].toUpperCase();\n splitedWord[0] = firstLetter;\n output += splitedWord.join('');\n\n if (index === 0) {\n output += ' ';\n }\n\n return output;\n }, '');\n\n editedUser[input.name] = formatedFullName;\n }\n return editedUser;\n }, {});\n\n if (infoToEdit) {\n this.url.editUser(infoToEdit, this.user._id);\n\n inputs.forEach(input => {\n if (input.tagName !== \"SELECT\") {\n input.value = \"\";\n input.classList.remove('correct');\n }\n });\n } else {\n alert('Something is incorrect!');\n }\n };\n\n editUserForm.addEventListener('submit', handlerForSubmit);\n }\n\n isValidFullName(value) {\n const splitedValue = value.split(' ');\n\n return splitedValue.length === 2 && splitedValue[0].length > 0 && splitedValue[1].length > 0;\n }\n\n isValidEmail(value) {\n const re = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n return re.test(String(value).toLowerCase());\n }\n\n isValidURL(value) {\n const re = new RegExp('^(https?:\\\\/\\\\/)?' + // protocol\n '((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.?)+[a-z]{2,}|' + // domain name\n '((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))' + // OR ip (v4) address\n '(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*' + // port and path\n '(\\\\?[;&a-z\\\\d%_.~+=-]*)?' + // query string\n '(\\\\#[-a-z\\\\d_]*)?$', 'i'); // fragment locator\n return re.test(String(value).toLowerCase());\n }\n\n}\n\n\n\n//# sourceURL=webpack:///./src/edit-user-page/edit-user-page.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"EditUserPage\", function() { return EditUserPage; });\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\nclass EditUserPage {\n constructor(store, accountName) {\n this.setStateEditUser = user => {\n const { setState, getState } = store;\n const initializeState = {\n stateName: 'EDIT USER',\n activePage: this.render(user)\n };\n setState(initializeState);\n window.history.pushState(initializeState.activePage, initializeState.stateName);\n };\n\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_0__[\"Url\"](accountName);\n }\n\n render(user) {\n this.user = user;\n\n return (/*html*/`\n
\n\n
\n
\n Edit user ${user.fullName}\n
\n
\n\n
\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n Length of your phone number should be more than 9\n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n \n
\n \n \n ex: https://cloud-drive/photo123456.\n
\n\n
\n \n
\n \n
\n
\n\n
\n `\n );\n }\n\n applyListenersForEditUserPage() {\n\n const editUserForm = document.querySelector('form');\n\n const handlerForInputs = e => {\n if (e.target.name === 'fullName') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidFullName(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'email') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidEmail(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'phone') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n\n if (e.target.name === 'birthdate') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 9) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === 'address') {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('correct');\n return;\n }\n\n if (VALUE.length > 0) {\n e.target.classList.add('correct');\n }\n }\n\n if (e.target.name === \"avatarUrl\") {\n const VALUE = e.target.value;\n\n if (VALUE.length === 0) {\n e.target.classList.remove('wrong');\n e.target.classList.remove('correct');\n return;\n }\n\n if (this.isValidURL(VALUE)) {\n e.target.classList.add('correct');\n e.target.classList.remove('wrong');\n } else {\n e.target.classList.add('wrong');\n e.target.classList.remove('correct');\n }\n }\n };\n\n editUserForm.addEventListener('input', handlerForInputs);\n const inputs = [...editUserForm.elements].filter(elem => elem.tagName === 'INPUT' || elem.tagName === 'SELECT');\n\n const handlerForSubmit = e => {\n e.preventDefault();\n\n const infoToEdit = inputs.reduce((editedUser, input) => {\n if (input.classList.contains('wrong')) {\n alert(`${input.name} is incorrect!`);\n return;\n };\n if (input.value.length !== 0 && input.name !== 'phone' && input.name !== 'gender' && input.name !== 'fullName') {\n editedUser[input.name] = input.value;\n }\n if (input.value.length !== 0 && input.name === 'phone') {\n editedUser[input.name] = input.value.replace(/(.{3})(.{3})(.{2})/g, '($1) $2-$3-');\n }\n if (input.name === 'gender') {\n input.value === \"Male\" ? editedUser[input.name] = \"M\" : editedUser[input.name] = \"F\";\n }\n if (input.value.length !== 0 && input.name === 'fullName') {\n const formatedFullName = input.value.split(' ').reduce((output, word, index) => {\n const splitedWord = word.toLowerCase().split('');\n const firstLetter = splitedWord[0].toUpperCase();\n splitedWord[0] = firstLetter;\n output += splitedWord.join('');\n\n if (index === 0) {\n output += ' ';\n }\n\n return output;\n }, '');\n\n editedUser[input.name] = formatedFullName;\n }\n return editedUser;\n }, {});\n\n if (infoToEdit) {\n this.url.editUser(infoToEdit, this.user._id || window.user);\n\n inputs.forEach(input => {\n if (input.tagName !== \"SELECT\") {\n input.value = \"\";\n input.classList.remove('correct');\n }\n });\n } else {\n alert('Something is incorrect!');\n }\n };\n\n editUserForm.addEventListener('submit', handlerForSubmit);\n }\n\n isValidFullName(value) {\n const splitedValue = value.split(' ');\n\n return splitedValue.length === 2 && splitedValue[0].length > 0 && splitedValue[1].length > 0;\n }\n\n isValidEmail(value) {\n const re = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n return re.test(String(value).toLowerCase());\n }\n\n isValidURL(value) {\n const re = new RegExp('^(https?:\\\\/\\\\/)?' + // protocol\n '((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.?)+[a-z]{2,}|' + // domain name\n '((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))' + // OR ip (v4) address\n '(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*' + // port and path\n '(\\\\?[;&a-z\\\\d%_.~+=-]*)?' + // query string\n '(\\\\#[-a-z\\\\d_]*)?$', 'i'); // fragment locator\n return re.test(String(value).toLowerCase());\n }\n\n}\n\n\n\n//# sourceURL=webpack:///./src/edit-user-page/edit-user-page.js?"); /***/ }), @@ -154,7 +154,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./authorization-page/authorization-page */ \"./src/authorization-page/authorization-page.js\");\n/* harmony import */ var _contact_contact__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./contact/contact */ \"./src/contact/contact.js\");\n/* harmony import */ var _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./keypad/keypad */ \"./src/keypad/keypad.js\");\n/* harmony import */ var _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./add-user/add-user */ \"./src/add-user/add-user.js\");\n\n\n\n\n\nclass App {\n constructor() {\n this.store = this.createStore();\n this.authorizationPage = new _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__[\"AuthorizationPage\"]();\n this.renderAuthorizationPage();\n }\n\n createStore() {\n let state;\n\n return {\n getState() {\n return state;\n },\n setState(newState) {\n state = newState;\n }\n };\n }\n\n reducer(action) {\n const currentState = this.store.getState();\n const mainWraper = document.getElementById('main-wraper');\n const switchBetweenPages = () => {\n mainWraper.firstElementChild.outerHTML = currentState.activePage;\n };\n\n if (action.type === 'MOVE_TO_KEYPAD_PAGE') {\n this.pages.keypad.setStateKeypad();\n switchBetweenPages();\n this.pages.keypad.applyListenerForKeypadPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_CONTACT_PAGE') {\n this.pages.contacts.setStateContact();\n switchBetweenPages();\n this.pages.contacts.renderUsers();\n this.pages.contacts.applyListenerForContactPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_ADD_USER_PAGE') {\n this.pages.addUser.setStateContact();\n switchBetweenPages();\n this.pages.addUser.applyListenersForAddUserPage();\n return;\n }\n }\n\n renderAuthorizationPage() {\n const authorizationPage = this.authorizationPage.render();\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = authorizationPage;\n this.applyListenerForAuthorizationPage();\n }\n\n applyListenerForAuthorizationPage() {\n const input = document.querySelector('.au-input');\n const logInButton = document.getElementById('log-in');\n const switchBetweenPages = () => {\n this.accountName = input.value;\n\n this.pages = {\n 'contacts': new _contact_contact__WEBPACK_IMPORTED_MODULE_1__[\"ContactPage\"](this.store, this.accountName),\n 'keypad': new _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__[\"KeypadPage\"](this.store, this.accountName),\n 'addUser': new _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__[\"AddUserPage\"](this.store, this.accountName),\n 'footer': new FooterNavigationBar()\n };\n\n this.pages.contacts.setStateContact();\n this.render();\n this.pages.contacts.applyListenerForContactPage();\n this.applyListenerForNavigation();\n };\n\n const handlerForLogInBtn = () => {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n };\n\n const handlerForLogInInput = e => {\n if (e.keyCode === 13) {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n }\n };\n\n logInButton.addEventListener('click', handlerForLogInBtn);\n input.addEventListener('keydown', handlerForLogInInput);\n }\n\n render() {\n const currentState = this.store.getState();\n const FOOTER = this.pages.footer.render();\n\n const appTemplate = /*html*/`\n
\n ${currentState.activePage}\n ${FOOTER}\n
\n `;\n\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = appTemplate;\n\n this.pages.contacts.renderUsers();\n }\n\n applyListenerForNavigation() {\n\n const _MOVE_TO_KEYPAD_PAGE = {\n type: 'MOVE_TO_KEYPAD_PAGE'\n };\n\n const _MOVE_TO_CONTACT_PAGE = {\n type: 'MOVE_TO_CONTACT_PAGE'\n };\n\n const _MOVE_TO_ADD_USER_PAGE = {\n type: 'MOVE_TO_ADD_USER_PAGE'\n };\n\n const wraperForFooter = document.getElementById('wraper-for-footer');\n wraperForFooter.addEventListener('click', e => {\n const currentState = this.store.getState();\n\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'to-keypad-page' || BUTTON_ID_FROM_SVG === 'to-keypad-page' || BUTTON_ID_FROM_PATH === 'to-keypad-page') {\n\n if (currentState.stateName !== 'KEYPAD') {\n this.pages.keypad.setStateKeypad();\n return this.reducer(_MOVE_TO_KEYPAD_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-contact-page' || BUTTON_ID_FROM_SVG === 'to-contact-page' || BUTTON_ID_FROM_PATH === 'to-contact-page') {\n\n if (currentState.stateName !== 'CONTACT') {\n this.pages.contacts.setStateContact();\n return this.reducer(_MOVE_TO_CONTACT_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-addUser-page' || BUTTON_ID_FROM_SVG === 'to-addUser-page' || BUTTON_ID_FROM_PATH === 'to-addUser-page') {\n\n if (currentState.stateName !== 'ADD USER') {\n this.pages.addUser.setStateContact();\n return this.reducer(_MOVE_TO_ADD_USER_PAGE);\n }\n return;\n }\n });\n }\n}\n\n/* ================== FOOTER START================== */\n\nclass FooterNavigationBar {\n constructor() {\n this.icons = {\n contactIcon: {\n id: 'to-contact-page',\n class: 'far fa-address-book'\n },\n keypadIcon: {\n id: 'to-keypad-page',\n class: 'fas fa-tty'\n },\n addUserIcon: {\n id: 'to-addUser-page',\n class: 'fas fa-user-plus'\n }\n };\n }\n\n render() {\n const navigationBar = /*html*/`\n
\n
\n ${this.createIcon(this.icons.contactIcon)}\n ${this.createIcon(this.icons.keypadIcon)}\n ${this.createIcon(this.icons.addUserIcon)}\n
\n
\n `;\n\n return navigationBar;\n }\n\n createIcon(iconPattern) {\n const ID = iconPattern.id;\n const CLASS = iconPattern.class;\n\n const icon = /*html*/`\n
\n \n
\n `;\n\n return icon;\n }\n\n}\n\n/* ================== FOOTER END================== */\n\nconst APPLICATION = new App();\n\n//# sourceURL=webpack:///./src/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./authorization-page/authorization-page */ \"./src/authorization-page/authorization-page.js\");\n/* harmony import */ var _contact_contact__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./contact/contact */ \"./src/contact/contact.js\");\n/* harmony import */ var _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./keypad/keypad */ \"./src/keypad/keypad.js\");\n/* harmony import */ var _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./add-user/add-user */ \"./src/add-user/add-user.js\");\n/* harmony import */ var _user_page_user_page__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./user-page/user-page */ \"./src/user-page/user-page.js\");\n/* harmony import */ var _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./edit-user-page/edit-user-page */ \"./src/edit-user-page/edit-user-page.js\");\n\n\n\n\n\n\n\nclass App {\n constructor() {\n this.store = this.createStore();\n this.authorizationPage = new _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__[\"AuthorizationPage\"](this.store);\n this.authorizationPage.setStateAuthorization(this.applyListenerForAuthorizationPage);\n this.renderAuthorizationPage();\n }\n\n createStore() {\n let state;\n\n return {\n getState() {\n return state;\n },\n setState(newState) {\n state = newState;\n }\n };\n }\n\n reducer(action) {\n const currentState = this.store.getState();\n const mainWraper = document.getElementById('main-wraper');\n const switchBetweenPages = () => {\n mainWraper.firstElementChild.outerHTML = currentState.activePage;\n };\n\n if (action.type === 'MOVE_TO_KEYPAD_PAGE') {\n switchBetweenPages();\n this.pages.keypad.applyListenerForKeypadPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_CONTACT_PAGE') {\n switchBetweenPages();\n this.pages.contacts.renderUsers();\n this.pages.contacts.applyListenerForContactPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_ADD_USER_PAGE') {\n switchBetweenPages();\n this.pages.addUser.applyListenersForAddUserPage();\n return;\n }\n }\n\n renderAuthorizationPage() {\n const authorizationPage = this.authorizationPage.render();\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = authorizationPage;\n this.applyListenerForAuthorizationPage();\n }\n\n applyListenerForAuthorizationPage() {\n const input = document.querySelector('.au-input');\n const logInButton = document.getElementById('log-in');\n const switchBetweenPages = () => {\n this.accountName = input.value;\n\n this.pages = {\n 'contacts': new _contact_contact__WEBPACK_IMPORTED_MODULE_1__[\"ContactPage\"](this.store, this.accountName),\n 'keypad': new _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__[\"KeypadPage\"](this.store, this.accountName),\n 'addUser': new _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__[\"AddUserPage\"](this.store, this.accountName),\n 'footer': new FooterNavigationBar(),\n 'userPage': new _user_page_user_page__WEBPACK_IMPORTED_MODULE_4__[\"UserPage\"](this.store, this.accountName),\n 'editUserPage': new _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_5__[\"EditUserPage\"](this.store, this.accountName)\n };\n\n this.pages.contacts.setStateContact();\n this.render();\n this.pages.contacts.applyListenerForContactPage();\n this.applyListenerForNavigation();\n };\n\n const handlerForLogInBtn = () => {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n };\n\n const handlerForLogInInput = e => {\n if (e.keyCode === 13) {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n }\n };\n\n logInButton.addEventListener('click', handlerForLogInBtn);\n input.addEventListener('keydown', handlerForLogInInput);\n }\n\n render() {\n const currentState = this.store.getState();\n const FOOTER = this.pages.footer.render();\n\n const appTemplate = /*html*/`\n
\n ${currentState.activePage}\n ${FOOTER}\n
\n `;\n\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = appTemplate;\n\n if (currentState.stateName === 'CONTACT') {\n this.pages.contacts.renderUsers();\n };\n }\n\n updateView(state) {\n const mainWraper = document.getElementById('main-wraper');\n\n mainWraper.firstElementChild.outerHTML = state;\n }\n\n applyListenerForNavigation() {\n\n const _MOVE_TO_KEYPAD_PAGE = {\n type: 'MOVE_TO_KEYPAD_PAGE'\n };\n\n const _MOVE_TO_CONTACT_PAGE = {\n type: 'MOVE_TO_CONTACT_PAGE'\n };\n\n const _MOVE_TO_ADD_USER_PAGE = {\n type: 'MOVE_TO_ADD_USER_PAGE'\n };\n\n const wraperForFooter = document.getElementById('wraper-for-footer');\n wraperForFooter.addEventListener('click', e => {\n const currentState = this.store.getState();\n\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'to-keypad-page' || BUTTON_ID_FROM_SVG === 'to-keypad-page' || BUTTON_ID_FROM_PATH === 'to-keypad-page') {\n\n if (currentState.stateName !== 'KEYPAD') {\n this.pages.keypad.setStateKeypad();\n return this.reducer(_MOVE_TO_KEYPAD_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-contact-page' || BUTTON_ID_FROM_SVG === 'to-contact-page' || BUTTON_ID_FROM_PATH === 'to-contact-page') {\n\n if (currentState.stateName !== 'CONTACT') {\n this.pages.contacts.setStateContact();\n return this.reducer(_MOVE_TO_CONTACT_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-addUser-page' || BUTTON_ID_FROM_SVG === 'to-addUser-page' || BUTTON_ID_FROM_PATH === 'to-addUser-page') {\n\n if (currentState.stateName !== 'ADD USER') {\n this.pages.addUser.setStateAddUser();\n return this.reducer(_MOVE_TO_ADD_USER_PAGE);\n }\n return;\n }\n });\n\n window.addEventListener('popstate', e => {\n this.updateView(e.state);\n\n if (/id=\"user-page\"/.test(e.state)) {\n this.pages.userPage.applyListenersForUserPage();\n }\n\n if (/id=\"contact-wraper\"/.test(e.state)) {\n this.pages.contacts.renderUsers();\n this.pages.contacts.applyListenerForContactPage();\n }\n\n if (/id=\"edit-user-page\"/.test(e.state)) {\n this.pages.editUserPage.applyListenersForEditUserPage();\n }\n\n if (/id=\"add-user-page\"/.test(e.state)) {\n this.pages.addUser.applyListenersForAddUserPage();\n }\n\n if (/id=\"keypad-wraper\"/.test(e.state)) {\n this.pages.keypad.applyListenerForKeypadPage();\n }\n });\n }\n}\n\n/* ================== FOOTER START================== */\n\nclass FooterNavigationBar {\n constructor() {\n this.icons = {\n contactIcon: {\n id: 'to-contact-page',\n class: 'far fa-address-book'\n },\n keypadIcon: {\n id: 'to-keypad-page',\n class: 'fas fa-tty'\n },\n addUserIcon: {\n id: 'to-addUser-page',\n class: 'fas fa-user-plus'\n }\n };\n }\n\n render() {\n const navigationBar = /*html*/`\n
\n
\n ${this.createIcon(this.icons.contactIcon)}\n ${this.createIcon(this.icons.keypadIcon)}\n ${this.createIcon(this.icons.addUserIcon)}\n
\n
\n `;\n\n return navigationBar;\n }\n\n createIcon(iconPattern) {\n const ID = iconPattern.id;\n const CLASS = iconPattern.class;\n\n const icon = /*html*/`\n
\n \n
\n `;\n\n return icon;\n }\n\n}\n\n/* ================== FOOTER END================== */\n\nconst APPLICATION = new App();\n\n//# sourceURL=webpack:///./src/index.js?"); /***/ }), @@ -166,7 +166,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _aut /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"KeypadPage\", function() { return KeypadPage; });\n/* harmony import */ var _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/mobile-operators-identifiers */ \"./src/components/mobile-operators-identifiers.js\");\n\n\n/* ================== KEYPAD START================== */\n\nclass KeypadPage {\n constructor(store, accountName) {\n this.setStateKeypad = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'KEYPAD',\n activePage: this.render()\n };\n setState(initializeState);\n };\n\n this.callMode = new CallMode();\n }\n\n render() {\n const buttons = {\n ONE: '1',\n TWO: '2',\n THREE: '3',\n FOUR: '4',\n FIVE: '5',\n SIX: '6',\n SEVEN: '7',\n EIGHT: '8',\n NINE: '9',\n ZERO: '0',\n ASTERISK: '*',\n HASH: '#'\n };\n\n return (/*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n \n
\n
\n
\n\n
\n \n
\n
\n ${this.createButton(buttons.ONE)}\n ${this.createButton(buttons.TWO)}\n ${this.createButton(buttons.THREE)}\n
\n
\n ${this.createButton(buttons.FOUR)}\n ${this.createButton(buttons.FIVE)}\n ${this.createButton(buttons.SIX)}\n
\n
\n ${this.createButton(buttons.SEVEN)}\n ${this.createButton(buttons.EIGHT)}\n ${this.createButton(buttons.NINE)}\n
\n
\n ${this.createButton(buttons.ASTERISK)}\n ${this.createButton(buttons.ZERO)}\n ${this.createButton(buttons.HASH)}\n
\n
\n\n
\n
\n
\n \n\n
\n\n
\n `\n );\n }\n\n createButton(value) {\n const button = /*html*/`\n
${value}
\n `;\n\n return button;\n }\n\n applyListenerForKeypadPage() {\n\n /* ADD NUMBER */\n const keypadButtons = document.getElementById('wraper-for-buttons');\n const fieldForNumber = document.getElementById('number');\n const fieldForOperator = document.getElementById('operator');\n\n const toFormateNumberFieldForAdding = () => {\n const numbersFromField = fieldForNumber.textContent.replace(/\\D/gm, '');\n let finalConstructions = null;\n\n if (numbersFromField.length === 1) {\n finalConstructions = numbersFromField.replace(/(.{1})/g, '($1');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 3) {\n finalConstructions = numbersFromField.replace(/(.{3})/g, '($1)');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 4) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{1})/g, '($1) $2');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 7) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{1})/g, '($1) $2-$3');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 9) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{2})(.{1})/g, '($1) $2-$3-$4');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n };\n\n keypadButtons.addEventListener('click', e => {\n const TARGET_CLASS_NAME = e.target.className;\n\n if (TARGET_CLASS_NAME === 'number-btn') {\n const BUTTON_VALUE = e.target.textContent;\n fieldForNumber.textContent += BUTTON_VALUE;\n\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n }\n });\n\n /* REMOVE NUMBER */\n const deleteButton = document.getElementById('delete');\n\n deleteButton.addEventListener('click', e => {\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'delete' || BUTTON_ID_FROM_SVG === 'delete' || BUTTON_ID_FROM_PATH === 'delete') {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n\n return;\n }\n });\n\n /* TO CALL BUTTON */\n const mainWraper = document.getElementById('main-wraper');\n\n const toCallButton = document.getElementById('call-btn');\n toCallButton.addEventListener('click', () => {\n const ERROR_BLOCK = document.getElementById('error-block');\n\n if (fieldForNumber.textContent.length < 3) {\n ERROR_BLOCK.textContent = `ERROR you've typed incorrect number`;\n setTimeout(() => {\n ERROR_BLOCK.textContent = '';\n }, 3000);\n return;\n }\n\n const NUMBER_FOR_CALL_MODE = this.callMode.getNumber();\n const OPERATOR_FOR_CALL_MODE = this.callMode.getOperator();\n\n mainWraper.classList.add('call-mode');\n mainWraper.innerHTML = this.callMode.render(NUMBER_FOR_CALL_MODE, OPERATOR_FOR_CALL_MODE);\n this.callMode.applyListenerForCallMode();\n });\n\n /* WRITING NUMBER BY KEYBOARD */\n\n const keyCodes = {\n ONE: 49,\n TWO: 50,\n THREE: 51,\n FOUR: 52,\n FIVE: 53,\n SIX: 54,\n SEVEN: 55,\n EIGHT: 56,\n NINE: 57,\n ZERO: 48,\n ASTERISK: 42,\n HASH: 35,\n DELETE: 8\n };\n\n const SINGLE_TAPS = e => {\n\n if (e.keyCode === keyCodes.ONE) {\n const ONE = '1';\n fieldForNumber.textContent += ONE;\n }\n if (e.keyCode === keyCodes.TWO) {\n const TWO = '2';\n fieldForNumber.textContent += TWO;\n }\n if (e.keyCode === keyCodes.THREE) {\n const THREE = '3';\n fieldForNumber.textContent += THREE;\n }\n if (e.keyCode === keyCodes.FOUR) {\n const FOUR = '4';\n fieldForNumber.textContent += FOUR;\n }\n if (e.keyCode === keyCodes.FIVE) {\n const FIVE = '5';\n fieldForNumber.textContent += FIVE;\n }\n if (e.keyCode === keyCodes.SIX) {\n const SIX = '6';\n fieldForNumber.textContent += SIX;\n }\n if (e.keyCode === keyCodes.SEVEN) {\n const SEVEN = '7';\n fieldForNumber.textContent += SEVEN;\n }\n if (e.keyCode === keyCodes.EIGHT) {\n const EIGHT = '8';\n fieldForNumber.textContent += EIGHT;\n }\n if (e.keyCode === keyCodes.NINE) {\n const NINE = '9';\n fieldForNumber.textContent += NINE;\n }\n if (e.keyCode === keyCodes.ZERO) {\n const ZERO = '0';\n fieldForNumber.textContent += ZERO;\n }\n if (e.keyCode === keyCodes.HASH) {\n const HASH = '#';\n fieldForNumber.textContent += HASH;\n }\n if (e.keyCode === keyCodes.ASTERISK) {\n const ASTERISK = '*';\n fieldForNumber.textContent += ASTERISK;\n }\n\n /* IDENTIFICATION FUNCTIONAL */\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n };\n\n const DELETE_FUNCTIONAL = e => {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n\n if (e.keyCode === keyCodes.DELETE) {\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n return;\n }\n };\n\n window.addEventListener('keypress', SINGLE_TAPS);\n window.addEventListener('keydown', DELETE_FUNCTIONAL);\n }\n\n indentifyMobileOperator(firstThreeNumbers) {\n let operator;\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].kuivstar.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Kuivstar';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].life.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Life';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].vodafone.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Vodafone';\n }\n });\n\n return operator;\n }\n}\n\n/* ================== KEYPAD END================== */\n\n/* ================== CALL MODE START================== */\nclass CallMode {\n constructor() {}\n\n render(number, operator) {\n return (/*html*/`\n
\n
\n\n
\n ${number}\n ${operator}\n
\n\n
\n \n \n \n \n \n
\n\n
\n\n
\n\n
\n\n
\n\n
\n
\n \n
\n mute\n
\n\n
\n
\n \n
\n keypad\n
\n \n
\n
\n \n
\n volume\n
\n \n
\n\n
\n
\n
\n \n
\n add\n
\n \n
\n
\n \n
\n video\n
\n\n
\n
\n \n
\n contacts\n
\n
\n\n
\n\n
\n
\n \n
\n
\n\n
\n
\n `\n );\n }\n\n getNumber() {\n const phoneNumber = document.getElementById('number');\n return phoneNumber.textContent;\n }\n\n getOperator() {\n const phoneOperator = document.getElementById('operator');\n return phoneOperator.textContent;\n }\n\n applyListenerForCallMode() {}\n\n setSavedKeypadPage(page) {\n this.savedKeypadPage = page;\n }\n}\n\n/* ================== CALL MODE END================== */\n\n\n\n//# sourceURL=webpack:///./src/keypad/keypad.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"KeypadPage\", function() { return KeypadPage; });\n/* harmony import */ var _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/mobile-operators-identifiers */ \"./src/components/mobile-operators-identifiers.js\");\n\n\n/* ================== KEYPAD START================== */\n\nclass KeypadPage {\n constructor(store, accountName) {\n this.setStateKeypad = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'KEYPAD',\n activePage: this.render()\n };\n setState(initializeState);\n window.history.pushState(initializeState.activePage, initializeState.stateName);\n };\n\n this.callMode = new CallMode();\n }\n\n render() {\n const buttons = {\n ONE: '1',\n TWO: '2',\n THREE: '3',\n FOUR: '4',\n FIVE: '5',\n SIX: '6',\n SEVEN: '7',\n EIGHT: '8',\n NINE: '9',\n ZERO: '0',\n ASTERISK: '*',\n HASH: '#'\n };\n\n return (/*html*/`\n
\n\n
\n
\n
\n \n \n
\n
\n \n
\n
\n
\n\n
\n \n
\n
\n ${this.createButton(buttons.ONE)}\n ${this.createButton(buttons.TWO)}\n ${this.createButton(buttons.THREE)}\n
\n
\n ${this.createButton(buttons.FOUR)}\n ${this.createButton(buttons.FIVE)}\n ${this.createButton(buttons.SIX)}\n
\n
\n ${this.createButton(buttons.SEVEN)}\n ${this.createButton(buttons.EIGHT)}\n ${this.createButton(buttons.NINE)}\n
\n
\n ${this.createButton(buttons.ASTERISK)}\n ${this.createButton(buttons.ZERO)}\n ${this.createButton(buttons.HASH)}\n
\n
\n\n
\n
\n
\n \n\n
\n\n
\n `\n );\n }\n\n createButton(value) {\n const button = /*html*/`\n
${value}
\n `;\n\n return button;\n }\n\n applyListenerForKeypadPage() {\n\n /* ADD NUMBER */\n const keypadButtons = document.getElementById('wraper-for-buttons');\n const fieldForNumber = document.getElementById('number');\n const fieldForOperator = document.getElementById('operator');\n\n const toFormateNumberFieldForAdding = () => {\n const numbersFromField = fieldForNumber.textContent.replace(/\\D/gm, '');\n let finalConstructions = null;\n\n if (numbersFromField.length === 1) {\n finalConstructions = numbersFromField.replace(/(.{1})/g, '($1');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 3) {\n finalConstructions = numbersFromField.replace(/(.{3})/g, '($1)');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 4) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{1})/g, '($1) $2');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 7) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{1})/g, '($1) $2-$3');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n\n if (numbersFromField.length === 9) {\n finalConstructions = numbersFromField.replace(/(.{3})(.{3})(.{2})(.{1})/g, '($1) $2-$3-$4');\n fieldForNumber.textContent = finalConstructions;\n return;\n }\n };\n\n keypadButtons.addEventListener('click', e => {\n const TARGET_CLASS_NAME = e.target.className;\n\n if (TARGET_CLASS_NAME === 'number-btn') {\n const BUTTON_VALUE = e.target.textContent;\n fieldForNumber.textContent += BUTTON_VALUE;\n\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n }\n });\n\n /* REMOVE NUMBER */\n const deleteButton = document.getElementById('delete');\n\n deleteButton.addEventListener('click', e => {\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'delete' || BUTTON_ID_FROM_SVG === 'delete' || BUTTON_ID_FROM_PATH === 'delete') {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n\n return;\n }\n });\n\n /* TO CALL BUTTON */\n const mainWraper = document.getElementById('main-wraper');\n\n const toCallButton = document.getElementById('call-btn');\n toCallButton.addEventListener('click', () => {\n const ERROR_BLOCK = document.getElementById('error-block');\n\n if (fieldForNumber.textContent.length < 3) {\n ERROR_BLOCK.textContent = `ERROR you've typed incorrect number`;\n setTimeout(() => {\n ERROR_BLOCK.textContent = '';\n }, 3000);\n return;\n }\n\n const NUMBER_FOR_CALL_MODE = this.callMode.getNumber();\n const OPERATOR_FOR_CALL_MODE = this.callMode.getOperator();\n\n mainWraper.classList.add('call-mode');\n mainWraper.innerHTML = this.callMode.render(NUMBER_FOR_CALL_MODE, OPERATOR_FOR_CALL_MODE);\n this.callMode.applyListenerForCallMode();\n });\n\n /* WRITING NUMBER BY KEYBOARD */\n\n const keyCodes = {\n ONE: 49,\n TWO: 50,\n THREE: 51,\n FOUR: 52,\n FIVE: 53,\n SIX: 54,\n SEVEN: 55,\n EIGHT: 56,\n NINE: 57,\n ZERO: 48,\n ASTERISK: 42,\n HASH: 35,\n DELETE: 8\n };\n\n const SINGLE_TAPS = e => {\n\n if (e.keyCode === keyCodes.ONE) {\n const ONE = '1';\n fieldForNumber.textContent += ONE;\n }\n if (e.keyCode === keyCodes.TWO) {\n const TWO = '2';\n fieldForNumber.textContent += TWO;\n }\n if (e.keyCode === keyCodes.THREE) {\n const THREE = '3';\n fieldForNumber.textContent += THREE;\n }\n if (e.keyCode === keyCodes.FOUR) {\n const FOUR = '4';\n fieldForNumber.textContent += FOUR;\n }\n if (e.keyCode === keyCodes.FIVE) {\n const FIVE = '5';\n fieldForNumber.textContent += FIVE;\n }\n if (e.keyCode === keyCodes.SIX) {\n const SIX = '6';\n fieldForNumber.textContent += SIX;\n }\n if (e.keyCode === keyCodes.SEVEN) {\n const SEVEN = '7';\n fieldForNumber.textContent += SEVEN;\n }\n if (e.keyCode === keyCodes.EIGHT) {\n const EIGHT = '8';\n fieldForNumber.textContent += EIGHT;\n }\n if (e.keyCode === keyCodes.NINE) {\n const NINE = '9';\n fieldForNumber.textContent += NINE;\n }\n if (e.keyCode === keyCodes.ZERO) {\n const ZERO = '0';\n fieldForNumber.textContent += ZERO;\n }\n if (e.keyCode === keyCodes.HASH) {\n const HASH = '#';\n fieldForNumber.textContent += HASH;\n }\n if (e.keyCode === keyCodes.ASTERISK) {\n const ASTERISK = '*';\n fieldForNumber.textContent += ASTERISK;\n }\n\n /* IDENTIFICATION FUNCTIONAL */\n const MATCH_NUMBERS = fieldForNumber.textContent.match(/\\d+/gm);\n const FIRST_THREE_NUMBERS = MATCH_NUMBERS[0];\n const LENGTH_OF_FIRST_NUMBERS = FIRST_THREE_NUMBERS.length;\n\n if (LENGTH_OF_FIRST_NUMBERS === 3) {\n fieldForOperator.textContent = this.indentifyMobileOperator(FIRST_THREE_NUMBERS);\n }\n\n toFormateNumberFieldForAdding();\n };\n\n const DELETE_FUNCTIONAL = e => {\n const LENGTH_OF_NUMBERS = fieldForNumber.textContent.length;\n\n if (e.keyCode === keyCodes.DELETE) {\n const LENGTH_OF_NUMBERS_FOR_SLICE = fieldForNumber.textContent.length - 1;\n const strWithDeletedOneNumber = fieldForNumber.textContent.slice(0, LENGTH_OF_NUMBERS_FOR_SLICE);\n fieldForNumber.textContent = strWithDeletedOneNumber;\n\n if (LENGTH_OF_NUMBERS <= 3) {\n fieldForOperator.textContent = '';\n }\n return;\n }\n };\n\n window.addEventListener('keypress', SINGLE_TAPS);\n window.addEventListener('keydown', DELETE_FUNCTIONAL);\n }\n\n indentifyMobileOperator(firstThreeNumbers) {\n let operator;\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].kuivstar.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Kuivstar';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].life.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Life';\n }\n });\n\n _components_mobile_operators_identifiers__WEBPACK_IMPORTED_MODULE_0__[\"MOBILE_OPERATORS_IDENTIFICATORS\"].vodafone.forEach(identicationNumber => {\n if (identicationNumber === firstThreeNumbers) {\n operator = 'Vodafone';\n }\n });\n\n return operator;\n }\n}\n\n/* ================== KEYPAD END================== */\n\n/* ================== CALL MODE START================== */\nclass CallMode {\n constructor() {}\n\n render(number, operator) {\n return (/*html*/`\n
\n
\n\n
\n ${number}\n ${operator}\n
\n\n
\n \n \n \n \n \n
\n\n
\n\n
\n\n
\n\n
\n\n
\n
\n \n
\n mute\n
\n\n
\n
\n \n
\n keypad\n
\n \n
\n
\n \n
\n volume\n
\n \n
\n\n
\n
\n
\n \n
\n add\n
\n \n
\n
\n \n
\n video\n
\n\n
\n
\n \n
\n contacts\n
\n
\n\n
\n\n
\n
\n \n
\n
\n\n
\n
\n `\n );\n }\n\n getNumber() {\n const phoneNumber = document.getElementById('number');\n return phoneNumber.textContent;\n }\n\n getOperator() {\n const phoneOperator = document.getElementById('operator');\n return phoneOperator.textContent;\n }\n\n applyListenerForCallMode() {}\n\n setSavedKeypadPage(page) {\n this.savedKeypadPage = page;\n }\n}\n\n/* ================== CALL MODE END================== */\n\n\n\n//# sourceURL=webpack:///./src/keypad/keypad.js?"); /***/ }), @@ -190,7 +190,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UserPage\", function() { return UserPage; });\n/* harmony import */ var _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../edit-user-page/edit-user-page */ \"./src/edit-user-page/edit-user-page.js\");\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\n\nclass UserPage {\n constructor(store, accountName) {\n this.setStateUserPage = () => {\n const { setState } = store;\n const initializeState = {\n stateName: 'USER_PAGE'\n };\n setState(initializeState);\n };\n\n this.editUserPage = new _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_0__[\"EditUserPage\"](store, accountName);\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_1__[\"Url\"](accountName);\n }\n\n render(user) {\n this.user = user;\n\n return (/*html*/`\n
\n\n
\n
\n User page\n
\n
\n\n
\n \n
\n \"avatar\"\n
\n\n
\n

Full Name:

\n

${user.fullName}

\n
\n
\n

Email:

\n

${user.email}

\n
\n
\n

Phone number:

\n

${user.phone}

\n
\n
\n

Birth date:

\n

${user.birthdate ? user.birthdate.slice(0, 10) : '__________'}

\n
\n
\n

Address:

\n

${user.address ? user.address : '__________'}

\n
\n
\n

Gender:

\n

${user.gender === \"M\" ? 'Male' : 'Female'}

\n
\n\n
\n \n \n
\n\n
\n\n
\n `\n );\n }\n\n applyListenersForUserPage() {\n const wraperForButtons = document.getElementById('usp-wraper-for-btns');\n\n const handlerForButtons = e => {\n if (e.target.textContent.trim() === 'Edit') {\n this.editUserPage.setStateEditUser();\n const EDIT_USER_PAGE = this.editUserPage.render(this.user);\n\n const MAIN_WRAPER = document.getElementById('main-wraper');\n MAIN_WRAPER.firstElementChild.outerHTML = EDIT_USER_PAGE;\n this.editUserPage.applyListenersForEditUserPage();\n }\n\n if (e.target.textContent.trim() === 'Delete') {\n const requestForDelete = confirm('Are you sure?');\n if (requestForDelete) {\n this.url.deleteUserById(this.user._id);\n\n const USER_PAGE = document.getElementById('user-info');\n USER_PAGE.innerHTML = /*html*/`

This user was deleted

`;\n }\n }\n };\n\n wraperForButtons.addEventListener('click', handlerForButtons);\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/user-page/user-page.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UserPage\", function() { return UserPage; });\n/* harmony import */ var _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../edit-user-page/edit-user-page */ \"./src/edit-user-page/edit-user-page.js\");\n/* harmony import */ var _url_url__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../url/url */ \"./src/url/url.js\");\n\n\n\nclass UserPage {\n constructor(store, accountName) {\n this.setStateUserPage = user => {\n const { setState, getState } = store;\n const initializeState = {\n stateName: 'USER_PAGE',\n activePage: this.render(user)\n };\n setState(initializeState);\n window.history.pushState(initializeState.activePage, initializeState.stateName);\n };\n\n this.editUserPage = new _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_0__[\"EditUserPage\"](store, accountName);\n this.url = new _url_url__WEBPACK_IMPORTED_MODULE_1__[\"Url\"](accountName);\n }\n\n render(user) {\n this.user = user;\n\n return (/*html*/`\n
\n\n
\n
\n User page\n
\n
\n\n
\n \n
\n \"avatar\"\n
\n\n
\n

Full Name:

\n

${user.fullName}

\n
\n
\n

Email:

\n

${user.email}

\n
\n
\n

Phone number:

\n

${user.phone}

\n
\n
\n

Birth date:

\n

${user.birthdate ? user.birthdate.slice(0, 10) : '__________'}

\n
\n
\n

Address:

\n

${user.address ? user.address : '__________'}

\n
\n
\n

Gender:

\n

${user.gender === \"M\" ? 'Male' : 'Female'}

\n
\n\n
\n \n \n
\n\n
\n\n
\n `\n );\n }\n\n applyListenersForUserPage() {\n const wraperForButtons = document.getElementById('usp-wraper-for-btns');\n\n const handlerForButtons = e => {\n if (e.target.textContent.trim() === 'Edit') {\n this.editUserPage.setStateEditUser(this.user || window.user);\n const EDIT_USER_PAGE = this.editUserPage.render(this.user || window.user);\n\n const MAIN_WRAPER = document.getElementById('main-wraper');\n MAIN_WRAPER.firstElementChild.outerHTML = EDIT_USER_PAGE;\n this.editUserPage.applyListenersForEditUserPage();\n }\n\n if (e.target.textContent.trim() === 'Delete') {\n const requestForDelete = confirm('Are you sure?');\n if (requestForDelete) {\n this.url.deleteUserById(this.user._id || window.user);\n\n const USER_PAGE = document.getElementById('user-info');\n USER_PAGE.innerHTML = /*html*/`

This user was deleted

`;\n }\n }\n };\n\n wraperForButtons.addEventListener('click', handlerForButtons);\n }\n}\n\n\n\n//# sourceURL=webpack:///./src/user-page/user-page.js?"); /***/ }) diff --git a/phone-book/src/add-user/add-user.js b/phone-book/src/add-user/add-user.js index b3d2d9d..f51971d 100644 --- a/phone-book/src/add-user/add-user.js +++ b/phone-book/src/add-user/add-user.js @@ -2,13 +2,14 @@ import {Url} from '../url/url'; class AddUserPage { constructor(store, accountName) { - this.setStateContact = () => { + this.setStateAddUser = () => { const {setState} = store; const initializeState = { stateName: 'ADD USER', activePage: this.render(), }; setState(initializeState); + window.history.pushState(initializeState.activePage, initializeState.stateName); } this.url = new Url(accountName); diff --git a/phone-book/src/authorization-page/authorization-page.js b/phone-book/src/authorization-page/authorization-page.js index e0e933b..78f673b 100644 --- a/phone-book/src/authorization-page/authorization-page.js +++ b/phone-book/src/authorization-page/authorization-page.js @@ -1,12 +1,13 @@ class AuthorizationPage{ - constructor() { - this.setStateAuthorization = () => { + constructor(store) { + this.setStateAuthorization = (listeners) => { const {setState} = store; const initializeState = { stateName: 'AUTHORIZATION', - activePage: this.render(), + activePage: this.render() }; setState(initializeState); + window.history.pushState(initializeState.activePage, initializeState.stateName); } } diff --git a/phone-book/src/contact/contact.js b/phone-book/src/contact/contact.js index ef29ca5..07f09f3 100644 --- a/phone-book/src/contact/contact.js +++ b/phone-book/src/contact/contact.js @@ -6,12 +6,13 @@ import {UserPage} from '../user-page/user-page'; class ContactPage { constructor(store, accountName) { this.setStateContact = () => { - const {setState} = store; + const {setState, getState} = store; const initializeState = { stateName: 'CONTACT', - activePage: this.render(), + activePage: this.render() }; setState(initializeState); + window.history.pushState(initializeState.activePage, initializeState.stateName); } this.url = new Url(accountName); @@ -143,12 +144,14 @@ class ContactPage { if(e.target.parentElement.tagName === "TR") { const id = e.target.parentElement.id; const user = this.users.filter(user => user._id === id)[0]; - this.userPage.setStateUserPage(); + this.userPage.setStateUserPage(user); const userPage = this.userPage.render(user); const MAIN_WRAPER = document.getElementById('main-wraper'); MAIN_WRAPER.firstElementChild.outerHTML = userPage; this.userPage.applyListenersForUserPage(); + + window.user = user; } } diff --git a/phone-book/src/edit-user-page/edit-user-page.js b/phone-book/src/edit-user-page/edit-user-page.js index 1cc2085..6e067c7 100644 --- a/phone-book/src/edit-user-page/edit-user-page.js +++ b/phone-book/src/edit-user-page/edit-user-page.js @@ -2,12 +2,14 @@ import {Url} from '../url/url'; class EditUserPage { constructor(store, accountName) { - this.setStateEditUser = () => { - const {setState} = store; + this.setStateEditUser = (user) => { + const {setState, getState} = store; const initializeState = { stateName: 'EDIT USER', + activePage: this.render(user) }; setState(initializeState); + window.history.pushState(initializeState.activePage, initializeState.stateName); } this.url = new Url(accountName); @@ -17,7 +19,7 @@ class EditUserPage { this.user = user; return /*html*/` -
+
@@ -232,7 +234,7 @@ class EditUserPage { }, {}); if(infoToEdit) { - this.url.editUser(infoToEdit, this.user._id); + this.url.editUser(infoToEdit, this.user._id || window.user); inputs.forEach(input => { if(input.tagName !== "SELECT") { diff --git a/phone-book/src/index.js b/phone-book/src/index.js index 7d8a1a0..03ce87a 100644 --- a/phone-book/src/index.js +++ b/phone-book/src/index.js @@ -2,11 +2,14 @@ import {AuthorizationPage} from './authorization-page/authorization-page'; import {ContactPage} from './contact/contact'; import {KeypadPage} from './keypad/keypad'; import {AddUserPage} from './add-user/add-user'; +import {UserPage} from './user-page/user-page'; +import {EditUserPage} from './edit-user-page/edit-user-page'; class App { constructor() { this.store = this.createStore(); - this.authorizationPage = new AuthorizationPage(); + this.authorizationPage = new AuthorizationPage(this.store); + this.authorizationPage.setStateAuthorization(this.applyListenerForAuthorizationPage); this.renderAuthorizationPage(); } @@ -31,14 +34,12 @@ class App { }; if(action.type === 'MOVE_TO_KEYPAD_PAGE') { - this.pages.keypad.setStateKeypad(); switchBetweenPages(); this.pages.keypad.applyListenerForKeypadPage(); return; } if(action.type === 'MOVE_TO_CONTACT_PAGE') { - this.pages.contacts.setStateContact(); switchBetweenPages(); this.pages.contacts.renderUsers(); this.pages.contacts.applyListenerForContactPage(); @@ -46,7 +47,6 @@ class App { } if(action.type === 'MOVE_TO_ADD_USER_PAGE') { - this.pages.addUser.setStateContact(); switchBetweenPages(); this.pages.addUser.applyListenersForAddUserPage(); return; @@ -71,7 +71,9 @@ class App { 'contacts': new ContactPage(this.store, this.accountName), 'keypad': new KeypadPage(this.store, this.accountName), 'addUser': new AddUserPage(this.store, this.accountName), - 'footer': new FooterNavigationBar() + 'footer': new FooterNavigationBar(), + 'userPage': new UserPage(this.store, this.accountName), + 'editUserPage': new EditUserPage(this.store, this.accountName) } this.pages.contacts.setStateContact(); @@ -116,7 +118,13 @@ class App { const mountMode = document.getElementById('mountMode'); mountMode.innerHTML = appTemplate; - this.pages.contacts.renderUsers(); + if(currentState.stateName === 'CONTACT') {this.pages.contacts.renderUsers()}; + } + + updateView(state) { + const mainWraper = document.getElementById('main-wraper'); + + mainWraper.firstElementChild.outerHTML = state; } applyListenerForNavigation() { @@ -174,12 +182,37 @@ class App { ) { if(currentState.stateName !== 'ADD USER') { - this.pages.addUser.setStateContact(); + this.pages.addUser.setStateAddUser(); return this.reducer(_MOVE_TO_ADD_USER_PAGE); } return; } }) + + window.addEventListener('popstate', e => { + this.updateView(e.state); + + if(/id="user-page"/.test(e.state)) { + this.pages.userPage.applyListenersForUserPage(); + } + + if(/id="contact-wraper"/.test(e.state)) { + this.pages.contacts.renderUsers(); + this.pages.contacts.applyListenerForContactPage(); + } + + if(/id="edit-user-page"/.test(e.state)) { + this.pages.editUserPage.applyListenersForEditUserPage(); + } + + if(/id="add-user-page"/.test(e.state)) { + this.pages.addUser.applyListenersForAddUserPage(); + } + + if(/id="keypad-wraper"/.test(e.state)) { + this.pages.keypad.applyListenerForKeypadPage(); + } + }); } } diff --git a/phone-book/src/keypad/keypad.js b/phone-book/src/keypad/keypad.js index 3e7ee6b..fb50514 100644 --- a/phone-book/src/keypad/keypad.js +++ b/phone-book/src/keypad/keypad.js @@ -11,6 +11,7 @@ class KeypadPage { activePage: this.render(), }; setState(initializeState); + window.history.pushState(initializeState.activePage, initializeState.stateName); } this.callMode = new CallMode(); diff --git a/phone-book/src/user-page/user-page.js b/phone-book/src/user-page/user-page.js index 238b612..41eea97 100644 --- a/phone-book/src/user-page/user-page.js +++ b/phone-book/src/user-page/user-page.js @@ -3,12 +3,14 @@ import {Url} from '../url/url'; class UserPage{ constructor(store, accountName) { - this.setStateUserPage = () => { - const {setState} = store; + this.setStateUserPage = (user) => { + const {setState, getState} = store; const initializeState = { stateName: 'USER_PAGE', + activePage: this.render(user) }; setState(initializeState); + window.history.pushState(initializeState.activePage, initializeState.stateName); } this.editUserPage = new EditUserPage(store, accountName); @@ -74,8 +76,8 @@ class UserPage{ const handlerForButtons = (e) => { if(e.target.textContent.trim() === 'Edit') { - this.editUserPage.setStateEditUser(); - const EDIT_USER_PAGE = this.editUserPage.render(this.user); + this.editUserPage.setStateEditUser(this.user || window.user); + const EDIT_USER_PAGE = this.editUserPage.render(this.user || window.user); const MAIN_WRAPER = document.getElementById('main-wraper'); MAIN_WRAPER.firstElementChild.outerHTML = EDIT_USER_PAGE; @@ -85,7 +87,7 @@ class UserPage{ if(e.target.textContent.trim() === 'Delete') { const requestForDelete = confirm('Are you sure?'); if(requestForDelete) { - this.url.deleteUserById(this.user._id); + this.url.deleteUserById(this.user._id || window.user); const USER_PAGE = document.getElementById('user-info'); USER_PAGE.innerHTML = /*html*/`

This user was deleted

`; From 35375322cdad4bb627e5bc59da2027b466eb5392 Mon Sep 17 00:00:00 2001 From: Balashov Nikita Date: Thu, 23 Aug 2018 22:05:07 +0300 Subject: [PATCH 14/14] fix bag with autorization in router --- phone-book/build/bundle.js | 2 +- phone-book/src/index.js | 10 +++++++++- phone-book/src/router/router.js | 5 +++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 phone-book/src/router/router.js diff --git a/phone-book/build/bundle.js b/phone-book/build/bundle.js index a43cfee..9191cc4 100644 --- a/phone-book/build/bundle.js +++ b/phone-book/build/bundle.js @@ -154,7 +154,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./authorization-page/authorization-page */ \"./src/authorization-page/authorization-page.js\");\n/* harmony import */ var _contact_contact__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./contact/contact */ \"./src/contact/contact.js\");\n/* harmony import */ var _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./keypad/keypad */ \"./src/keypad/keypad.js\");\n/* harmony import */ var _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./add-user/add-user */ \"./src/add-user/add-user.js\");\n/* harmony import */ var _user_page_user_page__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./user-page/user-page */ \"./src/user-page/user-page.js\");\n/* harmony import */ var _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./edit-user-page/edit-user-page */ \"./src/edit-user-page/edit-user-page.js\");\n\n\n\n\n\n\n\nclass App {\n constructor() {\n this.store = this.createStore();\n this.authorizationPage = new _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__[\"AuthorizationPage\"](this.store);\n this.authorizationPage.setStateAuthorization(this.applyListenerForAuthorizationPage);\n this.renderAuthorizationPage();\n }\n\n createStore() {\n let state;\n\n return {\n getState() {\n return state;\n },\n setState(newState) {\n state = newState;\n }\n };\n }\n\n reducer(action) {\n const currentState = this.store.getState();\n const mainWraper = document.getElementById('main-wraper');\n const switchBetweenPages = () => {\n mainWraper.firstElementChild.outerHTML = currentState.activePage;\n };\n\n if (action.type === 'MOVE_TO_KEYPAD_PAGE') {\n switchBetweenPages();\n this.pages.keypad.applyListenerForKeypadPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_CONTACT_PAGE') {\n switchBetweenPages();\n this.pages.contacts.renderUsers();\n this.pages.contacts.applyListenerForContactPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_ADD_USER_PAGE') {\n switchBetweenPages();\n this.pages.addUser.applyListenersForAddUserPage();\n return;\n }\n }\n\n renderAuthorizationPage() {\n const authorizationPage = this.authorizationPage.render();\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = authorizationPage;\n this.applyListenerForAuthorizationPage();\n }\n\n applyListenerForAuthorizationPage() {\n const input = document.querySelector('.au-input');\n const logInButton = document.getElementById('log-in');\n const switchBetweenPages = () => {\n this.accountName = input.value;\n\n this.pages = {\n 'contacts': new _contact_contact__WEBPACK_IMPORTED_MODULE_1__[\"ContactPage\"](this.store, this.accountName),\n 'keypad': new _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__[\"KeypadPage\"](this.store, this.accountName),\n 'addUser': new _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__[\"AddUserPage\"](this.store, this.accountName),\n 'footer': new FooterNavigationBar(),\n 'userPage': new _user_page_user_page__WEBPACK_IMPORTED_MODULE_4__[\"UserPage\"](this.store, this.accountName),\n 'editUserPage': new _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_5__[\"EditUserPage\"](this.store, this.accountName)\n };\n\n this.pages.contacts.setStateContact();\n this.render();\n this.pages.contacts.applyListenerForContactPage();\n this.applyListenerForNavigation();\n };\n\n const handlerForLogInBtn = () => {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n };\n\n const handlerForLogInInput = e => {\n if (e.keyCode === 13) {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n }\n };\n\n logInButton.addEventListener('click', handlerForLogInBtn);\n input.addEventListener('keydown', handlerForLogInInput);\n }\n\n render() {\n const currentState = this.store.getState();\n const FOOTER = this.pages.footer.render();\n\n const appTemplate = /*html*/`\n
\n ${currentState.activePage}\n ${FOOTER}\n
\n `;\n\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = appTemplate;\n\n if (currentState.stateName === 'CONTACT') {\n this.pages.contacts.renderUsers();\n };\n }\n\n updateView(state) {\n const mainWraper = document.getElementById('main-wraper');\n\n mainWraper.firstElementChild.outerHTML = state;\n }\n\n applyListenerForNavigation() {\n\n const _MOVE_TO_KEYPAD_PAGE = {\n type: 'MOVE_TO_KEYPAD_PAGE'\n };\n\n const _MOVE_TO_CONTACT_PAGE = {\n type: 'MOVE_TO_CONTACT_PAGE'\n };\n\n const _MOVE_TO_ADD_USER_PAGE = {\n type: 'MOVE_TO_ADD_USER_PAGE'\n };\n\n const wraperForFooter = document.getElementById('wraper-for-footer');\n wraperForFooter.addEventListener('click', e => {\n const currentState = this.store.getState();\n\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'to-keypad-page' || BUTTON_ID_FROM_SVG === 'to-keypad-page' || BUTTON_ID_FROM_PATH === 'to-keypad-page') {\n\n if (currentState.stateName !== 'KEYPAD') {\n this.pages.keypad.setStateKeypad();\n return this.reducer(_MOVE_TO_KEYPAD_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-contact-page' || BUTTON_ID_FROM_SVG === 'to-contact-page' || BUTTON_ID_FROM_PATH === 'to-contact-page') {\n\n if (currentState.stateName !== 'CONTACT') {\n this.pages.contacts.setStateContact();\n return this.reducer(_MOVE_TO_CONTACT_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-addUser-page' || BUTTON_ID_FROM_SVG === 'to-addUser-page' || BUTTON_ID_FROM_PATH === 'to-addUser-page') {\n\n if (currentState.stateName !== 'ADD USER') {\n this.pages.addUser.setStateAddUser();\n return this.reducer(_MOVE_TO_ADD_USER_PAGE);\n }\n return;\n }\n });\n\n window.addEventListener('popstate', e => {\n this.updateView(e.state);\n\n if (/id=\"user-page\"/.test(e.state)) {\n this.pages.userPage.applyListenersForUserPage();\n }\n\n if (/id=\"contact-wraper\"/.test(e.state)) {\n this.pages.contacts.renderUsers();\n this.pages.contacts.applyListenerForContactPage();\n }\n\n if (/id=\"edit-user-page\"/.test(e.state)) {\n this.pages.editUserPage.applyListenersForEditUserPage();\n }\n\n if (/id=\"add-user-page\"/.test(e.state)) {\n this.pages.addUser.applyListenersForAddUserPage();\n }\n\n if (/id=\"keypad-wraper\"/.test(e.state)) {\n this.pages.keypad.applyListenerForKeypadPage();\n }\n });\n }\n}\n\n/* ================== FOOTER START================== */\n\nclass FooterNavigationBar {\n constructor() {\n this.icons = {\n contactIcon: {\n id: 'to-contact-page',\n class: 'far fa-address-book'\n },\n keypadIcon: {\n id: 'to-keypad-page',\n class: 'fas fa-tty'\n },\n addUserIcon: {\n id: 'to-addUser-page',\n class: 'fas fa-user-plus'\n }\n };\n }\n\n render() {\n const navigationBar = /*html*/`\n
\n
\n ${this.createIcon(this.icons.contactIcon)}\n ${this.createIcon(this.icons.keypadIcon)}\n ${this.createIcon(this.icons.addUserIcon)}\n
\n
\n `;\n\n return navigationBar;\n }\n\n createIcon(iconPattern) {\n const ID = iconPattern.id;\n const CLASS = iconPattern.class;\n\n const icon = /*html*/`\n
\n \n
\n `;\n\n return icon;\n }\n\n}\n\n/* ================== FOOTER END================== */\n\nconst APPLICATION = new App();\n\n//# sourceURL=webpack:///./src/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./authorization-page/authorization-page */ \"./src/authorization-page/authorization-page.js\");\n/* harmony import */ var _contact_contact__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./contact/contact */ \"./src/contact/contact.js\");\n/* harmony import */ var _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./keypad/keypad */ \"./src/keypad/keypad.js\");\n/* harmony import */ var _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./add-user/add-user */ \"./src/add-user/add-user.js\");\n/* harmony import */ var _user_page_user_page__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./user-page/user-page */ \"./src/user-page/user-page.js\");\n/* harmony import */ var _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./edit-user-page/edit-user-page */ \"./src/edit-user-page/edit-user-page.js\");\n\n\n\n\n\n\n\nclass App {\n constructor() {\n this.store = this.createStore();\n this.authorizationPage = new _authorization_page_authorization_page__WEBPACK_IMPORTED_MODULE_0__[\"AuthorizationPage\"](this.store);\n this.authorizationPage.setStateAuthorization(this.applyListenerForAuthorizationPage);\n this.renderAuthorizationPage();\n }\n\n createStore() {\n let state;\n\n return {\n getState() {\n return state;\n },\n setState(newState) {\n state = newState;\n }\n };\n }\n\n reducer(action) {\n const currentState = this.store.getState();\n const mainWraper = document.getElementById('main-wraper');\n const switchBetweenPages = () => {\n mainWraper.firstElementChild.outerHTML = currentState.activePage;\n };\n\n if (action.type === 'MOVE_TO_KEYPAD_PAGE') {\n switchBetweenPages();\n this.pages.keypad.applyListenerForKeypadPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_CONTACT_PAGE') {\n switchBetweenPages();\n this.pages.contacts.renderUsers();\n this.pages.contacts.applyListenerForContactPage();\n return;\n }\n\n if (action.type === 'MOVE_TO_ADD_USER_PAGE') {\n switchBetweenPages();\n this.pages.addUser.applyListenersForAddUserPage();\n return;\n }\n }\n\n renderAuthorizationPage() {\n const authorizationPage = this.authorizationPage.render();\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = authorizationPage;\n this.applyListenerForAuthorizationPage();\n }\n\n applyListenerForAuthorizationPage() {\n const input = document.querySelector('.au-input');\n const logInButton = document.getElementById('log-in');\n const switchBetweenPages = () => {\n this.accountName = input.value;\n\n this.pages = {\n 'contacts': new _contact_contact__WEBPACK_IMPORTED_MODULE_1__[\"ContactPage\"](this.store, this.accountName),\n 'keypad': new _keypad_keypad__WEBPACK_IMPORTED_MODULE_2__[\"KeypadPage\"](this.store, this.accountName),\n 'addUser': new _add_user_add_user__WEBPACK_IMPORTED_MODULE_3__[\"AddUserPage\"](this.store, this.accountName),\n 'footer': new FooterNavigationBar(),\n 'userPage': new _user_page_user_page__WEBPACK_IMPORTED_MODULE_4__[\"UserPage\"](this.store, this.accountName),\n 'editUserPage': new _edit_user_page_edit_user_page__WEBPACK_IMPORTED_MODULE_5__[\"EditUserPage\"](this.store, this.accountName)\n };\n\n this.pages.contacts.setStateContact();\n this.render();\n this.pages.contacts.applyListenerForContactPage();\n this.applyListenerForNavigation();\n };\n\n const handlerForLogInBtn = () => {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n };\n\n const handlerForLogInInput = e => {\n if (e.keyCode === 13) {\n if (input.value.length > 3) {\n switchBetweenPages();\n } else {\n alert('So short login');\n }\n }\n };\n\n logInButton.addEventListener('click', handlerForLogInBtn);\n input.addEventListener('keydown', handlerForLogInInput);\n }\n\n render() {\n const currentState = this.store.getState();\n const FOOTER = this.pages.footer.render();\n\n const appTemplate = /*html*/`\n
\n ${currentState.activePage}\n ${FOOTER}\n
\n `;\n\n const mountMode = document.getElementById('mountMode');\n mountMode.innerHTML = appTemplate;\n\n if (currentState.stateName === 'CONTACT') {\n this.pages.contacts.renderUsers();\n };\n }\n\n updateView(state) {\n const mainWraper = document.getElementById('main-wraper');\n\n mainWraper.firstElementChild.outerHTML = state;\n }\n\n applyListenerForNavigation() {\n\n const _MOVE_TO_KEYPAD_PAGE = {\n type: 'MOVE_TO_KEYPAD_PAGE'\n };\n\n const _MOVE_TO_CONTACT_PAGE = {\n type: 'MOVE_TO_CONTACT_PAGE'\n };\n\n const _MOVE_TO_ADD_USER_PAGE = {\n type: 'MOVE_TO_ADD_USER_PAGE'\n };\n\n const wraperForFooter = document.getElementById('wraper-for-footer');\n wraperForFooter.addEventListener('click', e => {\n const currentState = this.store.getState();\n\n const BUTTON_ID = e.target.id;\n const BUTTON_ID_FROM_SVG = e.target.parentElement.id;\n const BUTTON_ID_FROM_PATH = e.target.parentElement.parentElement.id;\n\n if (BUTTON_ID === 'to-keypad-page' || BUTTON_ID_FROM_SVG === 'to-keypad-page' || BUTTON_ID_FROM_PATH === 'to-keypad-page') {\n\n if (currentState.stateName !== 'KEYPAD') {\n this.pages.keypad.setStateKeypad();\n return this.reducer(_MOVE_TO_KEYPAD_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-contact-page' || BUTTON_ID_FROM_SVG === 'to-contact-page' || BUTTON_ID_FROM_PATH === 'to-contact-page') {\n\n if (currentState.stateName !== 'CONTACT') {\n this.pages.contacts.setStateContact();\n return this.reducer(_MOVE_TO_CONTACT_PAGE);\n }\n return;\n }\n\n if (BUTTON_ID === 'to-addUser-page' || BUTTON_ID_FROM_SVG === 'to-addUser-page' || BUTTON_ID_FROM_PATH === 'to-addUser-page') {\n\n if (currentState.stateName !== 'ADD USER') {\n this.pages.addUser.setStateAddUser();\n return this.reducer(_MOVE_TO_ADD_USER_PAGE);\n }\n return;\n }\n });\n\n window.addEventListener('popstate', e => {\n\n if (/id=\"user-page\"/.test(e.state)) {\n this.updateView(e.state);\n this.pages.userPage.applyListenersForUserPage();\n }\n\n if (/id=\"contact-wraper\"/.test(e.state)) {\n this.updateView(e.state);\n this.pages.contacts.renderUsers();\n this.pages.contacts.applyListenerForContactPage();\n }\n\n if (/id=\"edit-user-page\"/.test(e.state)) {\n this.updateView(e.state);\n this.pages.editUserPage.applyListenersForEditUserPage();\n }\n\n if (/id=\"add-user-page\"/.test(e.state)) {\n this.updateView(e.state);\n this.pages.addUser.applyListenersForAddUserPage();\n }\n\n if (/id=\"keypad-wraper\"/.test(e.state)) {\n this.updateView(e.state);\n this.pages.keypad.applyListenerForKeypadPage();\n }\n\n if (/class=\"authorization-block\"/.test(e.state)) {\n this.renderAuthorizationPage();\n }\n });\n }\n}\n\n/* ================== FOOTER START================== */\n\nclass FooterNavigationBar {\n constructor() {\n this.icons = {\n contactIcon: {\n id: 'to-contact-page',\n class: 'far fa-address-book'\n },\n keypadIcon: {\n id: 'to-keypad-page',\n class: 'fas fa-tty'\n },\n addUserIcon: {\n id: 'to-addUser-page',\n class: 'fas fa-user-plus'\n }\n };\n }\n\n render() {\n const navigationBar = /*html*/`\n
\n
\n ${this.createIcon(this.icons.contactIcon)}\n ${this.createIcon(this.icons.keypadIcon)}\n ${this.createIcon(this.icons.addUserIcon)}\n
\n
\n `;\n\n return navigationBar;\n }\n\n createIcon(iconPattern) {\n const ID = iconPattern.id;\n const CLASS = iconPattern.class;\n\n const icon = /*html*/`\n
\n \n
\n `;\n\n return icon;\n }\n\n}\n\n/* ================== FOOTER END================== */\n\nconst APPLICATION = new App();\n\n//# sourceURL=webpack:///./src/index.js?"); /***/ }), diff --git a/phone-book/src/index.js b/phone-book/src/index.js index 03ce87a..b701aa8 100644 --- a/phone-book/src/index.js +++ b/phone-book/src/index.js @@ -190,28 +190,36 @@ class App { }) window.addEventListener('popstate', e => { - this.updateView(e.state); if(/id="user-page"/.test(e.state)) { + this.updateView(e.state); this.pages.userPage.applyListenersForUserPage(); } if(/id="contact-wraper"/.test(e.state)) { + this.updateView(e.state); this.pages.contacts.renderUsers(); this.pages.contacts.applyListenerForContactPage(); } if(/id="edit-user-page"/.test(e.state)) { + this.updateView(e.state); this.pages.editUserPage.applyListenersForEditUserPage(); } if(/id="add-user-page"/.test(e.state)) { + this.updateView(e.state); this.pages.addUser.applyListenersForAddUserPage(); } if(/id="keypad-wraper"/.test(e.state)) { + this.updateView(e.state); this.pages.keypad.applyListenerForKeypadPage(); } + + if(/class="authorization-block"/.test(e.state)) { + this.renderAuthorizationPage(); + } }); } } diff --git a/phone-book/src/router/router.js b/phone-book/src/router/router.js new file mode 100644 index 0000000..e99875a --- /dev/null +++ b/phone-book/src/router/router.js @@ -0,0 +1,5 @@ +class Router{ + constructor() { + + } +} \ No newline at end of file