└── database-vladilin ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── img │ └── icons │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── android-chrome-maskable-192x192.png │ │ ├── android-chrome-maskable-512x512.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── msapplication-icon-144x144.png │ │ ├── mstile-150x150.png │ │ └── safari-pinned-tab.svg ├── index.html └── robots.txt └── src ├── App.vue ├── assets └── index.css ├── components ├── CategoryCreate.vue ├── CategoryEdit.vue ├── HomeBill.vue ├── HomeCurrency.vue ├── app │ ├── Loader.vue │ ├── Navbar.vue │ └── Sidebar.vue └── historyTable.vue ├── directives └── tooltip.directive.js ├── filters ├── currency.filter.js ├── date.filter.js └── localize.filter.js ├── layouts ├── EmptyLayput.vue └── MainLayout.vue ├── locales ├── en.json └── ru.json ├── main.js ├── mixins └── pagination.mixins.js ├── registerServiceWorker.js ├── router └── index.js ├── store ├── auth.js ├── category.js ├── index.js ├── info.js └── record.js ├── utils ├── message.plugin.js ├── messages.js └── title.plugin.js └── views ├── Categories.vue ├── Detail.vue ├── History.vue ├── Home.vue ├── Login.vue ├── Planning.vue ├── Profile.vue ├── Record.vue └── Register.vue /database-vladilin/README.md: -------------------------------------------------------------------------------- 1 | # database-vladilin 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Customize configuration 19 | See [Configuration Reference](https://cli.vuejs.org/config/). 20 | -------------------------------------------------------------------------------- /database-vladilin/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /database-vladilin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "database-vladilin", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "chart.js": "^2.8.0", 11 | "core-js": "^3.6.5", 12 | "firebase": "^9.5.0", 13 | "materialize-css": "^1.0.0-rc.2", 14 | "register-service-worker": "^1.7.1", 15 | "vue": "^2.6.11", 16 | "vue-chartjs": "^3.5.1", 17 | "vue-meta": "^2.4.0", 18 | "vue-router": "^3.2.0", 19 | "vuejs-paginate": "^2.1.0", 20 | "vuelidate": "^0.7.6", 21 | "vuex": "^3.4.0" 22 | }, 23 | "devDependencies": { 24 | "@vue/cli-plugin-babel": "~4.5.0", 25 | "@vue/cli-plugin-pwa": "~4.5.0", 26 | "@vue/cli-plugin-router": "~4.5.0", 27 | "@vue/cli-plugin-vuex": "~4.5.0", 28 | "@vue/cli-service": "~4.5.0", 29 | "node-sass": "^4.12.0", 30 | "sass-loader": "^8.0.2", 31 | "vue-template-compiler": "^2.6.11" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /database-vladilin/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/favicon.ico -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/android-chrome-maskable-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/android-chrome-maskable-192x192.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/android-chrome-maskable-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/android-chrome-maskable-512x512.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/favicon-16x16.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Doston1002/vuejsProject/efbe498f033f79c5e2d36ac5ddecac0a22087566/database-vladilin/public/img/icons/mstile-150x150.png -------------------------------------------------------------------------------- /database-vladilin/public/img/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /database-vladilin/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= htmlWebpackPlugin.options.title %> 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /database-vladilin/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /database-vladilin/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /database-vladilin/src/assets/index.css: -------------------------------------------------------------------------------- 1 | .empty-layout{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:center;-ms-flex-align:center;align-items:center;padding-top:5rem;height:100vh}.auth-card{width:500px}.auth-submit{width:100%}.helper-text.invalid{color:#f44336}.app-page{padding:2rem}.app-main-layout{position:relative;min-height:100vh}.app-sidenav{padding-top:5px;position:absolute;top:64px;width:250px;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;bottom:0!important;height:auto!important}.app-sidenav.open{-webkit-transform:translateX(0);transform:translateX(0)}.navbar{position:absolute;top:0;left:0;width:100%;height:64px!important;padding:0 2rem;z-index:1000}.nav-wrapper{-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.nav-wrapper,.navbar-left{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.navbar-left>a{margin-right:1rem}.app-content{padding-top:64px;padding-left:250px;transition:padding-left .3s;position:relative}.app-content.full{padding-left:0}.page-title{-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-align-items:center;-ms-flex-align:center;align-items:center;padding-bottom:1rem;border-bottom:solid 1px rgba(51,51,51,.12)}.page-title a{color:#000;opacity:.8}.page-subtitle h4,.page-title h3,.page-title h4{margin:0;font-size:2rem}.page-subtitle h4,.page-title{margin-bottom:2rem}.app-loader,.currency-line,.page-title{display:-webkit-flex;display:-ms-flexbox;display:flex}.app-loader{width:100%;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding-top:2rem}.currency-line{-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:2px solid #fff;padding-bottom:1rem;padding-top:1.5rem}.currency-line span{font-size:1.5rem}.bill-card{height:310px}.pointer{cursor:pointer}.form{max-width:500px}.breadcrumb-wrap,.breadcrumb-wrap a,.breadcrumb-wrap a:before{-webkit-align-items:center;-ms-flex-align:center;align-items:center}.breadcrumb-wrap{position:relative;display:-webkit-flex;display:-ms-flexbox;display:flex}.breadcrumb-wrap a,.breadcrumb-wrap a:before{display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;color:rgba(0,0,0,.7)!important}.history-chart{max-width:600px;margin:0 auto} 2 | -------------------------------------------------------------------------------- /database-vladilin/src/components/CategoryCreate.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 92 | -------------------------------------------------------------------------------- /database-vladilin/src/components/CategoryEdit.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 126 | -------------------------------------------------------------------------------- /database-vladilin/src/components/HomeBill.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 39 | -------------------------------------------------------------------------------- /database-vladilin/src/components/HomeCurrency.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 31 | 39 | -------------------------------------------------------------------------------- /database-vladilin/src/components/app/Loader.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 27 | -------------------------------------------------------------------------------- /database-vladilin/src/components/app/Navbar.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 43 | 77 | -------------------------------------------------------------------------------- /database-vladilin/src/components/app/Sidebar.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /database-vladilin/src/components/historyTable.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 50 | -------------------------------------------------------------------------------- /database-vladilin/src/directives/tooltip.directive.js: -------------------------------------------------------------------------------- 1 | export default { 2 | bind(el, {value}) { 3 | M.Tooltip.init(el, {html: value}) 4 | }, 5 | unbind(el) { 6 | const tooltip = M.Tooltip.getInstance(el) 7 | 8 | if (tooltip && tooltip.destroy) { 9 | tooltip.destroy() 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /database-vladilin/src/filters/currency.filter.js: -------------------------------------------------------------------------------- 1 | export default function currencyFilter(value, currency = 'RUB') { 2 | return new Intl.NumberFormat('ru-RU', { 3 | style: 'currency', 4 | currency 5 | }).format(value) 6 | } 7 | -------------------------------------------------------------------------------- /database-vladilin/src/filters/date.filter.js: -------------------------------------------------------------------------------- 1 | import store from "../store" 2 | 3 | export default function dateFilter(value, format = 'date') { 4 | const options = {} 5 | 6 | if (format.includes('date')){ 7 | options.day = '2-digit' 8 | options.month = 'long' 9 | options.year = 'numeric' 10 | } 11 | if (format.includes('time')){ 12 | options.hour = '2-digit' 13 | options.minute = '2-digit' 14 | options.second = '2-digit' 15 | } 16 | const locale = store.getters.info.locale || 'ru-RU' 17 | return new Intl.DateTimeFormat(locale, options).format(new Date(value)) 18 | } 19 | -------------------------------------------------------------------------------- /database-vladilin/src/filters/localize.filter.js: -------------------------------------------------------------------------------- 1 | import store from '../store' 2 | import ru from '../locales/ru.json' 3 | import en from '../locales/en.json' 4 | 5 | const locales = { 6 | 'ru-RU': ru, 7 | 'en-US': en, 8 | } 9 | 10 | export default function localizeFilter(key){ 11 | const locale = store.getters.info.locale || 'ru-RU' 12 | return locales[locale][key] || `[Localize error] : key ${key} not found` 13 | } 14 | -------------------------------------------------------------------------------- /database-vladilin/src/layouts/EmptyLayput.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | -------------------------------------------------------------------------------- /database-vladilin/src/layouts/MainLayout.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 64 | -------------------------------------------------------------------------------- /database-vladilin/src/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "ProfileTitle": "Profile", 3 | "Message_EnterName": "Enter name", 4 | "Update": "Update", 5 | "Create": "Create", 6 | "Bill": "Bill", 7 | "Name": "Name", 8 | "Exit": "Exit", 9 | "Edit": "Edit", 10 | "Menu_Bill": "Bill", 11 | "Detail_Title": "Detail", 12 | "Menu_History": "History", 13 | "Menu_Planning": "Planning", 14 | "Menu_NewRecord": "New record", 15 | "Menu_Categories": "Categories", 16 | "Title": "Title", 17 | "Limit": "Limit", 18 | "Message_EnterDescription": "Enter description", 19 | "Message_CategoryTitle": "Enter category name", 20 | "Message_MinLength": "Mininum length is", 21 | "Category_HasBeenCreated": "Category has been created", 22 | "Category_HasBeenUpdated": "Category has been updated", 23 | "SelectCategory": "Select category", 24 | "Amount": "Amount", 25 | "Date": "Date", 26 | "Description": "Description", 27 | "Category": "Category", 28 | "Categories": "Categories", 29 | "NoCategories": "No categories", 30 | "Type": "Type", 31 | "Open": "Open", 32 | "OpenRecord": "Open record", 33 | "BillInCurrency": "Bill in currencies", 34 | "Currency": "Currency", 35 | "CurrencyType": "Rate", 36 | "CurrencyAmountTitle": "Currencies rates", 37 | "Income": "Income", 38 | "Outcome": "Outcome", 39 | "Of": "of", 40 | "History_Title": "Records history", 41 | "NoRecords": "No records", 42 | "AddFirst": "Add first", 43 | "Back": "Back", 44 | "Forward": "Forward", 45 | "CostsForCategories": "Categories costs", 46 | "MoreThan": "Excess on", 47 | "Stayed": "Left", 48 | "RecordHasBeenCreated": "Record has been created", 49 | "NotEnoughMoney": "Not enough money", 50 | "CRM_Title": "CRM by Vladilen", 51 | "Message_EmailRequired": "Email field is required", 52 | "Message_EmailValid": "Enter valid email", 53 | "Password": "Password", 54 | "Message_EnterPassword": "Enter password", 55 | "Login": "Login", 56 | "NoAccount": "Has no account?", 57 | "HasAccount": "Has account?", 58 | "Register": "Register", 59 | "AcceptRules": "Agree with rules", 60 | "CreateNewRecord": "Create new record", 61 | "Logout": "You have logged out", 62 | "FirstLogin": "First login", 63 | "NoUserWithEmail": "No user with email", 64 | "WrongPassword": "Invalid password", 65 | "EmailInUse": "Email is already in use", 66 | "Error": "Error" 67 | } 68 | -------------------------------------------------------------------------------- /database-vladilin/src/locales/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "ProfileTitle": "Профиль", 3 | "Message_EnterName": "Введите имя", 4 | "Update": "Обновить", 5 | "Create": "Создать", 6 | "Bill": "Счет", 7 | "Name": "Имя", 8 | "Exit": "Выйти", 9 | "Edit": "Редактировать", 10 | "Menu_Bill": "Счет", 11 | "Detail_Title": "Запись", 12 | "Menu_History": "История", 13 | "Menu_Planning": "Планирование", 14 | "Menu_NewRecord": "Новая запись", 15 | "Menu_Categories": "Категории", 16 | "Выйти": "Выйти", 17 | "Title": "Название", 18 | "Limit": "Лимит", 19 | "Message_EnterDescription": "Введите описание", 20 | "Message_CategoryTitle": "Введите название категории", 21 | "Message_MinLength": "Минимальная значение", 22 | "Category_HasBeenCreated": "Категория была создана", 23 | "Category_HasBeenUpdated": "Категория упешно обновлена", 24 | "SelectCategory": "Выберите категорию", 25 | "Amount": "Сумма", 26 | "Date": "Дата", 27 | "Description": "Описание", 28 | "Category": "Категория", 29 | "Categories": "Категории", 30 | "NoCategories": "Категорий пока нет", 31 | "Type": "Тип", 32 | "Open": "Открыть", 33 | "OpenRecord": "Посмотреть запись", 34 | "BillInCurrency": "Счет в валюте", 35 | "Currency": "Валюта", 36 | "CurrencyType": "Курс", 37 | "CurrencyAmountTitle": "Курс валют", 38 | "Income": "Доход", 39 | "Outcome": "Расход", 40 | "Of": "из", 41 | "History_Title": "История записей", 42 | "NoRecords": "Записей пока нет", 43 | "AddFirst": "Добавьте первую", 44 | "Back": "Назад", 45 | "Forward": "Вперед", 46 | "CostsForCategories": "Расходы по категориям", 47 | "MoreThan": "Превышение на", 48 | "Stayed": "Осталось", 49 | "RecordHasBeenCreated": "Запись успешно создана", 50 | "NotEnoughMoney": "Недостаточно средств на счете", 51 | "CRM_Title": "Домашняя бухгалтерия", 52 | "Message_EmailRequired": "Поле Email не должно быть пустым", 53 | "Message_EmailValid": "Введите корретный Email", 54 | "Password": "Пароль", 55 | "Message_EnterPassword": "Введите пароль", 56 | "Login": "Войти", 57 | "NoAccount": "Нет аккаунта?", 58 | "HasAccount": "Уже есть аккаунт?", 59 | "Register": "Зарегистрироваться", 60 | "AcceptRules": "С правилами согласен", 61 | "CreateNewRecord": "Создать новую запись", 62 | "Logout": "Вы вышли из системы", 63 | "FirstLogin": "Для начала войдите в систему", 64 | "NoUserWithEmail": "Пользователя с таким email не существует", 65 | "WrongPassword": "Неверный пароль", 66 | "EmailInUse": "Email уже занят", 67 | "Error": "Ошибка" 68 | } 69 | -------------------------------------------------------------------------------- /database-vladilin/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuelidate from 'vuelidate' 3 | import Paginate from 'vuejs-paginate' 4 | import VueMeta from 'vue-meta' 5 | import App from './App.vue' 6 | import './registerServiceWorker' 7 | import router from './router' 8 | import dateFilter from '@/filters/date.filter' 9 | import currencyFilter from '@/filters/currency.filter' 10 | import localizeFilter from '@/filters/localize.filter' 11 | import tooltipDirective from './directives/tooltip.directive' 12 | import messagePlugin from '@/utils/message.plugin' 13 | import titlePlugin from '@/utils/title.plugin' 14 | import Loader from '@/components/app/Loader' 15 | import store from './store' 16 | import 'materialize-css/dist/js/materialize.min' 17 | 18 | 19 | import firebase from 'firebase/compat/app' 20 | import 'firebase/compat/auth' 21 | import 'firebase/compat/database' 22 | 23 | Vue.config.productionTip = false 24 | 25 | Vue.use(messagePlugin) 26 | Vue.use(titlePlugin) 27 | Vue.use(Vuelidate) 28 | Vue.use(VueMeta) 29 | Vue.filter('date', dateFilter) 30 | Vue.filter('localize', localizeFilter) 31 | Vue.filter('currency', currencyFilter) 32 | Vue.directive('tooltip', tooltipDirective) 33 | Vue.component('Loader', Loader) 34 | Vue.component('Paginate', Paginate) 35 | 36 | firebase.initializeApp({ 37 | apiKey: "AIzaSyByX1Z5gTrvdmGYG895h1t5tAkK1CAtKXs", 38 | authDomain: "vue-test-68173.firebaseapp.com", 39 | projectId: "vue-test-68173", 40 | storageBucket: "vue-test-68173.appspot.com", 41 | messagingSenderId: "128099926266", 42 | appId: "1:128099926266:web:da9bd54ddbe98de0d5c943", 43 | measurementId: "G-VK3YHYG576" 44 | }) 45 | 46 | let app 47 | 48 | firebase.auth().onAuthStateChanged(() =>{ 49 | if (!app){ 50 | app = new Vue({ 51 | router, 52 | store, 53 | render: h => h(App) 54 | }).$mount('#app') 55 | } 56 | }) 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /database-vladilin/src/mixins/pagination.mixins.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | export default { 4 | data() { 5 | return { 6 | page: +this.$route.query.page || 1, 7 | pageSize: 3, 8 | pageCount: 0, 9 | allItems: [], 10 | items: [] 11 | } 12 | }, 13 | methods: { 14 | pageChangeHandler(page) { 15 | this.$router.push(`${this.$route.path}?page=${page}`) 16 | this.items = this.allItems[page - 1] || this.allItems[0] 17 | }, 18 | 19 | setupPagination(allItems) { 20 | this.allItems = _.chunk(allItems, this.pageSize) 21 | this.pageCount = _.size(this.allItems) 22 | this.items = this.allItems[this.page - 1] || this.allItems[0] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /database-vladilin/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import { register } from 'register-service-worker' 4 | 5 | if (process.env.NODE_ENV === 'production') { 6 | register(`${process.env.BASE_URL}service-worker.js`, { 7 | ready () { 8 | console.log( 9 | 'App is being served from cache by a service worker.\n' + 10 | 'For more details, visit https://goo.gl/AFskqB' 11 | ) 12 | }, 13 | registered () { 14 | console.log('Service worker has been registered.') 15 | }, 16 | cached () { 17 | console.log('Content has been cached for offline use.') 18 | }, 19 | updatefound () { 20 | console.log('New content is downloading.') 21 | }, 22 | updated () { 23 | console.log('New content is available; please refresh.') 24 | }, 25 | offline () { 26 | console.log('No internet connection found. App is running in offline mode.') 27 | }, 28 | error (error) { 29 | console.error('Error during service worker registration:', error) 30 | } 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /database-vladilin/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import firebase from 'firebase/compat/app' 4 | 5 | Vue.use(VueRouter) 6 | 7 | const router = new VueRouter({ 8 | mode: 'history', 9 | base: process.env.BASE_URL, 10 | routes:[ 11 | { 12 | path: '/', 13 | name: 'Home', 14 | meta:{layout:'main', auth: true}, 15 | component: () => import('../views/Home.vue') 16 | }, 17 | { 18 | path: '/login', 19 | name: 'login', 20 | meta:{layout:'empty'}, 21 | component:() => import('../views/Login.vue') 22 | }, 23 | { 24 | path: '/register', 25 | name: 'register', 26 | meta: {layout: 'empty'}, 27 | component: () => import('../views/Register') 28 | }, 29 | { 30 | path: '/categories', 31 | name: 'categories', 32 | meta:{layout:'main', auth: true}, 33 | component:() => import('../views/Categories.vue') 34 | }, 35 | { 36 | path: '/detail/:id', 37 | name: 'detail', 38 | meta: {layout: 'main', auth: true}, 39 | component: () => import('../views/Detail.vue') 40 | }, 41 | { 42 | path: '/history', 43 | name: 'history', 44 | meta: {layout: 'main', auth: true}, 45 | component: () => import('../views/History.vue') 46 | }, 47 | { 48 | path: '/planning', 49 | name: 'planning', 50 | meta: {layout: 'main', auth: true}, 51 | component: () => import('../views/Planning.vue') 52 | }, 53 | { 54 | path: '/profile', 55 | name: 'profile', 56 | meta: {layout: 'main', auth: true}, 57 | component: () => import('../views/Profile.vue') 58 | }, 59 | { 60 | path: '/record', 61 | name: 'record', 62 | meta: {layout: 'main', auth: true}, 63 | component: () => import('../views/Record.vue') 64 | } 65 | ] 66 | }) 67 | 68 | 69 | 70 | 71 | 72 | router.beforeEach((to, from, next) => { 73 | const currentUser = firebase.auth().currentUser 74 | const requireAuth = to.matched.some(record => record.meta.auth) 75 | 76 | if (requireAuth && !currentUser) { 77 | next('/login?message=login') 78 | } else { 79 | next() 80 | } 81 | }) 82 | 83 | export default router 84 | 85 | 86 | -------------------------------------------------------------------------------- /database-vladilin/src/store/auth.js: -------------------------------------------------------------------------------- 1 | import firebase from "@firebase/app-compat" 2 | 3 | export default { 4 | actions: { 5 | async login({dispatch, commit}, {email, password}) { 6 | try { 7 | await firebase.auth().signInWithEmailAndPassword(email, password) 8 | } catch (e) { 9 | commit('setError', e) 10 | throw e 11 | } 12 | }, 13 | async register({dispatch, commit}, {email, password, name}) { 14 | try { 15 | await firebase.auth().createUserWithEmailAndPassword(email, password) 16 | const uid = await dispatch('getUid') 17 | await firebase.database().ref(`/users/${uid}/info`).set({ 18 | bill: 10000, 19 | name 20 | }) 21 | } catch (e) { 22 | console.log('EEE', e) 23 | commit('setError', e) 24 | throw e 25 | } 26 | }, 27 | getUid() { 28 | const user = firebase.auth().currentUser 29 | return user ? user.uid : null 30 | }, 31 | async logout({commit}) { 32 | await firebase.auth().signOut() 33 | commit('clearInfo') 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database-vladilin/src/store/category.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase/compat/app' 2 | 3 | export default { 4 | actions: { 5 | async fetchCategories({commit, dispatch}){ 6 | try { 7 | const uid = await dispatch('getUid') 8 | const categories = (await firebase.database().ref(`/users/${uid}/categories`).once('value')).val() || {} 9 | return Object.keys(categories).map(key =>({...categories[key], id: key})) 10 | } catch (e) { 11 | commit('setError', e) 12 | throw e 13 | } 14 | }, 15 | 16 | async fetchCategoryById({commit, dispatch}, id){ 17 | try { 18 | const uid = await dispatch('getUid') 19 | const category = (await firebase.database().ref(`/users/${uid}/categories`).child(id).once('value')).val() || {} 20 | return {...category, id} 21 | } catch (e) { 22 | commit('setError', e) 23 | throw e 24 | } 25 | }, 26 | 27 | async updateCategory({commit, dispatch}, {title, limit, id}){ 28 | try { 29 | const uid = await dispatch('getUid') 30 | await firebase.database().ref(`/users/${uid}/categories`).child(id).update({title, limit}) 31 | } catch (e) { 32 | commit('setError', e) 33 | throw e 34 | } 35 | }, 36 | async createCategory({commit, dispatch}, {title, limit}) { 37 | try { 38 | const uid = await dispatch('getUid') 39 | const category = await firebase.database().ref(`/users/${uid}/categories`).push({title, limit}) 40 | return {title, limit, id: category.key} 41 | } catch (e) { 42 | commit('setError', e) 43 | throw e 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /database-vladilin/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import auth from './auth' 4 | import info from './info' 5 | import category from './category' 6 | import record from './record' 7 | 8 | Vue.use(Vuex) 9 | 10 | export default new Vuex.Store({ 11 | state: { 12 | error: null 13 | }, 14 | mutations: { 15 | setError(state, error) { 16 | debugger 17 | state.error = error 18 | }, 19 | clearError(state) { 20 | state.error = null 21 | } 22 | }, 23 | 24 | actions: { 25 | async fetchCurrency() { 26 | const key = process.env.VUE_APP_FIXER 27 | const res = await fetch(`http://data.fixer.io/api/latest?access_key=${key}&symbols=USD,EUR,RUB`) 28 | return await res.json() 29 | } 30 | }, 31 | getters: { 32 | error: s => s.error 33 | }, 34 | modules: { 35 | auth, info, category, record 36 | } 37 | }) 38 | -------------------------------------------------------------------------------- /database-vladilin/src/store/info.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase/compat/app' 2 | 3 | export default { 4 | state: { 5 | info: {} 6 | }, 7 | mutations: { 8 | setInfo(state, info) { 9 | state.info = info 10 | }, 11 | clearInfo(state) { 12 | state.info = {} 13 | } 14 | }, 15 | actions: { 16 | async updateInfo({dispatch, commit, getters}, toUpdate){ 17 | try { 18 | const uid = await dispatch('getUid') 19 | const updateData = {...getters.info, ...toUpdate} 20 | await firebase.database().ref(`/users/${uid}/info`).update(updateData) 21 | commit('setInfo', updateData) 22 | } catch (e) { 23 | commit('setError', e) 24 | throw e 25 | } 26 | }, 27 | async fetchInfo({dispatch, commit}) { 28 | try { 29 | const uid = await dispatch('getUid') 30 | const info = (await firebase.database().ref(`/users/${uid}/info`).once('value')).val() 31 | commit('setInfo', info) 32 | } catch (e) { 33 | commit('setError', e) 34 | throw e 35 | } 36 | } 37 | }, 38 | getters: { 39 | info: s => s.info 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /database-vladilin/src/store/record.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase/compat/app' 2 | 3 | export default { 4 | actions: { 5 | async createRecord({dispatch, commit}, record) { 6 | try { 7 | const uid = await dispatch('getUid') 8 | return await firebase.database().ref(`/users/${uid}/records`).push(record) 9 | } catch (e) { 10 | commit('setError', e) 11 | throw e 12 | } 13 | }, 14 | async fetchRecords({dispatch,commit}) { 15 | try{ 16 | const uid = await dispatch('getUid') 17 | const records = (await firebase.database().ref(`/users/${uid}/records`).once('value')).val() || {} 18 | return Object.keys(records).map(key => ({...records[key], id: key})) 19 | } 20 | catch(e) { 21 | commit('setError',e) 22 | throw e 23 | } 24 | }, 25 | async fetchRecordById({dispatch,commit}, id) { 26 | try{ 27 | const uid = await dispatch('getUid') 28 | const record = (await firebase.database().ref(`/users/${uid}/records`).child(id).once('value')).val() || {} 29 | return { 30 | ...record, id 31 | } 32 | } 33 | catch(e) { 34 | commit('setError',e) 35 | throw e 36 | } 37 | }, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /database-vladilin/src/utils/message.plugin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | install(Vue, options) { 3 | Vue.prototype.$message = function(html) { 4 | M.toast({html}) 5 | } 6 | 7 | Vue.prototype.$error = function(html) { 8 | M.toast({html: `[Ошибка]: ${html}`}) 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /database-vladilin/src/utils/messages.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'logout': 'Вы вышли из системы', 3 | 'login': 'Для начала войдите в систему', 4 | 'auth/user-not-found': 'Пользователя с таким Email не существует', 5 | 'auth/wrong-password': 'Неверный пароль', 6 | 'auth/email-already-in-use': 'Email уже занят' 7 | } 8 | -------------------------------------------------------------------------------- /database-vladilin/src/utils/title.plugin.js: -------------------------------------------------------------------------------- 1 | import locaizeFilter from '../filters/localize.filter' 2 | 3 | export default { 4 | install(Vue) { 5 | Vue.prototype.$title = function(titleKey) { 6 | const appName = process.env.VUE_APP-TITLE 7 | 8 | return`${locaizeFilter(titleKey)} | ${appName}` 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /database-vladilin/src/views/Categories.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 62 | -------------------------------------------------------------------------------- /database-vladilin/src/views/Detail.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | 61 | -------------------------------------------------------------------------------- /database-vladilin/src/views/History.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 117 | -------------------------------------------------------------------------------- /database-vladilin/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 29 | 66 | -------------------------------------------------------------------------------- /database-vladilin/src/views/Login.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 108 | -------------------------------------------------------------------------------- /database-vladilin/src/views/Planning.vue: -------------------------------------------------------------------------------- 1 | 28 | 83 | -------------------------------------------------------------------------------- /database-vladilin/src/views/Profile.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 85 | 86 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /database-vladilin/src/views/Record.vue: -------------------------------------------------------------------------------- 1 | 88 | 89 | 178 | -------------------------------------------------------------------------------- /database-vladilin/src/views/Register.vue: -------------------------------------------------------------------------------- 1 | 83 | 84 | 129 | --------------------------------------------------------------------------------