App.vue
and replace the image that was before. In addition, edit the styles: <style lang="scss"> @import "./assets/styles"; body { background: url('./assets/images/background.jpg') no-repeat center center fixed; background-size: cover; &:after { content: ''; position: fixed; width: 100%; height: 100%; top: 0; left: 0; background-color: $background-tint; opacity: .3; z-index: -1; } .application { background: none; } } </style>
background-size: cover
property and the following construction: .application { background: none; }
App.vue
file, App.vue
's make some changes to the template: <template> <v-app> <v-container> <router-view/> </v-container> </v-app> </template>
div id="app"
to a v-app
, this is the main component from Vuetify.Authentication.vue
component file and make some changes to the styles: <style lang="scss"> @import "./../../../assets/styles"; .l-auth { background-color: $background-color; padding: 15px; margin: 45px auto; min-width: 272px; max-width: 320px; animation: bounceIn 1s forwards ease; label, input, .icon { color: #29b6f6!important; } .input-group__details { &:before { background-color: $border-color-input !important; } } } .l-signup { @extend .l-auth; animation: slideInFromLeft 1s forwards ease; } </style>
v-app
. In addition, we expanded the l-auth
class, since our l-signup
class is exactly the same, the differences are only in the animation. As a result, the application will look like this:index.js
, which is located in the Authentication
folder. First, we will make changes to the authenticate
method: authenticate (context, credentials, redirect) { Axios.post(`${BudgetManagerAPI}/api/v1/auth`, credentials) .then(({data}) => { context.$cookie.set('token', data.token, '1D') context.$cookie.set('user_id', data.user._id, '1D') context.validLogin = true this.user.authenticated = true if (redirect) router.push(redirect) }).catch(({response: {data}}) => { context.snackbar = true context.message = data.message }) },
data
object, we extract the user ID from it, since we intend to store this id
.signup
method: signup (context, credentials, redirect) { Axios.post(`${BudgetManagerAPI}/api/v1/signup`, credentials) .then(() => { context.validSignUp = true this.authenticate(context, credentials, redirect) }).catch(({response: {data}}) => { context.snackbar = true context.message = data.message }) },
authenticate
method.signup
method, add the signout
method: signout (context, redirect) { context.$cookie.delete('token') context.$cookie.delete('user_id') this.user.authenticated = false if (redirect) router.push(redirect) },
signout
method, signout
make small changes to the checkAuthentication
method: checkAuthentication () { const token = document.cookie this.user.authenticated = !!token },
token
constant to a boolean value, use the ternary comparison operator. this.user.authenticated = token ? true : false
components
folder and create a file Header.vue
: <template> <header class="l-header-container"> <v-layout row wrap> <v-flex xs12 md5> <v-text-field v-model="search" label="Search" append-icon="search" color="light-blue lighten-1"> </v-text-field> </v-flex> <v-flex xs12 offset-md1 md1> <v-btn block color="light-blue lighten-1">Clients</v-btn> </v-flex> <v-flex xs12 offset-md1 md2> <v-select label="Status" color="light-blue lighten-1" v-model="status" :items="statusItems" single-line> </v-select> </v-flex> <v-flex xs12 offset-md1 md1> <v-btn block color="red lighten-1 white--text" @click.native="submitSignout()">Sign out</v-btn> </v-flex> </v-layout> </header> </template> <script> import Authentication from '@/components/pages/Authentication' export default { data () { return { search: '', status: '', statusItems: [ 'All', 'Approved', 'Denied', 'Waiting', 'Writing', 'Editing' ] } }, methods: { submitSignout () { Authentication.signout(this, '/login') } } } </script> <style lang="scss"> @import "./../assets/styles"; .l-header-container { background-color: $background-color; margin: 0 auto; padding: 0 15px; min-width: 272px; label, input, .icon, .input-group__selections__comma { color: #29b6f6!important; } .input-group__details { &:before { background-color: $border-color-input !important; } } .btn { margin-top: 15px; } } </style>
search
, a button to go to the clients page, which we will deal with later, a switch to filter documents and a button to exit the system._variables
template, add color information there, and set the background-color
transparency to 0.7
: // Colors $background-tint: #1734C1; $background-color: rgba(0, 0, 0, .7); $border-color-input: rgba(255, 255, 255, 0.42);
index.js
file in the router
folder and bring it to this form: // Pages import Home from '@/components/pages/Home' import Authentication from '@/components/pages/Authentication/Authentication' // Global components import Header from '@/components/Header' // Register components Vue.component('app-header', Header) Vue.use(Router)
Home
component, then the Header
component, and then register it, keeping in mind that the @
sign when using the webpack
is a pseudonym for the src
folder. App-header
is the tag name that we will use to output the Header
component. const router = new Router({ routes: [ { path: '/', name: 'Home', components: { default: Home, header: Header }, meta: { requiredAuth: true } }, { path: '/login', name: 'Authentication', component: Authentication } ] })
Home
, and also include the Header
component on this page. Please note that here we do not make any changes to the route to enter the system. The Header
component representing the page Header
is not needed there.Header
component later, but at this stage of work we are satisfied with its current state.pages
folder and open the Home.vue
file: <template> <main class="l-home-page"> <app-header></app-header> <div class="l-home"> <h4 class="white--text text-xs-center my-0"> Focus Budget Manager </h4> <budget-list> <budget-list-header slot="budget-list-header"></budget-list-header> <budget-list-body slot="budget-list-body" :budgets="budgets"></budget-list-body> </budget-list> </div> </main> </template> <script> import Axios from 'axios' import Authentication from '@/components/pages/Authentication' import BudgetListHeader from './../Budget/BudgetListHeader' import BudgetListBody from './../Budget/BudgetListBody' const BudgetManagerAPI = `http://${window.location.hostname}:3001` export default { components: { 'budget-list-header': BudgetListHeader, 'budget-list-body': BudgetListBody }, data () { return { budgets: [] } }, mounted () { this.getAllBudgets() }, methods: { getAllBudgets () { Axios.get(`${BudgetManagerAPI}/api/v1/budget`, { headers: { 'Authorization': Authentication.getAuthenticationHeader(this) }, params: { user_id: this.$cookie.get('user_id') } }).then(({data}) => (this.budgets = data)) } } } </script> <style lang="scss" scoped> @import "./../../assets/styles"; .l-home { background-color: $background-color; margin: 25px auto; padding: 15px; min-width: 272px; } </style>
h4
tag, containing the name of the application. The following classes are assigned to it:white--text
: used to color the text in white.text-xs-center
: used to center the text along the x
axis.my-0
: used to set the y
axis fields to 0
.budget-list
component, which we will create below. It includes the budget-list-header
and budget-list-body
components, which play the role of data slots.budget-list-body
array of financial budgets
documents, the data from which are extracted when the component is mounted. We pass the Authorization
header, which gives us the opportunity to work with the API. It is also transmitted here as a parameter, user_id
, which makes it possible to indicate which user is requesting data.components
folder and create a new folder called Budget
in it. Inside this folder, create a component file BudgetListHeader.vue
: <template> <header class="l-budget-header"> <div class="md-budget-header white--text">Client</div> <div class="md-budget-header white--text">Title</div> <div class="md-budget-header white--text">Status</div> <div class="md-budget-header white--text">Actions</div> </header> </template> <script> export default {} </script> <style lang="scss"> @import "./../../assets/styles"; .l-budget-header { display: none; width: 100%; @media (min-width: 601px) { margin: 25px 0 0; display: flex; } .md-budget-header { width: 100%; background-color: $background-color; border: 1px solid $border-color-input; padding: 0 15px; display: flex; height: 45px; align-items: center; justify-content: center; font-size: 22px; @media (min-width: 601px) { justify-content: flex-start; } } } </style>
BudgetListBody.vue
: <template> <section class="l-budget-body"> <div class="md-budget" v-if="budgets != null" v-for="budget in budgets"> <div class="md-budget-info white--text">{{ budget.client }}</div> <div class="md-budget-info white--text">{{ budget.title }}</div> <div class="md-budget-info white--text">{{ budget.state }}</div> <div class="l-budget-actions"> <v-btn small flat color="light-blue lighten-1"> <v-icon small>visibility</v-icon> </v-btn> <v-btn small flat color="yellow accent-1"> <v-icon>mode_edit</v-icon> </v-btn> <v-btn small flat color="red lighten-1"> <v-icon>delete_forever</v-icon> </v-btn> </div> </div> </section> </template> <script> export default { props: ['budgets'] } </script> <style lang="scss"> @import "./../../assets/styles"; .l-budget-body { display: flex; flex-direction: column; .md-budget { width: 100%; display: flex; flex-direction: column; margin: 15px 0; @media (min-width: 960px) { flex-direction: row; margin: 0; } .md-budget-info { flex-basis: 25%; width: 100%; background-color: rgba(0, 175, 255, 0.45); border: 1px solid $border-color-input; padding: 0 15px; display: flex; height: 35px; align-items: center; justify-content: center; &:first-of-type, &:nth-of-type(2) { text-transform: capitalize; } &:nth-of-type(3) { text-transform: uppercase; } @media (min-width: 601px) { justify-content: flex-start; } } .l-budget-actions { flex-basis: 25%; display: flex; background-color: rgba(0, 175, 255, 0.45); border: 1px solid $border-color-input; align-items: center; justify-content: center; .btn { min-width: 45px !important; margin: 0 5px !important; } } } } </style>
BudgetList.vue
file in the same folder and add the code of the corresponding component to it: <template> <section class="l-budget-list-container"> <slot name="budget-list-header"></slot> <slot name="budget-list-body"></slot> </section> </template> <script> export default {} </script>
slot
tags. In them we deduce components. These tags are called named slots.BudgetList
component to the router: // ... // Global components import Header from '@/components/Header' import BudgetList from '@/components/Budget/BudgetList' // Register components Vue.component('app-header', Header) Vue.component('budget-list', BudgetList) // ... const router = new Router({ routes: [ { path: '/', name: 'Home', components: { default: Home, header: Header, budgetList: BudgetList }, meta: { requiredAuth: true } }, { path: '/login', name: 'Authentication', component: Authentication } ] }) // ... export default router
Home
component to use them.user.js
from the services/BudgetManagerAPI/app/api
folder and bring it to this form: const mongoose = require('mongoose'); const api = {}; api.signup = (User) => (req, res) => { if (!req.body.username || !req.body.password) res.json({ success: false, message: 'Please, pass an username and password.' }); else { const user = new User({ username: req.body.username, password: req.body.password }); user.save(error => { if (error) return res.status(400).json({ success: false, message: 'Username already exists.' }); res.json({ success: true, message: 'Account created successfully' }); }); } } module.exports = api;
setup
and index
methods. The setup
method is no longer needed, since we already have the means to create accounts. The index
method is not required due to the fact that we are not going to display a list of all registered users. In addition, we got rid of console.log
in the signup
method, and from the empty array of clients in the method of creating a new user.user.js
file, which is stored in the services/BudgetManagerAPI/app/routes
folder: const models = require('@BudgetManager/app/setup'); module.exports = (app) => { const api = app.BudgetManagerAPI.app.api.user; app.route('/api/v1/signup') .post(api.signup(models.User)); }
models
folder, which is located at BudgetManagerAPI/app/
and make some improvements in the model. Open the file user.js
Here we are going to modify the user data scheme: const Schema = mongoose.Schema({ username: { type: String, unique: true, required: true }, password: { type: String, required: true } });
client.js
file: const mongoose = require('mongoose'); const Schema = mongoose.Schema({ name: { type: String, required: true }, email: { type: String, required: true }, phone: { type: String, required: true }, user_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } }); mongoose.model('Client', Schema);
budget.js
file: const mongoose = require('mongoose'); const Schema = mongoose.Schema({ client: { type: String, required: true }, state: { type: String, required: true }, title: { type: String, required: true }, total_price: { type: Number, required: true }, client_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Client' }, items: [{}] }); mongoose.model('Budget', Schema);
ref
and ObjectID
.index.js
file from the setup
folder and bring it to this form: const mongoose = require('mongoose'), UserModel = require('@BudgetManagerModels/user'), BudgetModel = require('@BudgetManagerModels/budget'), ClientModel = require('@BudgetManagerModels/client'); const models = { User: mongoose.model('User'), Budget: mongoose.model('Budget'), Client: mongoose.model('Client') } module.exports = models;
api
folder and create a new client.js
file client.js
: const mongoose = require('mongoose'); const api = {}; api.store = (User, Client, Token) => (req, res) => { if (Token) { const client = new Client({ user_id: req.body.user_id, name: req.body.name, email: req.body.email, phone: req.body.phone, }); client.save(error => { if (error) return res.status(400).json(error); res.status(200).json({ success: true, message: "Client registration successfull" }); }) } else return res.status(403).send({ success: false, message: 'Unauthorized' }); } api.getAll = (User, Client, Token) => (req, res) => { if (Token) { Client.find({ user_id: req.query.user_id }, (error, client) => { if (error) return res.status(400).json(error); res.status(200).json(client); return true; }) } else return res.status(403).send({ success: false, message: 'Unauthorized' }); } module.exports = api;
budget.js
: const mongoose = require('mongoose'); const api = {}; api.store = (User, Budget, Client, Token) => (req, res) => { if (Token) { Client.findOne({ _id: req.body.client_id }, (error, client) => { if (error) res.status(400).json(error); if (client) { const budget = new Budget({ client_id: req.body.client_id, user_id: req.body.user_id, client: client.name, state: req.body.state, title: req.body.title, total_price: req.body.total_price, items: req.body.items }); budget.save(error => { if (error) res.status(400).json(error) res.status(200).json({ success: true, message: "Budget registered successfully" }) }) } else { res.status(400).json({ success: false, message: "Invalid client" }) } }) } else return res.status(403).send({ success: false, message: 'Unauthorized' }); } api.getAll = (User, Budget, Token) => (req, res) => { if (Token) { Budget.find({ user_id: req.query.user_id }, (error, budget) => { if (error) return res.status(400).json(error); res.status(200).json(budget); return true; }) } else return res.status(403).send({ success: false, message: 'Unauthorized' }); } api.getAllFromClient = (User, Budget, Token) => (req, res) => { if (Token) { Budget.find({ client_id: req.query.client_id }, (error, budget) => { if (error) return res.status(400).json(error); res.status(200).json(budget); return true; }) } else return res.status(403).send({ success: false, message: 'Unauthorized' }); } module.exports = api;
routes
folder and create a budget.js
file budget.js
: module.exports = (app) => { const api = app.BudgetManagerAPI.app.api.budget; app.route('/api/v1/budget') .post(passport.authenticate('jwt', config.session), api.store(models.User, models.Budget, models.Client, app.get('budgetsecret'))) .get(passport.authenticate('jwt', config.session), api.getAll(models.User, models.Budget, app.get('budgetsecret'))) .get(passport.authenticate('jwt', config.session), api.getAllFromClient(models.User, models.Budget, app.get('budgetsecret'))) }
client.js
file: const passport = require('passport'), config = require('@config'), models = require('@BudgetManager/app/setup'); module.exports = (app) => { const api = app.BudgetManagerAPI.app.api.client; app.route('/api/v1/client') .post(passport.authenticate('jwt', config.session), api.store(models.User, models.Client, app.get('budgetsecret'))) .get(passport.authenticate('jwt', config.session), api.getAll(models.User, models.Client, app.get('budgetsecret'))); }
passport.authenticate
method, and then the API methods with passing the models and the secret key to them.Source: https://habr.com/ru/post/341874/
All Articles