diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 6a247fef..2ab6b918 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -2,7 +2,9 @@ namespace App\Http\Controllers\Auth; +use Validator; use App\Http\Controllers\Controller; +use Illuminate\Http\Request; use Illuminate\Foundation\Auth\SendsPasswordResetEmails; class ForgotPasswordController extends Controller @@ -29,4 +31,28 @@ public function __construct() { $this->middleware('guest'); } + + /** + * Send a reset link to the given user. + * Override native function to validate if email to reset exists + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse + */ + public function sendResetLinkEmail(Request $request) + { + + $this->validate($request, ['email' => 'required|exists:users,email']); + + // We will send the password reset link to this user. Once we have attempted + // to send the link, we will examine the response then see the message we + // need to show to the user. Finally, we'll send out a proper response. + $response = $this->broker()->sendResetLink( + $this->credentials($request) + ); + + return $response == Password::RESET_LINK_SENT + ? $this->sendResetLinkResponse($request, $response) + : $this->sendResetLinkFailedResponse($request, $response); + } } diff --git a/public/js/app.js b/public/js/app.js index 3d3a8782..19080f20 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -10853,6 +10853,13 @@ __webpack_require__.r(__webpack_exports__); // // // +// +// +// +// +// +// +// /* harmony default export */ __webpack_exports__["default"] = ({ data: function data() { return { @@ -11039,6 +11046,78 @@ __webpack_require__.r(__webpack_exports__); /***/ }), +/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/views/auth/password/Request.vue?vue&type=script&lang=js&": +/*!***************************************************************************************************************************************************************************!*\ + !*** ./node_modules/babel-loader/lib??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/views/auth/password/Request.vue?vue&type=script&lang=js& ***! + \***************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +/* harmony default export */ __webpack_exports__["default"] = ({ + data: function data() { + return { + email: '', + validationErrors: {} + }; + }, + methods: { + handleSubmit: function handleSubmit(e) { + var _this = this; + + e.preventDefault(); + axios.post('/api/password/email', { + email: this.email + }).then(function (response) { + alert('email sent'); + })["catch"](function (error) { + console.log(error.response); + + if (error.response.data.errors) { + _this.validationErrors = error.response.data.errors; + } else { + _this.$router.push({ + name: 'genericError', + params: { + err: error.response.data.message + } + }); + } + }); + } + } +}); + +/***/ }), + /***/ "./node_modules/process/browser.js": /*!*****************************************!*\ !*** ./node_modules/process/browser.js ***! @@ -14967,6 +15046,38 @@ var render = function() { ], 1 ) + ]), + _vm._v(" "), + _c("div", { staticClass: "columns is-mobile is-centered" }, [ + _c( + "div", + { + staticClass: + "column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd" + }, + [ + _vm._v( + "\n " + + _vm._s(_vm.$t("auth.forms.forgot_your_password")) + + " " + ), + _c( + "router-link", + { + staticClass: "is-link", + attrs: { to: { name: "password.request" } } + }, + [ + _vm._v( + "\n " + + _vm._s(_vm.$t("auth.forms.request_password_reset")) + + "\n " + ) + ] + ) + ], + 1 + ) ]) ]) } @@ -15228,6 +15339,118 @@ render._withStripped = true +/***/ }), + +/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/views/auth/password/Request.vue?vue&type=template&id=127cf7da&": +/*!*******************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/views/auth/password/Request.vue?vue&type=template&id=127cf7da& ***! + \*******************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "render", function() { return render; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return staticRenderFns; }); +var render = function() { + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c("div", { staticClass: "section" }, [ + _c("div", { staticClass: "columns is-mobile is-centered" }, [ + _c( + "div", + { + staticClass: + "column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd" + }, + [ + _c("h1", { staticClass: "title" }, [ + _vm._v(_vm._s(_vm.$t("passwords.reset_password"))) + ]), + _vm._v(" "), + _c("form", { attrs: { method: "POST", action: "/login" } }, [ + _c("div", { staticClass: "field" }, [ + _c("label", { staticClass: "label" }, [ + _vm._v(_vm._s(_vm.$t("auth.forms.email"))) + ]), + _vm._v(" "), + _c("div", { staticClass: "control" }, [ + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.email, + expression: "email" + } + ], + staticClass: "input", + attrs: { + id: "email", + type: "email", + required: "", + autofocus: "" + }, + domProps: { value: _vm.email }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.email = $event.target.value + } + } + }) + ]), + _vm._v(" "), + _vm.validationErrors.email + ? _c("p", { staticClass: "help is-danger" }, [ + _vm._v(_vm._s(_vm.validationErrors.email.toString())) + ]) + : _vm._e() + ]), + _vm._v(" "), + _c("div", { staticClass: "field is-grouped" }, [ + _c("div", { staticClass: "control" }, [ + _c( + "button", + { + staticClass: "button is-link", + attrs: { type: "submit" }, + on: { click: _vm.handleSubmit } + }, + [_vm._v(_vm._s(_vm.$t("passwords.send_password_reset_link")))] + ) + ]), + _vm._v(" "), + _c( + "div", + { staticClass: "control" }, + [ + _c( + "router-link", + { + staticClass: "button is-text", + attrs: { to: { name: "login" } } + }, + [_vm._v(_vm._s(_vm.$t("commons.cancel")))] + ) + ], + 1 + ) + ]) + ]) + ] + ) + ]) + ]) +} +var staticRenderFns = [] +render._withStripped = true + + + /***/ }), /***/ "./node_modules/vue-loader/lib/runtime/componentNormalizer.js": @@ -30269,10 +30492,11 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _views_Accounts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./views/Accounts */ "./resources/js/views/Accounts.vue"); /* harmony import */ var _views_Create__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./views/Create */ "./resources/js/views/Create.vue"); /* harmony import */ var _views_Edit__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./views/Edit */ "./resources/js/views/Edit.vue"); -/* harmony import */ var _views_Error__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./views/Error */ "./resources/js/views/Error.vue"); -/* harmony import */ var _fortawesome_fontawesome_svg_core__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @fortawesome/fontawesome-svg-core */ "./node_modules/@fortawesome/fontawesome-svg-core/index.es.js"); -/* harmony import */ var _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @fortawesome/free-solid-svg-icons */ "./node_modules/@fortawesome/free-solid-svg-icons/index.es.js"); -/* harmony import */ var _fortawesome_vue_fontawesome__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @fortawesome/vue-fontawesome */ "./node_modules/@fortawesome/vue-fontawesome/index.es.js"); +/* harmony import */ var _views_auth_password_Request__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./views/auth/password/Request */ "./resources/js/views/auth/password/Request.vue"); +/* harmony import */ var _views_Error__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./views/Error */ "./resources/js/views/Error.vue"); +/* harmony import */ var _fortawesome_fontawesome_svg_core__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @fortawesome/fontawesome-svg-core */ "./node_modules/@fortawesome/fontawesome-svg-core/index.es.js"); +/* harmony import */ var _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @fortawesome/free-solid-svg-icons */ "./node_modules/@fortawesome/free-solid-svg-icons/index.es.js"); +/* harmony import */ var _fortawesome_vue_fontawesome__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @fortawesome/vue-fontawesome */ "./node_modules/@fortawesome/vue-fontawesome/index.es.js"); @@ -30289,8 +30513,9 @@ vue__WEBPACK_IMPORTED_MODULE_0___default.a.use(vue_i18n__WEBPACK_IMPORTED_MODULE -_fortawesome_fontawesome_svg_core__WEBPACK_IMPORTED_MODULE_11__["library"].add(_fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__["faPlus"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__["faQrcode"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__["faImage"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__["faTrash"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__["faEdit"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__["faCheck"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__["faLock"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__["faLockOpen"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_12__["faSearch"]); -vue__WEBPACK_IMPORTED_MODULE_0___default.a.component('font-awesome-icon', _fortawesome_vue_fontawesome__WEBPACK_IMPORTED_MODULE_13__["FontAwesomeIcon"]); // const lang = document.documentElement.lang.substr(0, 2); + +_fortawesome_fontawesome_svg_core__WEBPACK_IMPORTED_MODULE_12__["library"].add(_fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__["faPlus"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__["faQrcode"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__["faImage"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__["faTrash"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__["faEdit"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__["faCheck"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__["faLock"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__["faLockOpen"], _fortawesome_free_solid_svg_icons__WEBPACK_IMPORTED_MODULE_13__["faSearch"]); +vue__WEBPACK_IMPORTED_MODULE_0___default.a.component('font-awesome-icon', _fortawesome_vue_fontawesome__WEBPACK_IMPORTED_MODULE_14__["FontAwesomeIcon"]); // const lang = document.documentElement.lang.substr(0, 2); var lang = 'en'; var i18n = new vue_i18n__WEBPACK_IMPORTED_MODULE_2__["default"]({ @@ -30321,19 +30546,24 @@ var router = new vue_router__WEBPACK_IMPORTED_MODULE_1__["default"]({ name: 'edit', component: _views_Edit__WEBPACK_IMPORTED_MODULE_9__["default"] }, { + path: '/password/request', + name: 'password.request', + component: _views_auth_password_Request__WEBPACK_IMPORTED_MODULE_10__["default"] + }, //{ path: '/password/reset/:token', name: 'password.reset', component: page('auth/password/reset.vue') }, + { path: '/flooded', name: 'flooded', - component: _views_Error__WEBPACK_IMPORTED_MODULE_10__["default"], + component: _views_Error__WEBPACK_IMPORTED_MODULE_11__["default"], props: true }, { path: '/error', name: 'genericError', - component: _views_Error__WEBPACK_IMPORTED_MODULE_10__["default"], + component: _views_Error__WEBPACK_IMPORTED_MODULE_11__["default"], props: true }, { path: '/404', name: '404', - component: _views_Error__WEBPACK_IMPORTED_MODULE_10__["default"], + component: _views_Error__WEBPACK_IMPORTED_MODULE_11__["default"], props: true }, { path: '*', @@ -31041,6 +31271,75 @@ __webpack_require__.r(__webpack_exports__); +/***/ }), + +/***/ "./resources/js/views/auth/password/Request.vue": +/*!******************************************************!*\ + !*** ./resources/js/views/auth/password/Request.vue ***! + \******************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _Request_vue_vue_type_template_id_127cf7da___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Request.vue?vue&type=template&id=127cf7da& */ "./resources/js/views/auth/password/Request.vue?vue&type=template&id=127cf7da&"); +/* harmony import */ var _Request_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Request.vue?vue&type=script&lang=js& */ "./resources/js/views/auth/password/Request.vue?vue&type=script&lang=js&"); +/* empty/unused harmony star reexport *//* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ "./node_modules/vue-loader/lib/runtime/componentNormalizer.js"); + + + + + +/* normalize component */ + +var component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__["default"])( + _Request_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__["default"], + _Request_vue_vue_type_template_id_127cf7da___WEBPACK_IMPORTED_MODULE_0__["render"], + _Request_vue_vue_type_template_id_127cf7da___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"], + false, + null, + null, + null + +) + +/* hot reload */ +if (false) { var api; } +component.options.__file = "resources/js/views/auth/password/Request.vue" +/* harmony default export */ __webpack_exports__["default"] = (component.exports); + +/***/ }), + +/***/ "./resources/js/views/auth/password/Request.vue?vue&type=script&lang=js&": +/*!*******************************************************************************!*\ + !*** ./resources/js/views/auth/password/Request.vue?vue&type=script&lang=js& ***! + \*******************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_Request_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../../../node_modules/babel-loader/lib??ref--4-0!../../../../../node_modules/vue-loader/lib??vue-loader-options!./Request.vue?vue&type=script&lang=js& */ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/views/auth/password/Request.vue?vue&type=script&lang=js&"); +/* empty/unused harmony star reexport */ /* harmony default export */ __webpack_exports__["default"] = (_node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_Request_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__["default"]); + +/***/ }), + +/***/ "./resources/js/views/auth/password/Request.vue?vue&type=template&id=127cf7da&": +/*!*************************************************************************************!*\ + !*** ./resources/js/views/auth/password/Request.vue?vue&type=template&id=127cf7da& ***! + \*************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_Request_vue_vue_type_template_id_127cf7da___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../../../../node_modules/vue-loader/lib??vue-loader-options!./Request.vue?vue&type=template&id=127cf7da& */ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/views/auth/password/Request.vue?vue&type=template&id=127cf7da&"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "render", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_Request_vue_vue_type_template_id_127cf7da___WEBPACK_IMPORTED_MODULE_0__["render"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_Request_vue_vue_type_template_id_127cf7da___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"]; }); + + + /***/ }), /***/ "./resources/js/vue-i18n-locales.generated.js": @@ -31070,7 +31369,9 @@ __webpack_require__.r(__webpack_exports__); "confirm_password": "Confirm password", "dont_have_account_yet": "Don't have your account yet?", "already_register": "Already registered?", - "password_do_not_match": "Password do not match" + "password_do_not_match": "Password do not match", + "forgot_your_password": "Forgot your password?", + "request_password_reset": "Request a password reset" } }, "commons": { @@ -31096,7 +31397,9 @@ __webpack_require__.r(__webpack_exports__); "reset": "Your password has been reset!", "sent": "We have e-mailed your password reset link!", "token": "This password reset token is invalid.", - "user": "We can't find a user with that e-mail address." + "user": "We can't find a user with that e-mail address.", + "send_password_reset_link": "Send password reset link", + "reset_password": "Reset your password" }, "twofaccounts": { "service": "Service", diff --git a/public/js/vue-i18n-locales.generated.js b/public/js/vue-i18n-locales.generated.js index 0912b858..bbbc7fd9 100644 --- a/public/js/vue-i18n-locales.generated.js +++ b/public/js/vue-i18n-locales.generated.js @@ -113,7 +113,9 @@ __webpack_require__.r(__webpack_exports__); "confirm_password": "Confirm password", "dont_have_account_yet": "Don't have your account yet?", "already_register": "Already registered?", - "password_do_not_match": "Password do not match" + "password_do_not_match": "Password do not match", + "forgot_your_password": "Forgot your password?", + "request_password_reset": "Request a password reset" } }, "commons": { @@ -139,7 +141,9 @@ __webpack_require__.r(__webpack_exports__); "reset": "Your password has been reset!", "sent": "We have e-mailed your password reset link!", "token": "This password reset token is invalid.", - "user": "We can't find a user with that e-mail address." + "user": "We can't find a user with that e-mail address.", + "send_password_reset_link": "Send password reset link", + "reset_password": "Reset your password" }, "twofaccounts": { "service": "Service", diff --git a/resources/js/app.js b/resources/js/app.js index bd7776df..504ecbe0 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -6,13 +6,15 @@ import Locale from './vue-i18n-locales.generated'; Vue.use(VueRouter) Vue.use(VueInternationalization); -import App from './views/App' -import Login from './views/Login' -import Register from './views/Register' -import Accounts from './views/Accounts' -import Create from './views/Create' -import Edit from './views/Edit' -import NotFound from './views/Error' +import App from './views/App' +import Login from './views/Login' +import Register from './views/Register' +import Accounts from './views/Accounts' +import Create from './views/Create' +import Edit from './views/Edit' +import PasswordRequest from './views/auth/password/Request' +import NotFound from './views/Error' + import { library } from '@fortawesome/fontawesome-svg-core' import { faPlus, faQrcode, faImage, faTrash, faEdit, faCheck, faLock, faLockOpen, faSearch } from '@fortawesome/free-solid-svg-icons' @@ -33,54 +35,19 @@ const i18n = new VueInternationalization({ const router = new VueRouter({ mode: 'history', routes: [ - { - path: '/', - name: 'accounts', - component: Accounts, - props: true - }, - { - path: '/login', - name: 'login', - component: Login, - }, - { - path: '/register', - name: 'register', - component: Register, - }, - { - path: '/create', - name: 'create', - component: Create, - }, - { - path: '/edit/:twofaccountId', - name: 'edit', - component: Edit, - }, - { - path: '/flooded', - name: 'flooded', - component: NotFound, - props: true - }, - { - path: '/error', - name: 'genericError', - component: NotFound, - props: true - }, - { - path: '/404', - name: '404', - component: NotFound, - props: true - }, - { - path: '*', - redirect: { name: '404' } - } + { path: '/', name: 'accounts', component: Accounts, props: true }, + { path: '/login', name: 'login',component: Login }, + { path: '/register', name: 'register',component: Register }, + { path: '/create', name: 'create',component: Create }, + { path: '/edit/:twofaccountId', name: 'edit',component: Edit }, + + { path: '/password/request', name: 'password.request', component: PasswordRequest }, + //{ path: '/password/reset/:token', name: 'password.reset', component: page('auth/password/reset.vue') }, + + { path: '/flooded', name: 'flooded',component: NotFound,props: true }, + { path: '/error', name: 'genericError',component: NotFound,props: true }, + { path: '/404', name: '404',component: NotFound,props: true }, + { path: '*', redirect: { name: '404' } } ], }); diff --git a/resources/js/views/Login.vue b/resources/js/views/Login.vue index 3cf991ed..5c2343bb 100644 --- a/resources/js/views/Login.vue +++ b/resources/js/views/Login.vue @@ -33,6 +33,13 @@ +