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..9191cc4 --- /dev/null +++ b/phone-book/build/bundle.js @@ -0,0 +1,197 @@ +/******/ (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, 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?"); + +/***/ }), + +/***/ "./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(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?"); + +/***/ }), + +/***/ "./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/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 _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?"); + +/***/ }), + +/***/ "./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__, \"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?"); + +/***/ }), + +/***/ "./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 _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\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, 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?"); + +/***/ }), + +/***/ "./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(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 = 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?"); + +/***/ }) + +/******/ }); \ 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 0000000..12f63f7 Binary files /dev/null and b/phone-book/img/icon.ico differ diff --git a/phone-book/index.html b/phone-book/index.html new file mode 100644 index 0000000..3be67fe --- /dev/null +++ b/phone-book/index.html @@ -0,0 +1,21 @@ + + + + + + + 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..f51971d --- /dev/null +++ b/phone-book/src/add-user/add-user.js @@ -0,0 +1,272 @@ +import {Url} from '../url/url'; + +class AddUserPage { + constructor(store, accountName) { + 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); + } + + render() { + return /*html*/` +
+ +
+
+ Add new user +
+
+ +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + ex: https://cloud-drive/photo123456. +
+ +
+ +
+ +
+
+ +
+ `; + } + + applyListenersForAddUserPage() { + + 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'); + + const handlerForSubmit = (e) => { + e.preventDefault(); + + const user = inputs.reduce((newUser, 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' + ) { + newUser[input.name] = input.value; + } + 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; + }, {}) + + 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) + } + + 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 {AddUserPage}; 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..78f673b --- /dev/null +++ b/phone-book/src/authorization-page/authorization-page.js @@ -0,0 +1,27 @@ +class AuthorizationPage{ + constructor(store) { + this.setStateAuthorization = (listeners) => { + const {setState} = store; + const initializeState = { + stateName: 'AUTHORIZATION', + activePage: this.render() + }; + setState(initializeState); + window.history.pushState(initializeState.activePage, initializeState.stateName); + } + } + + render() { + return /*html*/` +
+

Authorization

+
+ + +
+
+ `; + } +} + +export {AuthorizationPage}; \ No newline at end of file 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/contact/contact.js b/phone-book/src/contact/contact.js new file mode 100644 index 0000000..07f09f3 --- /dev/null +++ b/phone-book/src/contact/contact.js @@ -0,0 +1,219 @@ +import {Url} from '../url/url'; +import {UserPage} from '../user-page/user-page'; + +/* ================== CONTACT START================== */ + +class ContactPage { + constructor(store, accountName) { + this.setStateContact = () => { + const {setState, getState} = store; + const initializeState = { + stateName: 'CONTACT', + activePage: this.render() + }; + setState(initializeState); + window.history.pushState(initializeState.activePage, initializeState.stateName); + } + + this.url = new Url(accountName); + this.userPage = new UserPage(store, accountName); + } + + render() { + const contactTempalte = /*html*/` +
+ +
+
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + + +
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 id = user._id; + + const userComponent = /*html*/` + + ${userFirstName} + ${userLastName} + ${userEmail} + + `; + + listStructure += userComponent; + return listStructure; + }, ``) + } + + 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) => { + 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(this.users, firstName); + listOfContacts.innerHTML = this.contactListComponent(sortedListByFirsName); + return; + } + + if(TH_ELEM_CONTAINS === PREDICT_TEXT_CONTENT.lastName) { + const lastName = 1; + 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', this.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); + + + }); + + /* 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(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; + } + } + + listOfContacts.addEventListener('click', handlerForListOfContacts); + } + + 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 this.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/edit-user-page/edit-user-page.js b/phone-book/src/edit-user-page/edit-user-page.js new file mode 100644 index 0000000..6e067c7 --- /dev/null +++ b/phone-book/src/edit-user-page/edit-user-page.js @@ -0,0 +1,277 @@ +import {Url} from '../url/url'; + +class EditUserPage { + constructor(store, accountName) { + 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); + } + + 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 || window.user); + + 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 diff --git a/phone-book/src/index.js b/phone-book/src/index.js new file mode 100644 index 0000000..b701aa8 --- /dev/null +++ b/phone-book/src/index.js @@ -0,0 +1,280 @@ +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.store); + this.authorizationPage.setStateAuthorization(this.applyListenerForAuthorizationPage); + this.renderAuthorizationPage(); + } + + 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') { + switchBetweenPages(); + this.pages.keypad.applyListenerForKeypadPage(); + return; + } + + if(action.type === 'MOVE_TO_CONTACT_PAGE') { + switchBetweenPages(); + this.pages.contacts.renderUsers(); + this.pages.contacts.applyListenerForContactPage(); + return; + } + + if(action.type === 'MOVE_TO_ADD_USER_PAGE') { + switchBetweenPages(); + this.pages.addUser.applyListenersForAddUserPage(); + return; + } + + } + + 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(), + 'userPage': new UserPage(this.store, this.accountName), + 'editUserPage': new EditUserPage(this.store, this.accountName) + } + + 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(); + + const appTemplate = /*html*/` +
+ ${currentState.activePage} + ${FOOTER} +
+ `; + + const mountMode = document.getElementById('mountMode'); + mountMode.innerHTML = appTemplate; + + if(currentState.stateName === 'CONTACT') {this.pages.contacts.renderUsers()}; + } + + updateView(state) { + const mainWraper = document.getElementById('main-wraper'); + + mainWraper.firstElementChild.outerHTML = state; + } + + 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.setStateAddUser(); + return this.reducer(_MOVE_TO_ADD_USER_PAGE); + } + return; + } + }) + + window.addEventListener('popstate', e => { + + 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(); + } + }); + } +} + +/* ================== 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..fb50514 --- /dev/null +++ b/phone-book/src/keypad/keypad.js @@ -0,0 +1,447 @@ +import {MOBILE_OPERATORS_IDENTIFICATORS} from '../components/mobile-operators-identifiers'; + +/* ================== KEYPAD START================== */ + +class KeypadPage { + constructor(store, accountName) { + this.setStateKeypad = () => { + const {setState} = store; + const initializeState = { + stateName: 'KEYPAD', + activePage: this.render(), + }; + setState(initializeState); + window.history.pushState(initializeState.activePage, initializeState.stateName); + } + + 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/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 diff --git a/phone-book/src/url/url.js b/phone-book/src/url/url.js new file mode 100644 index 0000000..ea5d53a --- /dev/null +++ b/phone-book/src/url/url.js @@ -0,0 +1,37 @@ +class Url{ + constructor(accountName) { + this.url = `https://easycode-js.herokuapp.com/${accountName}/users`; + } + + getUsersFromServer() { + return fetch(this.url) + } + + postUser(user) { + fetch(this.url, { + method: 'POST', + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify(user) + }) + } + + editUser(infoToEdit, id) { + fetch(this.url + '/' + id, { + method: 'PATCH', + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify(infoToEdit) + }) + } + + deleteUserById(id) { + fetch(this.url + '/' + id, { + method: 'DELETE' + }) + } +} + +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..41eea97 --- /dev/null +++ b/phone-book/src/user-page/user-page.js @@ -0,0 +1,102 @@ +import {EditUserPage} from '../edit-user-page/edit-user-page'; +import {Url} from '../url/url'; + +class UserPage{ + constructor(store, accountName) { + 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); + this.url = new Url(accountName); + } + + render(user) { + this.user = user; + + return /*html*/` +
+ +
+
+ User page +
+
+ +
+ +
+ 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'}

+
+ +
+ + +
+ +
+ +
+ `; + } + + applyListenersForUserPage() { + const wraperForButtons = document.getElementById('usp-wraper-for-btns'); + + const handlerForButtons = (e) => { + if(e.target.textContent.trim() === 'Edit') { + 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; + this.editUserPage.applyListenersForEditUserPage() + } + + if(e.target.textContent.trim() === 'Delete') { + const requestForDelete = confirm('Are you sure?'); + if(requestForDelete) { + this.url.deleteUserById(this.user._id || window.user); + + 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 diff --git a/phone-book/style/add-user.css b/phone-book/style/add-user.css new file mode 100644 index 0000000..8bdf126 --- /dev/null +++ b/phone-book/style/add-user.css @@ -0,0 +1,26 @@ +.add-user-header{ + font-size: 26px; + border-bottom: 2px solid black; +} + +.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/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..00eadcb --- /dev/null +++ b/phone-book/style/main.css @@ -0,0 +1,130 @@ +*{ + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + 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; + 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..23a37c9 --- /dev/null +++ b/phone-book/style/user-page.css @@ -0,0 +1,23 @@ +.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; +} + +#usp-wraper-for-btns{ + margin-bottom: 20px; +} \ 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..90bc2f2 --- /dev/null +++ b/phone-book/webpack.config.js @@ -0,0 +1,16 @@ +const path = require('path'); + +module.exports = { + entry: './src/index.js', + output: { + path: path.join(__dirname, 'build'), + filename: 'bundle.js', + publicPath: '/build/' + }, + watch: true, + module: { + rules: [ + { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" } + ] + } +} \ No newline at end of file